| /* |
| * 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 <= port <= 9000</dd> |
| * <dd>[8000,9000) | 8000 <= port < 9000</dd> |
| * <dd>(8000,9000] | 8000 < port <= 9000</dd> |
| * <dd>(8000,9000) | 8000 < port < 9000</dd> |
| * <dd>[,9000) | 1 < port < 9000</dd> |
| * <dd>[8000,) | 8000 <= port < 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; |
| } |
| } |
| } |