blob: 549c7feba3cf733112ce408b7d353017f4f2c7f1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.felix.http.jetty.internal;
import java.io.IOException;
import java.net.ServerSocket;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.zip.Deflater;
import org.apache.felix.http.base.internal.HttpConfig;
import org.apache.felix.http.base.internal.logger.SystemLogger;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.osgi.framework.BundleContext;
public final class JettyConfig
{
/** Felix specific property to set the interface to listen on. Applies to both HTTP and HTTP */
public static final String FELIX_HOST = "org.apache.felix.http.host";
/** Standard OSGi port property for HTTP service */
public static final String HTTP_PORT = "org.osgi.service.http.port";
/** Standard OSGi port property for HTTPS service */
public static final String HTTPS_PORT = "org.osgi.service.http.port.secure";
/** Felix specific property to set http reaching timeout limit */
public static final String HTTP_TIMEOUT = "org.apache.felix.http.timeout";
/** Felix specific property to override the keystore file location. */
public static final String FELIX_KEYSTORE = "org.apache.felix.https.keystore";
private static final String OSCAR_KEYSTORE = "org.ungoverned.osgi.bundle.https.keystore";
/** Felix specific property to override the keystore password. */
public static final String FELIX_KEYSTORE_PASSWORD = "org.apache.felix.https.keystore.password";
private static final String OSCAR_KEYSTORE_PASSWORD = "org.ungoverned.osgi.bundle.https.password";
/** Felix specific property to override the keystore key password. */
public static final String FELIX_KEYSTORE_KEY_PASSWORD = "org.apache.felix.https.keystore.key.password";
private static final String OSCAR_KEYSTORE_KEY_PASSWORD = "org.ungoverned.osgi.bundle.https.key.password";
/** Felix specific property to override the type of keystore (JKS). */
public static final String FELIX_KEYSTORE_TYPE = "org.apache.felix.https.keystore.type";
/** Felix specific property to control whether to enable HTTPS. */
public static final String FELIX_HTTPS_ENABLE = "org.apache.felix.https.enable";
private static final String OSCAR_HTTPS_ENABLE = "org.ungoverned.osgi.bundle.https.enable";
/** Felix specific property to control whether to enable HTTP. */
public static final String FELIX_HTTP_ENABLE = "org.apache.felix.http.enable";
/** Felix specific property to override the truststore file location. */
public static final String FELIX_TRUSTSTORE = "org.apache.felix.https.truststore";
/** Felix specific property to override the truststore password. */
public static final String FELIX_TRUSTSTORE_PASSWORD = "org.apache.felix.https.truststore.password";
/** Felix specific property to override the type of truststore (JKS). */
public static final String FELIX_TRUSTSTORE_TYPE = "org.apache.felix.https.truststore.type";
/** Felix specific property to control whether to want or require HTTPS client certificates. Valid values are "none", "wants", "needs". Default is "none". */
public static final String FELIX_HTTPS_CLIENT_CERT = "org.apache.felix.https.clientcertificate";
/** Felix specific property to configure the session timeout in minutes (same session-timout in web.xml). Default is servlet container specific */
public static final String FELIX_SESSION_TIMEOUT = "org.apache.felix.http.session.timeout";
/** Felix specific property to control the maximum size of the jetty thread pool */
public static final String FELIX_JETTY_THREADPOOL_MAX = "org.apache.felix.http.jetty.threadpool.max";
/** Felix specific property to control the number of jetty acceptor threads */
public static final String FELIX_JETTY_ACCEPTORS = "org.apache.felix.http.jetty.acceptors";
/** Felix specific property to control the number of jetty selector threads */
public static final String FELIX_JETTY_SELECTORS = "org.apache.felix.http.jetty.selectors";
/** Felix specific property to configure the request buffer size. Default is 16KB (instead of Jetty's default of 4KB) */
public static final String FELIX_JETTY_HEADER_BUFFER_SIZE = "org.apache.felix.http.jetty.headerBufferSize";
/** Felix specific property to configure the request buffer size. Default is 8KB */
public static final String FELIX_JETTY_REQUEST_BUFFER_SIZE = "org.apache.felix.http.jetty.requestBufferSize";
/** Felix specific property to configure the request buffer size. Default is 24KB */
public static final String FELIX_JETTY_RESPONSE_BUFFER_SIZE = "org.apache.felix.http.jetty.responseBufferSize";
/** Felix specific property to configure the max form size. Default is 200KB */
public static final String FELIX_JETTY_MAX_FORM_SIZE = "org.apache.felix.http.jetty.maxFormSize";
/** Felix specific property to enable Jetty MBeans. Valid values are "true", "false". Default is false */
public static final String FELIX_HTTP_MBEANS = "org.apache.felix.http.mbeans";
/** Felix specific property to set the servlet context path of the Http Service */
public static final String FELIX_HTTP_CONTEXT_PATH = "org.apache.felix.http.context_path";
/** Felix specific property to set the list of path exclusions for Web Application Bundles */
public static final String FELIX_HTTP_PATH_EXCLUSIONS = "org.apache.felix.http.path_exclusions";
/** Felix specific property to configure the excluded cipher suites. @deprecated use {@link #FELIX_JETTY_EXCLUDED_SUITES} instead. */
@Deprecated
public static final String FELIX_JETTY_EXCLUDED_SUITES_OLD = "org.apache.felix.https.jetty.cipersuites.excluded";
/** Felix specific property to configure the excluded cipher suites */
public static final String FELIX_JETTY_EXCLUDED_SUITES = "org.apache.felix.https.jetty.ciphersuites.excluded";
/** Felix specific property to configure the included cipher suites. @deprecated use {@link #FELIX_JETTY_INCLUDED_SUITES} instead. */
@Deprecated
public static final String FELIX_JETTY_INCLUDED_SUITES_OLD = "org.apache.felix.https.jetty.cipersuites.included";
/** Felix specific property to configure the included cipher suites. */
public static final String FELIX_JETTY_INCLUDED_SUITES = "org.apache.felix.https.jetty.ciphersuites.included";
/** Felix specific property to specify whether a server header should be sent (defaults to true) */
public static final String FELIX_JETTY_SEND_SERVER_HEADER = "org.apache.felix.http.jetty.sendServerHeader";
/** Felix specific property to configure the included protocols */
public static final String FELIX_JETTY_INCLUDED_PROTOCOLS = "org.apache.felix.https.jetty.protocols.included";
/** Felix specific property to configure the excluded protocols */
public static final String FELIX_JETTY_EXCLUDED_PROTOCOLS = "org.apache.felix.https.jetty.protocols.excluded";
/** Felix specific properties to be able to disable renegotiation protocol for TLSv1 */
public static final String FELIX_JETTY_RENEGOTIATION_ALLOWED = "org.apache.felix.https.jetty.renegotiateAllowed";
/** Felix specific property to control whether to enable Proxy/Load Balancer Connection */
public static final String FELIX_PROXY_LOAD_BALANCER_CONNECTION_ENABLE = "org.apache.felix.proxy.load.balancer.connection.enable";
/** Felix specific property to configure the session cookie httpOnly flag */
public static final String FELIX_JETTY_SESSION_COOKIE_HTTP_ONLY = "org.apache.felix.https.jetty.session.cookie.httpOnly";
/** Felix specific property to configure the session cookie secure flag */
public static final String FELIX_JETTY_SESSION_COOKIE_SECURE = "org.apache.felix.https.jetty.session.cookie.secure";
/** Felix specific property to configure session id path parameter*/
public static final String FELIX_JETTY_SERVLET_SESSION_ID_PATH_PARAMETER_NAME = "org.eclipse.jetty.servlet.SessionIdPathParameterName";
/** Felix specific property to configure whether JSESSIONID parameter will be added when encoding external URLs */
public static final String FELIX_JETTY_SERVLET_CHECK_REMOTE_SESSION_ENCODING = "org.eclipse.jetty.servlet.CheckingRemoteSessionIdEncoding";
/** Felix specific property to configure session cookie name */
public static final String FELIX_JETTY_SERVLET_SESSION_COOKIE_NAME = "org.eclipse.jetty.servlet.SessionCookie";
/** Felix specific property to configure session domain */
public static final String FELIX_JETTY_SERVLET_SESSION_DOMAIN = "org.eclipse.jetty.servlet.SessionDomain";
/** Felix specific property to configure session path */
public static final String FELIX_JETTY_SERVLET_SESSION_PATH = "org.eclipse.jetty.servlet.SessionPath";
/** Felix specific property to configure session max age */
public static final String FELIX_JETTY_SERVLET_SESSION_MAX_AGE = "org.eclipse.jetty.servlet.MaxAge";
/** Felix specific property to configure session scavenging interval in Seconds */
public static final String FELIX_JETTY_SESSION_SCAVENGING_INTERVAL = "org.eclipse.jetty.servlet.SessionScavengingInterval";
/** Felix specific property to set HTTP instance name. */
public static final String FELIX_HTTP_SERVICE_NAME = "org.apache.felix.http.name";
/** Felix specific property to configure a filter for RequestLog services */
public static final String FELIX_HTTP_REQUEST_LOG_FILTER = "org.apache.felix.http.requestlog.filter";
/** Felix specific property to enable request logging to the OSGi Log Service */
public static final String FELIX_HTTP_REQUEST_LOG_OSGI_ENABLE = "org.apache.felix.http.requestlog.osgi.enable";
/** Felix specific property to specify the published "name" property of the OSGi Log Service-base Request Log service. Allows server configs to filter on specific log services. */
public static final String FELIX_HTTP_REQUEST_LOG_OSGI_SERVICE_NAME = "org.apache.felix.http.requestlog.osgi.name";
/** Felix specific property to control the level of the log messages generated by the OSGi Log Service-based request log. Values must correspond to the constants defined in the LogService interface, default is 3 "INFO". */
public static final String FELIX_HTTP_REQUEST_LOG_OSGI_LEVEL = "org.apache.felix.http.requestlog.osgi.level";
/** Felix specific property to enable request logging to a file and provide the path to that file. Default is null meaning that the file log is disabled. */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_PATH = "org.apache.felix.http.requestlog.file.path";
/** Felix specific property to specify the published "name" property of the file-based RequestLog service. Allows server configs to filter on specific log services. */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_SERVICE_NAME = "org.apache.felix.http.requestlog.file.name";
/** Felix specific property to enable file request logging to be asynchronous */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_ASYNC = "org.apache.felix.http.requestlog.file.async";
/** Felix specific property to enable request logging to append to the log file rather than overwriting */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_APPEND = "org.apache.felix.http.requestlog.file.append";
/** Felix specific property to specify the number of days the request log file is retained */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_RETAIN_DAYS = "org.apache.felix.http.requestlog.file.retaindays";
/** Felix specific property to specify the date format in request log file names */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_FILENAME_DATE_FORMAT = "org.apache.felix.http.requestlog.file.dateformat";
/** Felix specific property to enable extended request logging to a named file */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_EXTENDED = "org.apache.felix.http.requestlog.file.extended";
/** Felix specific property to ignore matching paths in the request log file */
public static final String FELIX_HTTP_REQUEST_LOG_FILE_IGNORE_PATHS = "org.apache.felix.http.requestlog.file.ignorepaths";
/** Felix specific property to enable request logging cookies in the request log file*/
public static final String FELIX_HTTP_REQUEST_LOG_FILE_LOG_COOKIES = "org.apache.felix.http.requestlog.file.logcookies";
/** Felix specific property to enable request logging the host name in the request log file*/
public static final String FELIX_HTTP_REQUEST_LOG_FILE_LOG_SERVER = "org.apache.felix.http.requestlog.file.logserver";
/** Felix specific property to enable request logging request processing time in the request log file*/
public static final String FELIX_HTTP_REQUEST_LOG_FILE_LOG_LATENCY = "org.apache.felix.http.requestlog.file.loglatency";
/** Felix specific property to specify the date format used for the logging timestamps*/
public static final String FELIX_HTTP_REQUEST_LOG_FILE_DATE_FORMAT = "org.apache.felix.http.requestlog.file.logdateformat";
/** Felix specific property to specify the timezone used for the logging timestamps*/
public static final String FELIX_HTTP_REQUEST_LOG_FILE_TIMEZONE = "org.apache.felix.http.requestlog.file.timezone";
/** Felix specific property to define custom properties for the http runtime service. */
public static final String FELIX_CUSTOM_HTTP_RUNTIME_PROPERTY_PREFIX = "org.apache.felix.http.runtime.init.";
/** Felix specific property to specify whether the server should collect statistics information (defaults to false) */
public static final String FELIX_JETTY_STATISTICS_HANDLER_ENABLE = "org.apache.felix.jetty.statisticshandler.enable";
/** Felix specific property to specify whether the server should use a server-wide gzip handler (defaults to true) */
public static final String FELIX_JETTY_GZIP_HANDLER_ENABLE = "org.apache.felix.jetty.gziphandler.enable";
/** Felix specific property to specify the minimum response size to trigger dynamic compression */
public static final String FELIX_JETTY_GZIP_MIN_GZIP_SIZE = "org.apache.felix.jetty.gzip.minGzipSize";
/** Felix specific property to specify the compression level to use to initialize {@link Deflater#setLevel(int)} */
public static final String FELIX_JETTY_GZIP_COMPRESSION_LEVEL = "org.apache.felix.jetty.gzip.compressionLevel";
/** Felix specific property to specify the size in bytes of the buffer to inflate compressed request, or 0 for no inflation. */
public static final String FELIX_JETTY_GZIP_INFLATE_BUFFER_SIZE = "org.apache.felix.jetty.gzip.inflateBufferSize";
/** Felix specific property to specify the {@link Deflater} flush mode to use. */
public static final String FELIX_JETTY_GZIP_SYNC_FLUSH = "org.apache.felix.jetty.gzip.syncFlush";
/** Felix specific property to specify the regular expressions matching user agents to exclude */
public static final String FELIX_JETTY_GZIP_EXCLUDED_USER_AGENT = "org.apache.felix.jetty.gzip.excludedUserAgents";
/** Felix specific property to specify the methods to include in compression */
public static final String FELIX_JETTY_GZIP_INCLUDED_METHODS = "org.apache.felix.jetty.gzip.includedMethods";
/** Felix specific property to specify the methods to exclude from compression */
public static final String FELIX_JETTY_GZIP_EXCLUDED_METHODS = "org.apache.felix.jetty.gzip.excludedMethods";
/** Felix specific property to specify the path specs to include. Inclusion takes precedence over exclusion. */
public static final String FELIX_JETTY_GZIP_INCLUDED_PATHS = "org.apache.felix.jetty.gzip.includedPaths";
/** Felix specific property to specify the path specs to exclude. */
public static final String FELIX_JETTY_GZIP_EXCLUDED_PATHS = "org.apache.felix.jetty.gzip.excludedPaths";
/** Felix specific property to specify the included mime types. Inclusion takes precedence over exclusion. */
public static final String FELIX_JETTY_GZIP_INCLUDED_MIME_TYPES = "org.apache.felix.jetty.gzip.includedMimeTypes";
/** Felix specific property to specify the excluded mime types. */
public static final String FELIX_JETTY_GZIP_EXCLUDED_MIME_TYPES = "org.apache.felix.jetty.gzip.excludedMimeTypes";
/** Felix specific property to specify the stop timeout of the jetty server */
public static final String FELIX_JETTY_STOP_TIMEOUT = "org.apache.felix.jetty.stopTimeout";
private static String validateContextPath(String ctxPath)
{
// undefined, empty, or root context path
if (ctxPath == null || ctxPath.length() == 0 || "/".equals(ctxPath))
{
return "/";
}
// ensure leading but no trailing slash
if (!ctxPath.startsWith("/"))
{
ctxPath = "/".concat(ctxPath);
}
while (ctxPath.endsWith("/"))
{
ctxPath = ctxPath.substring(0, ctxPath.length() - 1);
}
return ctxPath;
}
private final BundleContext context;
/**
* Properties from the configuration not matching any of the
* predefined properties. These properties can be accessed from the
* getProperty* methods.
* <p>
* This map is indexed by String objects (the property names) and
* the values are just objects as provided by the configuration.
*/
private volatile Dictionary<String, ?> config;
private volatile Integer httpPort;
private volatile Integer httpsPort;
public JettyConfig(final BundleContext context)
{
this.context = context;
reset();
}
/**
* Returns the named generic configuration property from the
* configuration or the bundle context. If neither property is defined
* return the defValue.
*/
public boolean getBooleanProperty(String name, boolean defValue)
{
String value = getProperty(name, null);
if (value != null)
{
return "true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value);
}
return defValue;
}
public String getClientcert()
{
return getProperty(FELIX_HTTPS_CLIENT_CERT, "none");
}
public String getContextPath()
{
return validateContextPath(getProperty(FELIX_HTTP_CONTEXT_PATH, null));
}
public String[] getExcludedCipherSuites()
{
return getStringArrayProperty(FELIX_JETTY_EXCLUDED_SUITES, getStringArrayProperty(FELIX_JETTY_EXCLUDED_SUITES_OLD, null));
}
public String[] getIncludedProtocols()
{
return getStringArrayProperty(FELIX_JETTY_INCLUDED_PROTOCOLS, null);
}
public String[] getExcludedProtocols()
{
return getStringArrayProperty(FELIX_JETTY_EXCLUDED_PROTOCOLS, null);
}
public int getHeaderSize()
{
return getIntProperty(FELIX_JETTY_HEADER_BUFFER_SIZE, 16 * 1024);
}
public String getHost()
{
return getProperty(FELIX_HOST, null);
}
public int getHttpPort()
{
if (httpPort == null) {
httpPort = determinePort(String.valueOf(getProperty(HTTP_PORT)), 8080);
}
return httpPort;
}
public int getHttpsPort()
{
if (httpsPort == null) {
httpsPort = determinePort(String.valueOf(getProperty(HTTPS_PORT)), 8443);
}
return httpsPort;
}
public int getHttpTimeout()
{
return getIntProperty(HTTP_TIMEOUT, 60000);
}
public String[] getIncludedCipherSuites()
{
return getStringArrayProperty(FELIX_JETTY_INCLUDED_SUITES, getStringArrayProperty(FELIX_JETTY_INCLUDED_SUITES_OLD, null));
}
/**
* Returns the named generic configuration property from the
* configuration or the bundle context. If neither property is defined
* return the defValue.
*/
public int getIntProperty(String name, int defValue)
{
return parseInt(getProperty(name, null), defValue);
}
/**
* Returns the named generic configuration property from the
* configuration or the bundle context. If neither property is defined
* return the defValue.
*/
public long getLongProperty(String name, long defValue)
{
return parseLong(getProperty(name, null), defValue);
}
public String getKeyPassword()
{
return getProperty(FELIX_KEYSTORE_KEY_PASSWORD, this.context.getProperty(OSCAR_KEYSTORE_KEY_PASSWORD));
}
public String getKeystore()
{
return getProperty(FELIX_KEYSTORE, this.context.getProperty(OSCAR_KEYSTORE));
}
public String getKeystoreType()
{
return getProperty(FELIX_KEYSTORE_TYPE, KeyStore.getDefaultType());
}
public String getPassword()
{
return getProperty(FELIX_KEYSTORE_PASSWORD, this.context.getProperty(OSCAR_KEYSTORE_PASSWORD));
}
public String[] getPathExclusions()
{
return getStringArrayProperty(FELIX_HTTP_PATH_EXCLUSIONS, new String[] { "/system" });
}
/**
* Returns the named generic configuration property from the
* configuration or the bundle context. If neither property is defined
* return the defValue.
*/
public String getProperty(String name, String defValue)
{
Object value = getProperty(name);
return value != null ? String.valueOf(value) : defValue;
}
public int getThreadPoolMax()
{
return getIntProperty(FELIX_JETTY_THREADPOOL_MAX, -1);
}
public int getAcceptors()
{
return getIntProperty(FELIX_JETTY_ACCEPTORS, -1);
}
public int getSelectors()
{
return getIntProperty(FELIX_JETTY_SELECTORS, -1);
}
public int getRequestBufferSize()
{
return getIntProperty(FELIX_JETTY_REQUEST_BUFFER_SIZE, 8 * 1024);
}
public int getResponseBufferSize()
{
return getIntProperty(FELIX_JETTY_RESPONSE_BUFFER_SIZE, 24 * 1024);
}
public int getMaxFormSize()
{
return getIntProperty(FELIX_JETTY_MAX_FORM_SIZE, 200 * 1024);
}
/**
* Returns the configured session timeout in minutes or zero if not
* configured.
*/
public int getSessionTimeout()
{
return getIntProperty(FELIX_SESSION_TIMEOUT, 0);
}
public String getTrustPassword()
{
return getProperty(FELIX_TRUSTSTORE_PASSWORD, null);
}
public String getTruststore()
{
String value = getProperty(FELIX_TRUSTSTORE, null);
return value == null || value.trim().length() == 0 ? null : value;
}
public String getTruststoreType()
{
return getProperty(FELIX_TRUSTSTORE_TYPE, KeyStore.getDefaultType());
}
public boolean isRegisterMBeans()
{
return getBooleanProperty(FELIX_HTTP_MBEANS, false);
}
/**
* Returns <code>true</code> if HTTP is configured to be used (
* {@link #FELIX_HTTP_ENABLE}) and
* the configured HTTP port ({@link #HTTP_PORT}) is higher than zero.
*/
public boolean isUseHttp()
{
boolean useHttp = getBooleanProperty(FELIX_HTTP_ENABLE, true);
return useHttp && getHttpPort() > 0;
}
public boolean isSendServerHeader()
{
return getBooleanProperty(FELIX_JETTY_SEND_SERVER_HEADER, false);
}
/**
* Returns <code>true</code> if HTTPS is configured to be used (
* {@link #FELIX_HTTPS_ENABLE}) and
* the configured HTTP port ({@link #HTTPS_PORT}) is higher than zero.
*/
public boolean isUseHttps()
{
boolean useHttps = getBooleanProperty(FELIX_HTTPS_ENABLE, getBooleanProperty(OSCAR_HTTPS_ENABLE, false));
return useHttps && getHttpsPort() > 0;
}
public boolean isProxyLoadBalancerConnection()
{
return getBooleanProperty(FELIX_PROXY_LOAD_BALANCER_CONNECTION_ENABLE, false);
}
public boolean isRenegotiationAllowed() {
return getBooleanProperty(FELIX_JETTY_RENEGOTIATION_ALLOWED, false);
}
public String getHttpServiceName()
{
return (String) getProperty(FELIX_HTTP_SERVICE_NAME);
}
public String getRequestLogFilter() {
return getProperty(FELIX_HTTP_REQUEST_LOG_FILTER, null);
}
public boolean isRequestLogOSGiEnabled() {
return getBooleanProperty(FELIX_HTTP_REQUEST_LOG_OSGI_ENABLE, false);
}
public String getRequestLogOSGiServiceName() {
return (String) getProperty(FELIX_HTTP_REQUEST_LOG_OSGI_SERVICE_NAME);
}
public int getRequestLogOSGiLevel() {
return getIntProperty(FELIX_HTTP_REQUEST_LOG_OSGI_LEVEL, 3); // 3 == LogService.LOG_INFO
}
public String getRequestLogFilePath() {
return getProperty(FELIX_HTTP_REQUEST_LOG_FILE_PATH, null);
}
public String getRequestLogFileServiceName() {
return getProperty(FELIX_HTTP_REQUEST_LOG_FILE_SERVICE_NAME, "file");
}
public boolean isRequestLogFileAsync() {
return getBooleanProperty(FELIX_HTTP_REQUEST_LOG_FILE_ASYNC, false);
}
public boolean isRequestLogFileAppend() {
return getBooleanProperty(FELIX_HTTP_REQUEST_LOG_FILE_APPEND, true);
}
public int getRequestLogFileRetainDays() {
return getIntProperty(FELIX_HTTP_REQUEST_LOG_FILE_RETAIN_DAYS, 31);
}
public String getRequestLogFilenameDateFormat() {
return getProperty(FELIX_HTTP_REQUEST_LOG_FILE_FILENAME_DATE_FORMAT, null);
}
public boolean isRequestLogFileExtended() {
return getBooleanProperty(FELIX_HTTP_REQUEST_LOG_FILE_EXTENDED, false);
}
public String[] getRequestLogFileIgnorePaths() {
return getStringArrayProperty(FELIX_HTTP_REQUEST_LOG_FILE_IGNORE_PATHS, new String[0]);
}
public boolean isRequestLogFileLogCookies() {
return getBooleanProperty(FELIX_HTTP_REQUEST_LOG_FILE_LOG_COOKIES, false);
}
public boolean isRequestLogFileLogServer() {
return getBooleanProperty(FELIX_HTTP_REQUEST_LOG_FILE_LOG_SERVER, false);
}
public boolean isRequestLogFileLogLatency() {
return getBooleanProperty(FELIX_HTTP_REQUEST_LOG_FILE_LOG_LATENCY, false);
}
public String getRequestLogDateFormat() {
return getProperty(FELIX_HTTP_REQUEST_LOG_FILE_DATE_FORMAT, null);
}
public String getRequestLogTimeZone() {
return getProperty(FELIX_HTTP_REQUEST_LOG_FILE_TIMEZONE, null);
}
public boolean isStatisticsHandlerEnabled() {
return getBooleanProperty(FELIX_JETTY_STATISTICS_HANDLER_ENABLE, false);
}
public boolean isGzipHandlerEnabled() {
return getBooleanProperty(FELIX_JETTY_GZIP_HANDLER_ENABLE, false);
}
public int getGzipMinGzipSize() {
return getIntProperty(FELIX_JETTY_GZIP_MIN_GZIP_SIZE, GzipHandler.DEFAULT_MIN_GZIP_SIZE);
}
public int getGzipCompressionLevel() {
return getIntProperty(FELIX_JETTY_GZIP_COMPRESSION_LEVEL, Deflater.DEFAULT_COMPRESSION);
}
public int getGzipInflateBufferSize() {
return getIntProperty(FELIX_JETTY_GZIP_INFLATE_BUFFER_SIZE, -1);
}
public boolean isGzipSyncFlush() {
return getBooleanProperty(FELIX_JETTY_GZIP_SYNC_FLUSH, false);
}
public String[] getGzipExcludedUserAgent() {
return getStringArrayProperty(FELIX_JETTY_GZIP_EXCLUDED_USER_AGENT, new String[0]);
}
public String[] getGzipIncludedMethods() {
return getStringArrayProperty(FELIX_JETTY_GZIP_INCLUDED_METHODS, new String[0]);
}
public String[] getGzipExcludedMethods() {
return getStringArrayProperty(FELIX_JETTY_GZIP_EXCLUDED_METHODS, new String[0]);
}
public String[] getGzipIncludedPaths() {
return getStringArrayProperty(FELIX_JETTY_GZIP_INCLUDED_PATHS, new String[0]);
}
public String[] getGzipExcludedPaths() {
return getStringArrayProperty(FELIX_JETTY_GZIP_EXCLUDED_PATHS, new String[0]);
}
public String[] getGzipIncludedMimeTypes() {
return getStringArrayProperty(FELIX_JETTY_GZIP_INCLUDED_MIME_TYPES, new String[0]);
}
public String[] getGzipExcludedMimeTypes() {
return getStringArrayProperty(FELIX_JETTY_GZIP_EXCLUDED_MIME_TYPES, new String[0]);
}
public long getStopTimeout() {
return getLongProperty(FELIX_JETTY_STOP_TIMEOUT, -1l);
}
public void reset()
{
update(null);
}
public void setServiceProperties(Hashtable<String, Object> props)
{
props.put(HTTP_PORT, Integer.toString(getHttpPort()));
props.put(HTTPS_PORT, Integer.toString(getHttpsPort()));
props.put(FELIX_HTTP_ENABLE, Boolean.toString(isUseHttp()));
props.put(FELIX_HTTPS_ENABLE, Boolean.toString(isUseHttps()));
if (getHttpServiceName() != null)
{
props.put(FELIX_HTTP_SERVICE_NAME, getHttpServiceName());
}
props.put(HttpConfig.PROP_INVALIDATE_SESSION, getBooleanProperty(HttpConfig.PROP_INVALIDATE_SESSION,
HttpConfig.DEFAULT_INVALIDATE_SESSION));
props.put(HttpConfig.PROP_UNIQUE_SESSION_ID, getBooleanProperty(HttpConfig.PROP_UNIQUE_SESSION_ID,
HttpConfig.DEFAULT_UNIQUE_SESSION_ID));
addCustomServiceProperties(props);
}
private void addCustomServiceProperties(final Hashtable<String, Object> props)
{
final Enumeration<String> keys = this.config.keys();
while(keys.hasMoreElements())
{
final String key = keys.nextElement();
if (key.startsWith(FELIX_CUSTOM_HTTP_RUNTIME_PROPERTY_PREFIX))
{
props.put(key.substring(FELIX_CUSTOM_HTTP_RUNTIME_PROPERTY_PREFIX.length()), this.config.get(key));
}
}
}
/**
* Updates this configuration with the given dictionary.
*
* @param props the dictionary with the new configuration values, can be <code>null</code> to reset this configuration to its defaults.
* @return <code>true</code> if the configuration was updated due to a changed value, or <code>false</code> if no change was found.
*/
public boolean update(Dictionary<String, ?> props)
{
if (props == null)
{
props = new Hashtable<>();
}
// clear cached ports
this.httpPort = null;
this.httpsPort = null;
// FELIX-4312 Check whether there's something changed in our configuration...
Dictionary<String, ?> currentConfig = this.config;
if (currentConfig == null || !props.equals(currentConfig))
{
this.config = props;
return true;
}
return false;
}
private void closeSilently(ServerSocket resource)
{
if (resource != null)
{
try
{
resource.close();
}
catch (IOException e)
{
// Ignore...
}
}
}
/**
* Determine the appropriate port to use. <code>portProp</code> is based
* "version range" as described in OSGi Core Spec v4.2 3.2.6. It can use the
* following forms:
* <dl>
* <dd>8000 | 8000</dd>
* <dd>[8000,9000] | 8000 &lt;= port &lt;= 9000</dd>
* <dd>[8000,9000) | 8000 &lt;= port &lt; 9000</dd>
* <dd>(8000,9000] | 8000 &lt; port &lt;= 9000</dd>
* <dd>(8000,9000) | 8000 &lt; port &lt; 9000</dd>
* <dd>[,9000) | 1 &lt; port &lt; 9000</dd>
* <dd>[8000,) | 8000 &lt;= port &lt; 65534</dd>
* </dl>
*
* @param portProp
* The port property value to parse.
* @return The port determined to be usable. -1 if failed to find a port.
*/
private int determinePort(String portProp, int dflt)
{
// Default cases include null/empty range pattern or pattern == *.
if (portProp == null || "".equals(portProp.trim()))
{
return dflt;
}
// asking for random port, so let ServerSocket handle it and return the answer
portProp = portProp.trim();
if ("*".equals(portProp) || "0".equals(portProp))
{
return getSocketPort(0);
}
else
{
// check that the port property is a version range as described in
// OSGi Core Spec v4.2 3.2.6.
// deviations from the spec are limited to:
// * start, end of interval defaults to 1, 65535, respectively, if missing.
char startsWith = portProp.charAt(0);
char endsWith = portProp.charAt(portProp.length() - 1);
int minPort = 1;
int maxPort = 65535;
if (portProp.contains(",") && (startsWith == '[' || startsWith == '(') && (endsWith == ']' || endsWith == ')'))
{
String interval = portProp.substring(1, portProp.length() - 1);
int comma = interval.indexOf(',');
// check if the comma is first (start port in range is missing)
int start = (comma == 0) ? minPort : parseInt(interval.substring(0, comma), minPort);
// check if the comma is last (end port in range is missing)
int end = (comma == interval.length() - 1) ? maxPort : parseInt(interval.substring(comma + 1), maxPort);
// check for exclusive notation
if (startsWith == '(')
{
start++;
}
if (endsWith == ')')
{
end--;
}
// find a port in the requested range
int port = start - 1;
for (int i = start; port < start && i <= end; i++)
{
port = getSocketPort(i);
}
return (port < start) ? dflt : port;
}
else
{
// We don't recognize the pattern as special, so try to parse it to an int
return parseInt(portProp, dflt);
}
}
}
private int getSocketPort(int i)
{
int port = -1;
ServerSocket ss = null;
try
{
ss = new ServerSocket(i);
port = ss.getLocalPort();
}
catch (IOException e)
{
SystemLogger.debug("Unable to bind to port: " + i);
}
finally
{
closeSilently(ss);
}
return port;
}
private Object getProperty(final String name)
{
Dictionary<String, ?> conf = this.config;
Object value = (conf != null) ? conf.get(name) : null;
if (value == null)
{
value = this.context.getProperty(name);
}
return value;
}
/**
* Get the property value as a string array.
* Empty values are filtered out - if the resulting array is empty
* the default value is returned.
*/
private String[] getStringArrayProperty(String name, String[] defValue)
{
Object value = getProperty(name);
if (value instanceof String)
{
final String stringVal = ((String) value).trim();
if (stringVal.length() > 0)
{
return stringVal.split(",");
}
}
else if (value instanceof String[])
{
final String[] stringArr = (String[]) value;
final List<String> list = new ArrayList<>();
for (final String stringVal : stringArr)
{
if (stringVal.trim().length() > 0)
{
list.add(stringVal.trim());
}
}
if (list.size() > 0)
{
return list.toArray(new String[list.size()]);
}
}
else if (value instanceof Collection)
{
final ArrayList<String> conv = new ArrayList<>();
for (Iterator<?> vi = ((Collection<?>) value).iterator(); vi.hasNext();)
{
Object object = vi.next();
if (object != null)
{
conv.add(String.valueOf(object));
}
}
if (conv.size() > 0)
{
return conv.toArray(new String[conv.size()]);
}
}
return defValue;
}
private int parseInt(String value, int dflt)
{
try
{
return Integer.parseInt(value);
}
catch (NumberFormatException e)
{
return dflt;
}
}
private long parseLong(String value, long dflt)
{
try
{
return Long.parseLong(value);
}
catch (NumberFormatException e)
{
return dflt;
}
}
}