Skip to content

Commit

Permalink
[WFLY-6784] Add possibility to enable websocket compression via manag…
Browse files Browse the repository at this point in the history
  • Loading branch information
iweiss committed Sep 28, 2016
1 parent 32a02c9 commit a59f2df
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 20 deletions.
Expand Up @@ -224,6 +224,8 @@ public interface Constants {
String STATISTICS_ENABLED = "statistics-enabled"; String STATISTICS_ENABLED = "statistics-enabled";
String DEFAULT_SECURITY_DOMAIN = "default-security-domain"; String DEFAULT_SECURITY_DOMAIN = "default-security-domain";
String DISABLE_FILE_WATCH_SERVICE = "disable-file-watch-service"; String DISABLE_FILE_WATCH_SERVICE = "disable-file-watch-service";
String PER_MESSAGE_DEFLATE = "per-message-deflate";
String DEFLATER_LEVEL = "deflater-level";


// Elytron Integration // Elytron Integration
String APPLICATION_SECURITY_DOMAIN = "application-security-domain"; String APPLICATION_SECURITY_DOMAIN = "application-security-domain";
Expand Down
Expand Up @@ -100,7 +100,7 @@ public void installRuntimeServices(OperationContext context, ModelNode model, St


final int sessionTimeout = ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT.resolveModelAttribute(context, model).asInt(); final int sessionTimeout = ServletContainerDefinition.DEFAULT_SESSION_TIMEOUT.resolveModelAttribute(context, model).asInt();


WebsocketsDefinition.WebSocketInfo info = WebsocketsDefinition.INSTANCE.getConfig(context, model); WebsocketsDefinition.WebSocketInfo webSocketInfo = WebsocketsDefinition.INSTANCE.getConfig(context, fullModel.get(WebsocketsDefinition.INSTANCE.getPathElement().getKeyValuePair()));


final Map<String, String> mimeMappings = new HashMap<>(); final Map<String, String> mimeMappings = new HashMap<>();
if (fullModel.hasDefined(Constants.MIME_MAPPING)) { if (fullModel.hasDefined(Constants.MIME_MAPPING)) {
Expand Down Expand Up @@ -131,7 +131,8 @@ public void installRuntimeServices(OperationContext context, ModelNode model, St
ignoreFlush, ignoreFlush,
eagerFilterInit, eagerFilterInit,
sessionTimeout, sessionTimeout,
disableCachingForSecuredPages, info != null, info != null && info.isDispatchToWorker(), disableCachingForSecuredPages, webSocketInfo != null, webSocketInfo != null && webSocketInfo.isDispatchToWorker(),
webSocketInfo != null && webSocketInfo.isPerMessageDeflate(), webSocketInfo == null ? -1 : webSocketInfo.getDeflaterLevel(),
mimeMappings, mimeMappings,
welcomeFiles, directoryListingEnabled, proactiveAuth, sessionIdLength, authenticationMechanisms, maxSessions, crawlerSessionManagerConfig, disableFileWatchService); welcomeFiles, directoryListingEnabled, proactiveAuth, sessionIdLength, authenticationMechanisms, maxSessions, crawlerSessionManagerConfig, disableFileWatchService);


Expand All @@ -143,9 +144,9 @@ public void installRuntimeServices(OperationContext context, ModelNode model, St
if(persistentSessions) { if(persistentSessions) {
builder.addDependency(AbstractPersistentSessionManager.SERVICE_NAME, SessionPersistenceManager.class, container.getSessionPersistenceManagerInjectedValue()); builder.addDependency(AbstractPersistentSessionManager.SERVICE_NAME, SessionPersistenceManager.class, container.getSessionPersistenceManagerInjectedValue());
} }
if(info != null) { if(webSocketInfo != null) {
builder.addDependency(IOServices.WORKER.append(info.getWorker()), XnioWorker.class, container.getWebsocketsWorker()); builder.addDependency(IOServices.WORKER.append(webSocketInfo.getWorker()), XnioWorker.class, container.getWebsocketsWorker());
builder.addDependency(IOServices.BUFFER_POOL.append(info.getBufferPool()), Pool.class, (InjectedValue) container.getWebsocketsBufferPool()); builder.addDependency(IOServices.BUFFER_POOL.append(webSocketInfo.getBufferPool()), Pool.class, (InjectedValue) container.getWebsocketsBufferPool());
} }


builder.setInitialMode(ServiceController.Mode.ON_DEMAND) builder.setInitialMode(ServiceController.Mode.ON_DEMAND)
Expand Down
Expand Up @@ -72,6 +72,9 @@ public class ServletContainerService implements Service<ServletContainerService>
private final InjectedValue<Pool<ByteBuffer>> websocketsBufferPool = new InjectedValue<>(); private final InjectedValue<Pool<ByteBuffer>> websocketsBufferPool = new InjectedValue<>();
private final InjectedValue<XnioWorker> websocketsWorker = new InjectedValue<>(); private final InjectedValue<XnioWorker> websocketsWorker = new InjectedValue<>();
private final boolean dispatchWebsocketInvocationToWorker; private final boolean dispatchWebsocketInvocationToWorker;
private final boolean perMessageDeflate;
private final int deflaterLevel;

private final Map<String, String> mimeMappings; private final Map<String, String> mimeMappings;
private final List<String> welcomeFiles; private final List<String> welcomeFiles;
private final boolean proactiveAuth; private final boolean proactiveAuth;
Expand All @@ -81,8 +84,11 @@ public class ServletContainerService implements Service<ServletContainerService>


public ServletContainerService(boolean allowNonStandardWrappers, ServletStackTraces stackTraces, SessionCookieConfig sessionCookieConfig, JSPConfig jspConfig, public ServletContainerService(boolean allowNonStandardWrappers, ServletStackTraces stackTraces, SessionCookieConfig sessionCookieConfig, JSPConfig jspConfig,
String defaultEncoding, boolean useListenerEncoding, boolean ignoreFlush, boolean eagerFilterInit, int defaultSessionTimeout, String defaultEncoding, boolean useListenerEncoding, boolean ignoreFlush, boolean eagerFilterInit, int defaultSessionTimeout,
boolean disableCachingForSecuredPages, boolean websocketsEnabled, boolean dispatchWebsocketInvocationToWorker, Map<String, String> mimeMappings, boolean disableCachingForSecuredPages, boolean websocketsEnabled, boolean dispatchWebsocketInvocationToWorker, boolean perMessageDeflate,
List<String> welcomeFiles, Boolean directoryListingEnabled, boolean proactiveAuth, int sessionIdLength, Map<String, AuthenticationMechanismFactory> authenticationMechanisms, Integer maxSessions, CrawlerSessionManagerConfig crawlerSessionManagerConfig, boolean disableFileWatchService) { int deflaterLevel, Map<String, String> mimeMappings, List<String> welcomeFiles, Boolean directoryListingEnabled, boolean proactiveAuth,
int sessionIdLength, Map<String, AuthenticationMechanismFactory> authenticationMechanisms, Integer maxSessions,
CrawlerSessionManagerConfig crawlerSessionManagerConfig, boolean disableFileWatchService) {

this.allowNonStandardWrappers = allowNonStandardWrappers; this.allowNonStandardWrappers = allowNonStandardWrappers;
this.stackTraces = stackTraces; this.stackTraces = stackTraces;
this.sessionCookieConfig = sessionCookieConfig; this.sessionCookieConfig = sessionCookieConfig;
Expand All @@ -95,6 +101,8 @@ public ServletContainerService(boolean allowNonStandardWrappers, ServletStackTra
this.disableCachingForSecuredPages = disableCachingForSecuredPages; this.disableCachingForSecuredPages = disableCachingForSecuredPages;
this.websocketsEnabled = websocketsEnabled; this.websocketsEnabled = websocketsEnabled;
this.dispatchWebsocketInvocationToWorker = dispatchWebsocketInvocationToWorker; this.dispatchWebsocketInvocationToWorker = dispatchWebsocketInvocationToWorker;
this.perMessageDeflate = perMessageDeflate;
this.deflaterLevel = deflaterLevel;
this.directoryListingEnabled = directoryListingEnabled; this.directoryListingEnabled = directoryListingEnabled;
this.proactiveAuth = proactiveAuth; this.proactiveAuth = proactiveAuth;
this.maxSessions = maxSessions; this.maxSessions = maxSessions;
Expand Down Expand Up @@ -169,6 +177,14 @@ public InjectedValue<Pool<ByteBuffer>> getWebsocketsBufferPool() {
return websocketsBufferPool; return websocketsBufferPool;
} }


public boolean isPerMessageDeflate() {
return perMessageDeflate;
}

public int getDeflaterLevel() {
return deflaterLevel;
}

public boolean isWebsocketsEnabled() { public boolean isWebsocketsEnabled() {
return websocketsEnabled; return websocketsEnabled;
} }
Expand Down
Expand Up @@ -141,6 +141,11 @@ private static void registerTransformers_EAP_7_0_0(SubsystemRegistration subsyst
builder.addChildResource(UndertowExtension.PATH_SERVLET_CONTAINER) builder.addChildResource(UndertowExtension.PATH_SERVLET_CONTAINER)
.getAttributeBuilder() .getAttributeBuilder()
.addRejectCheck(RejectAttributeChecker.DEFINED, Constants.DISABLE_FILE_WATCH_SERVICE) .addRejectCheck(RejectAttributeChecker.DEFINED, Constants.DISABLE_FILE_WATCH_SERVICE)
.end()
.addChildResource(UndertowExtension.PATH_WEBSOCKETS)
.getAttributeBuilder()
.setDiscard(new DiscardAttributeChecker.DiscardAttributeValueChecker(new ModelNode(false)), Constants.PER_MESSAGE_DEFLATE)
.addRejectCheck(RejectAttributeChecker.DEFINED, Constants.PER_MESSAGE_DEFLATE, Constants.DEFLATER_LEVEL)
.end(); .end();


builder.addChildResource(UndertowExtension.PATH_FILTERS) builder.addChildResource(UndertowExtension.PATH_FILTERS)
Expand Down
Expand Up @@ -204,7 +204,9 @@ public class UndertowSubsystemParser_4_0 extends PersistentResourceXMLParser {
.addAttributes( .addAttributes(
WebsocketsDefinition.WORKER, WebsocketsDefinition.WORKER,
WebsocketsDefinition.BUFFER_POOL, WebsocketsDefinition.BUFFER_POOL,
WebsocketsDefinition.DISPATCH_TO_WORKER WebsocketsDefinition.DISPATCH_TO_WORKER,
WebsocketsDefinition.PER_MESSAGE_DEFLATE,
WebsocketsDefinition.DEFLATER_LEVEL
) )
) )
.addChild(builder(MimeMappingDefinition.INSTANCE) .addChild(builder(MimeMappingDefinition.INSTANCE)
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.jboss.as.controller.RestartParentResourceRemoveHandler; import org.jboss.as.controller.RestartParentResourceRemoveHandler;
import org.jboss.as.controller.SimpleAttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.operations.validation.IntRangeValidator;
import org.jboss.as.controller.registry.AttributeAccess; import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType; import org.jboss.dmr.ModelType;
Expand Down Expand Up @@ -68,10 +69,27 @@ class WebsocketsDefinition extends PersistentResourceDefinition {
.setDefaultValue(new ModelNode(true)) .setDefaultValue(new ModelNode(true))
.build(); .build();


protected static final SimpleAttributeDefinition PER_MESSAGE_DEFLATE =
new SimpleAttributeDefinitionBuilder("per-message-deflate", ModelType.BOOLEAN, true)
.setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES)
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();

protected static final SimpleAttributeDefinition DEFLATER_LEVEL =
new SimpleAttributeDefinitionBuilder("deflater-level", ModelType.INT, true)
.setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES)
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0, 9, true, true))
.setDefaultValue(new ModelNode(0))
.build();

protected static final SimpleAttributeDefinition[] ATTRIBUTES = { protected static final SimpleAttributeDefinition[] ATTRIBUTES = {
BUFFER_POOL, BUFFER_POOL,
WORKER, WORKER,
DISPATCH_TO_WORKER DISPATCH_TO_WORKER,
PER_MESSAGE_DEFLATE,
DEFLATER_LEVEL
}; };
static final Map<String, AttributeDefinition> ATTRIBUTES_MAP = new HashMap<>(); static final Map<String, AttributeDefinition> ATTRIBUTES_MAP = new HashMap<>();


Expand Down Expand Up @@ -101,8 +119,10 @@ public WebSocketInfo getConfig(final OperationContext context, final ModelNode m
boolean dispatchToWorker = DISPATCH_TO_WORKER.resolveModelAttribute(context, model).asBoolean(); boolean dispatchToWorker = DISPATCH_TO_WORKER.resolveModelAttribute(context, model).asBoolean();
String bufferPool = BUFFER_POOL.resolveModelAttribute(context, model).asString(); String bufferPool = BUFFER_POOL.resolveModelAttribute(context, model).asString();
String worker = WORKER.resolveModelAttribute(context, model).asString(); String worker = WORKER.resolveModelAttribute(context, model).asString();
boolean perMessageDeflate = PER_MESSAGE_DEFLATE.resolveModelAttribute(context, model).asBoolean();
int deflaterLevel = DEFLATER_LEVEL.resolveModelAttribute(context, model).asInt();


return new WebSocketInfo(worker, bufferPool, dispatchToWorker); return new WebSocketInfo(worker, bufferPool, dispatchToWorker, perMessageDeflate, deflaterLevel);
} }


private static class WebsocketsAdd extends RestartParentResourceAddHandler { private static class WebsocketsAdd extends RestartParentResourceAddHandler {
Expand Down Expand Up @@ -149,12 +169,16 @@ public static class WebSocketInfo {
private final String worker; private final String worker;
private final String bufferPool; private final String bufferPool;
private final boolean dispatchToWorker; private final boolean dispatchToWorker;
private final boolean perMessageDeflate;
private final int deflaterLevel;



public WebSocketInfo(String worker, String bufferPool, boolean dispatchToWorker, boolean perMessageDeflate,
public WebSocketInfo(String worker, String bufferPool, boolean dispatchToWorker) { int deflaterLevel) {
this.worker = worker; this.worker = worker;
this.bufferPool = bufferPool; this.bufferPool = bufferPool;
this.dispatchToWorker = dispatchToWorker; this.dispatchToWorker = dispatchToWorker;
this.perMessageDeflate = perMessageDeflate;
this.deflaterLevel = deflaterLevel;
} }


public String getWorker() { public String getWorker() {
Expand All @@ -168,5 +192,13 @@ public String getBufferPool() {
public boolean isDispatchToWorker() { public boolean isDispatchToWorker() {
return dispatchToWorker; return dispatchToWorker;
} }

public boolean isPerMessageDeflate() {
return perMessageDeflate;
}

public int getDeflaterLevel() {
return deflaterLevel;
}
} }
} }
Expand Up @@ -157,7 +157,6 @@
import org.wildfly.extension.undertow.security.jaspi.JASPICSecurityContextFactory; import org.wildfly.extension.undertow.security.jaspi.JASPICSecurityContextFactory;
import org.wildfly.extension.undertow.session.CodecSessionConfigWrapper; import org.wildfly.extension.undertow.session.CodecSessionConfigWrapper;
import org.wildfly.extension.undertow.session.SharedSessionManagerConfig; import org.wildfly.extension.undertow.session.SharedSessionManagerConfig;
import org.wildfly.security.manager.WildFlySecurityManager;
import org.xnio.IoUtils; import org.xnio.IoUtils;


import javax.servlet.Filter; import javax.servlet.Filter;
Expand Down Expand Up @@ -995,12 +994,9 @@ private DeploymentInfo createServletConfig() throws StartException {
webSocketDeploymentInfo.setWorker(servletContainer.getWebsocketsWorker().getValue()); webSocketDeploymentInfo.setWorker(servletContainer.getWebsocketsWorker().getValue());
webSocketDeploymentInfo.setDispatchToWorkerThread(servletContainer.isDispatchWebsocketInvocationToWorker()); webSocketDeploymentInfo.setDispatchToWorkerThread(servletContainer.isDispatchWebsocketInvocationToWorker());


// Enables per-message deflate compression. This fixes JBEAP-5076. if(servletContainer.isPerMessageDeflate()) {
// This is controlled by the system property "io.undertow.websockets.PER_MESSAGE_DEFLATE" PerMessageDeflateHandshake perMessageDeflate = new PerMessageDeflateHandshake(false, servletContainer.getDeflaterLevel());
boolean enablePerMessageDeflate = Boolean.parseBoolean( webSocketDeploymentInfo.addExtension(perMessageDeflate);
WildFlySecurityManager.getPropertyPrivileged("io.undertow.websockets.PER_MESSAGE_DEFLATE", "false"));
if (enablePerMessageDeflate) {
webSocketDeploymentInfo.addExtension(new PerMessageDeflateHandshake(false));
} }


final AtomicReference<ServerActivity> serverActivity = new AtomicReference<>(); final AtomicReference<ServerActivity> serverActivity = new AtomicReference<>();
Expand Down
Expand Up @@ -244,6 +244,8 @@ undertow.setting.websockets.remove=Removes websockets support
undertow.setting.websockets.dispatch-to-worker=If callbacks should be dispatched to a worker thread. If this is false then they will be run in the IO thread, which is faster however care must be taken not to perform blocking operations. undertow.setting.websockets.dispatch-to-worker=If callbacks should be dispatched to a worker thread. If this is false then they will be run in the IO thread, which is faster however care must be taken not to perform blocking operations.
undertow.setting.websockets.worker=The worker to use for websocket deployments undertow.setting.websockets.worker=The worker to use for websocket deployments
undertow.setting.websockets.buffer-pool=The buffer pool to use for websocket deployments undertow.setting.websockets.buffer-pool=The buffer pool to use for websocket deployments
undertow.setting.websockets.per-message-deflate=Enables websocket's per-message compression extension, RFC-7692
undertow.setting.websockets.deflater-level=Configures the level of compression of the DEFLATE algorithm
undertow.setting.crawler-session-management=Configures special session handing for crawler bots undertow.setting.crawler-session-management=Configures special session handing for crawler bots
undertow.setting.crawler-session-management.add=Adds special session handing for crawler bots undertow.setting.crawler-session-management.add=Adds special session handing for crawler bots
undertow.setting.crawler-session-management.remove=Removes special session handing for crawler bots undertow.setting.crawler-session-management.remove=Removes special session handing for crawler bots
Expand Down
2 changes: 2 additions & 0 deletions undertow/src/main/resources/schema/wildfly-undertow_4_0.xsd
Expand Up @@ -311,6 +311,8 @@
<xs:attribute name="worker" use="optional" type="xs:string" default="default"/> <xs:attribute name="worker" use="optional" type="xs:string" default="default"/>
<xs:attribute name="buffer-pool" use="optional" type="xs:string" default="default"/> <xs:attribute name="buffer-pool" use="optional" type="xs:string" default="default"/>
<xs:attribute name="dispatch-to-worker" use="optional" type="xs:boolean" default="true"/> <xs:attribute name="dispatch-to-worker" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="per-message-deflate" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="deflater-level" use="optional" type="xs:int"/>
</xs:complexType> </xs:complexType>


<xs:complexType name="crawler-session-managementType"> <xs:complexType name="crawler-session-managementType">
Expand Down
Expand Up @@ -100,6 +100,11 @@ protected Properties getResolvedProperties() {
return properties; return properties;
} }


@Override
protected KernelServices standardSubsystemTest(String configId, boolean compareXml) throws Exception {
return super.standardSubsystemTest(configId, false);
}

@Test @Test
public void testRuntime() throws Exception { public void testRuntime() throws Exception {
setProperty(); setProperty();
Expand Down
Expand Up @@ -89,7 +89,7 @@
http-only="true" http-only="true"
max-age="1000"/> max-age="1000"/>
<!--<persistent-sessions relative-to="${server.data.dir}" path="web-sessions"/>--> <!--<persistent-sessions relative-to="${server.data.dir}" path="web-sessions"/>-->
<websockets dispatch-to-worker="false" /> <websockets dispatch-to-worker="false" per-message-deflate="false" deflater-level="0" />
<mime-mappings> <mime-mappings>
<mime-mapping name="txt" value="text/plain" /> <mime-mapping name="txt" value="text/plain" />
</mime-mappings> </mime-mappings>
Expand Down

0 comments on commit a59f2df

Please sign in to comment.