You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
587 lines
17 KiB
587 lines
17 KiB
/** |
|
* Copyright (c) 2012-2019 Nikita Koksharov |
|
* |
|
* Licensed 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 com.fr.third.socketio; |
|
|
|
import java.io.InputStream; |
|
import java.util.Arrays; |
|
import java.util.List; |
|
|
|
import com.fr.third.socketio.handler.SuccessAuthorizationListener; |
|
import com.fr.third.socketio.listener.DefaultExceptionListener; |
|
import com.fr.third.socketio.listener.ExceptionListener; |
|
import com.fr.third.socketio.protocol.JsonSupport; |
|
import com.fr.third.socketio.store.MemoryStoreFactory; |
|
import com.fr.third.socketio.store.RedissonStoreFactory; |
|
import com.fr.third.socketio.store.StoreFactory; |
|
|
|
import javax.net.ssl.KeyManagerFactory; |
|
|
|
public class Configuration { |
|
|
|
private ExceptionListener exceptionListener = new DefaultExceptionListener(); |
|
|
|
private String context = "/socket.io"; |
|
|
|
private List<Transport> transports = Arrays.asList(Transport.WEBSOCKET, Transport.POLLING); |
|
|
|
private int bossThreads = 0; // 0 = current_processors_amount * 2 |
|
private int workerThreads = 0; // 0 = current_processors_amount * 2 |
|
private boolean useLinuxNativeEpoll; |
|
|
|
private boolean allowCustomRequests = false; |
|
|
|
private int upgradeTimeout = 10000; |
|
private int pingTimeout = 60000; |
|
private int pingInterval = 25000; |
|
private int firstDataTimeout = 5000; |
|
|
|
private int maxHttpContentLength = 64 * 1024; |
|
private int maxFramePayloadLength = 64 * 1024; |
|
|
|
private String packagePrefix; |
|
private String hostname; |
|
private int port = -1; |
|
|
|
private String sslProtocol = "TLSv1"; |
|
|
|
private String keyStoreFormat = "JKS"; |
|
private InputStream keyStore; |
|
private String keyStorePassword; |
|
|
|
private String trustStoreFormat = "JKS"; |
|
private InputStream trustStore; |
|
private String trustStorePassword; |
|
|
|
private String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); |
|
|
|
private boolean preferDirectBuffer = true; |
|
|
|
private SocketConfig socketConfig = new SocketConfig(); |
|
|
|
private StoreFactory storeFactory = new MemoryStoreFactory(); |
|
|
|
private JsonSupport jsonSupport; |
|
|
|
private AuthorizationListener authorizationListener = new SuccessAuthorizationListener(); |
|
|
|
private AckMode ackMode = AckMode.AUTO_SUCCESS_ONLY; |
|
|
|
private boolean addVersionHeader = true; |
|
|
|
private String origin; |
|
|
|
private boolean httpCompression = true; |
|
|
|
private boolean websocketCompression = true; |
|
|
|
private boolean randomSession = false; |
|
|
|
public Configuration() { |
|
} |
|
|
|
/** |
|
* Defend from further modifications by cloning |
|
* |
|
* @param conf - Configuration object to clone |
|
*/ |
|
Configuration(Configuration conf) { |
|
setBossThreads(conf.getBossThreads()); |
|
setWorkerThreads(conf.getWorkerThreads()); |
|
setUseLinuxNativeEpoll(conf.isUseLinuxNativeEpoll()); |
|
|
|
setPingInterval(conf.getPingInterval()); |
|
setPingTimeout(conf.getPingTimeout()); |
|
|
|
setHostname(conf.getHostname()); |
|
setPort(conf.getPort()); |
|
|
|
if (conf.getJsonSupport() == null) { |
|
try { |
|
getClass().getClassLoader().loadClass("com.fr.third.fasterxml.jackson.databind.ObjectMapper"); |
|
try { |
|
Class<?> jjs = getClass().getClassLoader().loadClass("com.fr.third.socketio.protocol.JacksonJsonSupport"); |
|
JsonSupport js = (JsonSupport) jjs.getConstructor().newInstance(); |
|
conf.setJsonSupport(js); |
|
} catch (Exception e) { |
|
throw new IllegalArgumentException(e); |
|
} |
|
} catch (ClassNotFoundException e) { |
|
throw new IllegalArgumentException("Can't find jackson lib in classpath", e); |
|
} |
|
} |
|
|
|
setJsonSupport(new JsonSupportWrapper(conf.getJsonSupport())); |
|
setContext(conf.getContext()); |
|
setAllowCustomRequests(conf.isAllowCustomRequests()); |
|
|
|
setKeyStorePassword(conf.getKeyStorePassword()); |
|
setKeyStore(conf.getKeyStore()); |
|
setKeyStoreFormat(conf.getKeyStoreFormat()); |
|
setTrustStore(conf.getTrustStore()); |
|
setTrustStoreFormat(conf.getTrustStoreFormat()); |
|
setTrustStorePassword(conf.getTrustStorePassword()); |
|
setKeyManagerFactoryAlgorithm(conf.getKeyManagerFactoryAlgorithm()); |
|
|
|
setTransports(conf.getTransports().toArray(new Transport[conf.getTransports().size()])); |
|
setMaxHttpContentLength(conf.getMaxHttpContentLength()); |
|
setPackagePrefix(conf.getPackagePrefix()); |
|
|
|
setPreferDirectBuffer(conf.isPreferDirectBuffer()); |
|
setStoreFactory(conf.getStoreFactory()); |
|
setAuthorizationListener(conf.getAuthorizationListener()); |
|
setExceptionListener(conf.getExceptionListener()); |
|
setSocketConfig(conf.getSocketConfig()); |
|
setAckMode(conf.getAckMode()); |
|
setMaxFramePayloadLength(conf.getMaxFramePayloadLength()); |
|
setUpgradeTimeout(conf.getUpgradeTimeout()); |
|
|
|
setAddVersionHeader(conf.isAddVersionHeader()); |
|
setOrigin(conf.getOrigin()); |
|
setSSLProtocol(conf.getSSLProtocol()); |
|
|
|
setHttpCompression(conf.isHttpCompression()); |
|
setWebsocketCompression(conf.isWebsocketCompression()); |
|
setRandomSession(conf.randomSession); |
|
} |
|
|
|
public JsonSupport getJsonSupport() { |
|
return jsonSupport; |
|
} |
|
|
|
/** |
|
* Allows to setup custom implementation of |
|
* JSON serialization/deserialization |
|
* |
|
* @param jsonSupport - json mapper |
|
* |
|
* @see JsonSupport |
|
*/ |
|
public void setJsonSupport(JsonSupport jsonSupport) { |
|
this.jsonSupport = jsonSupport; |
|
} |
|
|
|
public String getHostname() { |
|
return hostname; |
|
} |
|
|
|
/** |
|
* Optional parameter. If not set then bind address |
|
* will be 0.0.0.0 or ::0 |
|
* |
|
* @param hostname - name of host |
|
*/ |
|
public void setHostname(String hostname) { |
|
this.hostname = hostname; |
|
} |
|
|
|
public int getPort() { |
|
return port; |
|
} |
|
public void setPort(int port) { |
|
this.port = port; |
|
} |
|
|
|
public int getBossThreads() { |
|
return bossThreads; |
|
} |
|
public void setBossThreads(int bossThreads) { |
|
this.bossThreads = bossThreads; |
|
} |
|
|
|
public int getWorkerThreads() { |
|
return workerThreads; |
|
} |
|
public void setWorkerThreads(int workerThreads) { |
|
this.workerThreads = workerThreads; |
|
} |
|
|
|
/** |
|
* Ping interval |
|
* |
|
* @param heartbeatIntervalSecs - time in milliseconds |
|
*/ |
|
public void setPingInterval(int heartbeatIntervalSecs) { |
|
this.pingInterval = heartbeatIntervalSecs; |
|
} |
|
public int getPingInterval() { |
|
return pingInterval; |
|
} |
|
|
|
/** |
|
* Ping timeout |
|
* Use <code>0</code> to disable it |
|
* |
|
* @param heartbeatTimeoutSecs - time in milliseconds |
|
*/ |
|
public void setPingTimeout(int heartbeatTimeoutSecs) { |
|
this.pingTimeout = heartbeatTimeoutSecs; |
|
} |
|
public int getPingTimeout() { |
|
return pingTimeout; |
|
} |
|
public boolean isHeartbeatsEnabled() { |
|
return pingTimeout > 0; |
|
} |
|
|
|
public String getContext() { |
|
return context; |
|
} |
|
public void setContext(String context) { |
|
this.context = context; |
|
} |
|
|
|
public boolean isAllowCustomRequests() { |
|
return allowCustomRequests; |
|
} |
|
|
|
/** |
|
* Allow to service custom requests differs from socket.io protocol. |
|
* In this case it's necessary to add own handler which handle them |
|
* to avoid hang connections. |
|
* Default is {@code false} |
|
* |
|
* @param allowCustomRequests - {@code true} to allow |
|
*/ |
|
public void setAllowCustomRequests(boolean allowCustomRequests) { |
|
this.allowCustomRequests = allowCustomRequests; |
|
} |
|
|
|
/** |
|
* SSL key store password |
|
* |
|
* @param keyStorePassword - password of key store |
|
*/ |
|
public void setKeyStorePassword(String keyStorePassword) { |
|
this.keyStorePassword = keyStorePassword; |
|
} |
|
public String getKeyStorePassword() { |
|
return keyStorePassword; |
|
} |
|
|
|
/** |
|
* SSL key store stream, maybe appointed to any source |
|
* |
|
* @param keyStore - key store input stream |
|
*/ |
|
public void setKeyStore(InputStream keyStore) { |
|
this.keyStore = keyStore; |
|
} |
|
public InputStream getKeyStore() { |
|
return keyStore; |
|
} |
|
|
|
/** |
|
* Key store format |
|
* |
|
* @param keyStoreFormat - key store format |
|
*/ |
|
public void setKeyStoreFormat(String keyStoreFormat) { |
|
this.keyStoreFormat = keyStoreFormat; |
|
} |
|
public String getKeyStoreFormat() { |
|
return keyStoreFormat; |
|
} |
|
|
|
/** |
|
* Set maximum http content length limit |
|
* |
|
* @param value |
|
* the maximum length of the aggregated http content. |
|
*/ |
|
public void setMaxHttpContentLength(int value) { |
|
this.maxHttpContentLength = value; |
|
} |
|
public int getMaxHttpContentLength() { |
|
return maxHttpContentLength; |
|
} |
|
|
|
/** |
|
* Transports supported by server |
|
* |
|
* @param transports - list of transports |
|
*/ |
|
public void setTransports(Transport ... transports) { |
|
if (transports.length == 0) { |
|
throw new IllegalArgumentException("Transports list can't be empty"); |
|
} |
|
this.transports = Arrays.asList(transports); |
|
} |
|
public List<Transport> getTransports() { |
|
return transports; |
|
} |
|
|
|
/** |
|
* Package prefix for sending json-object from client |
|
* without full class name. |
|
* |
|
* With defined package prefix socket.io client |
|
* just need to define '@class: 'SomeType'' in json object |
|
* instead of '@class: 'com.full.package.name.SomeType'' |
|
* |
|
* @param packagePrefix - prefix string |
|
* |
|
*/ |
|
public void setPackagePrefix(String packagePrefix) { |
|
this.packagePrefix = packagePrefix; |
|
} |
|
public String getPackagePrefix() { |
|
return packagePrefix; |
|
} |
|
|
|
/** |
|
* Buffer allocation method used during packet encoding. |
|
* Default is {@code true} |
|
* |
|
* @param preferDirectBuffer {@code true} if a direct buffer should be tried to be used as target for |
|
* the encoded messages. If {@code false} is used it will allocate a heap |
|
* buffer, which is backed by an byte array. |
|
*/ |
|
public void setPreferDirectBuffer(boolean preferDirectBuffer) { |
|
this.preferDirectBuffer = preferDirectBuffer; |
|
} |
|
public boolean isPreferDirectBuffer() { |
|
return preferDirectBuffer; |
|
} |
|
|
|
/** |
|
* Data store - used to store session data and implements distributed pubsub. |
|
* Default is {@code MemoryStoreFactory} |
|
* |
|
* @param clientStoreFactory - implements StoreFactory |
|
* |
|
* @see MemoryStoreFactory |
|
* @see RedissonStoreFactory |
|
*/ |
|
public void setStoreFactory(StoreFactory clientStoreFactory) { |
|
this.storeFactory = clientStoreFactory; |
|
} |
|
public StoreFactory getStoreFactory() { |
|
return storeFactory; |
|
} |
|
|
|
/** |
|
* Authorization listener invoked on every handshake. |
|
* Accepts or denies a client by {@code AuthorizationListener.isAuthorized} method. |
|
* <b>Accepts</b> all clients by default. |
|
* |
|
* @param authorizationListener - authorization listener itself |
|
* |
|
* @see AuthorizationListener |
|
*/ |
|
public void setAuthorizationListener(AuthorizationListener authorizationListener) { |
|
this.authorizationListener = authorizationListener; |
|
} |
|
public AuthorizationListener getAuthorizationListener() { |
|
return authorizationListener; |
|
} |
|
|
|
/** |
|
* Exception listener invoked on any exception in |
|
* SocketIO listener |
|
* |
|
* @param exceptionListener - listener |
|
* |
|
* @see ExceptionListener |
|
*/ |
|
public void setExceptionListener(ExceptionListener exceptionListener) { |
|
this.exceptionListener = exceptionListener; |
|
} |
|
public ExceptionListener getExceptionListener() { |
|
return exceptionListener; |
|
} |
|
|
|
public SocketConfig getSocketConfig() { |
|
return socketConfig; |
|
} |
|
/** |
|
* TCP socket configuration |
|
* |
|
* @param socketConfig - config |
|
*/ |
|
public void setSocketConfig(SocketConfig socketConfig) { |
|
this.socketConfig = socketConfig; |
|
} |
|
|
|
/** |
|
* Auto ack-response mode |
|
* Default is {@code AckMode.AUTO_SUCCESS_ONLY} |
|
* |
|
* @see AckMode |
|
* |
|
* @param ackMode - ack mode |
|
*/ |
|
public void setAckMode(AckMode ackMode) { |
|
this.ackMode = ackMode; |
|
} |
|
public AckMode getAckMode() { |
|
return ackMode; |
|
} |
|
|
|
|
|
public String getTrustStoreFormat() { |
|
return trustStoreFormat; |
|
} |
|
public void setTrustStoreFormat(String trustStoreFormat) { |
|
this.trustStoreFormat = trustStoreFormat; |
|
} |
|
|
|
public InputStream getTrustStore() { |
|
return trustStore; |
|
} |
|
public void setTrustStore(InputStream trustStore) { |
|
this.trustStore = trustStore; |
|
} |
|
|
|
public String getTrustStorePassword() { |
|
return trustStorePassword; |
|
} |
|
public void setTrustStorePassword(String trustStorePassword) { |
|
this.trustStorePassword = trustStorePassword; |
|
} |
|
|
|
public String getKeyManagerFactoryAlgorithm() { |
|
return keyManagerFactoryAlgorithm; |
|
} |
|
public void setKeyManagerFactoryAlgorithm(String keyManagerFactoryAlgorithm) { |
|
this.keyManagerFactoryAlgorithm = keyManagerFactoryAlgorithm; |
|
} |
|
|
|
|
|
/** |
|
* Set maximum websocket frame content length limit |
|
* |
|
* @param maxFramePayloadLength - length |
|
*/ |
|
public void setMaxFramePayloadLength(int maxFramePayloadLength) { |
|
this.maxFramePayloadLength = maxFramePayloadLength; |
|
} |
|
public int getMaxFramePayloadLength() { |
|
return maxFramePayloadLength; |
|
} |
|
|
|
/** |
|
* Transport upgrade timeout in milliseconds |
|
* |
|
* @param upgradeTimeout - upgrade timeout |
|
*/ |
|
public void setUpgradeTimeout(int upgradeTimeout) { |
|
this.upgradeTimeout = upgradeTimeout; |
|
} |
|
public int getUpgradeTimeout() { |
|
return upgradeTimeout; |
|
} |
|
|
|
/** |
|
* Adds <b>Server</b> header with lib version to http response. |
|
* <p> |
|
* Default is <code>true</code> |
|
* |
|
* @param addVersionHeader - <code>true</code> to add header |
|
*/ |
|
public void setAddVersionHeader(boolean addVersionHeader) { |
|
this.addVersionHeader = addVersionHeader; |
|
} |
|
public boolean isAddVersionHeader() { |
|
return addVersionHeader; |
|
} |
|
|
|
/** |
|
* Set <b>Access-Control-Allow-Origin</b> header value for http each |
|
* response. |
|
* Default is <code>null</code> |
|
* |
|
* If value is <code>null</code> then request <b>ORIGIN</b> header value used. |
|
* |
|
* @param origin - origin |
|
*/ |
|
public void setOrigin(String origin) { |
|
this.origin = origin; |
|
} |
|
public String getOrigin() { |
|
return origin; |
|
} |
|
|
|
public boolean isUseLinuxNativeEpoll() { |
|
return useLinuxNativeEpoll; |
|
} |
|
public void setUseLinuxNativeEpoll(boolean useLinuxNativeEpoll) { |
|
this.useLinuxNativeEpoll = useLinuxNativeEpoll; |
|
} |
|
|
|
/** |
|
* Set the name of the requested SSL protocol |
|
* |
|
* @param sslProtocol - name of protocol |
|
*/ |
|
public void setSSLProtocol(String sslProtocol) { |
|
this.sslProtocol = sslProtocol; |
|
} |
|
public String getSSLProtocol() { |
|
return sslProtocol; |
|
} |
|
|
|
/** |
|
* Timeout between channel opening and first data transfer |
|
* Helps to avoid 'silent channel' attack and prevents |
|
* 'Too many open files' problem in this case |
|
* |
|
* @param firstDataTimeout - timeout value |
|
*/ |
|
public void setFirstDataTimeout(int firstDataTimeout) { |
|
this.firstDataTimeout = firstDataTimeout; |
|
} |
|
public int getFirstDataTimeout() { |
|
return firstDataTimeout; |
|
} |
|
|
|
/** |
|
* Activate http protocol compression. Uses {@code gzip} or |
|
* {@code deflate} encoding choice depends on the {@code "Accept-Encoding"} header value. |
|
* <p> |
|
* Default is <code>true</code> |
|
* |
|
* @param httpCompression - <code>true</code> to use http compression |
|
*/ |
|
public void setHttpCompression(boolean httpCompression) { |
|
this.httpCompression = httpCompression; |
|
} |
|
public boolean isHttpCompression() { |
|
return httpCompression; |
|
} |
|
|
|
/** |
|
* Activate websocket protocol compression. |
|
* Uses {@code permessage-deflate} encoding only. |
|
* <p> |
|
* Default is <code>true</code> |
|
* |
|
* @param websocketCompression - <code>true</code> to use websocket compression |
|
*/ |
|
public void setWebsocketCompression(boolean websocketCompression) { |
|
this.websocketCompression = websocketCompression; |
|
} |
|
public boolean isWebsocketCompression() { |
|
return websocketCompression; |
|
} |
|
|
|
public boolean isRandomSession() { |
|
return randomSession; |
|
} |
|
|
|
public void setRandomSession(boolean randomSession) { |
|
this.randomSession = randomSession; |
|
} |
|
}
|
|
|