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 authored and stuartwdouglas committed Sep 30, 2016
1 parent 64fd0f5 commit 0f399e2
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 DEFAULT_SECURITY_DOMAIN = "default-security-domain";
String DISABLE_FILE_WATCH_SERVICE = "disable-file-watch-service";
String PER_MESSAGE_DEFLATE = "per-message-deflate";
String DEFLATER_LEVEL = "deflater-level";

// Elytron Integration
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();

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<>();
if (fullModel.hasDefined(Constants.MIME_MAPPING)) {
Expand Down Expand Up @@ -131,7 +131,8 @@ public void installRuntimeServices(OperationContext context, ModelNode model, St
ignoreFlush,
eagerFilterInit,
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,
welcomeFiles, directoryListingEnabled, proactiveAuth, sessionIdLength, authenticationMechanisms, maxSessions, crawlerSessionManagerConfig, disableFileWatchService);

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

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<XnioWorker> websocketsWorker = new InjectedValue<>();
private final boolean dispatchWebsocketInvocationToWorker;
private final boolean perMessageDeflate;
private final int deflaterLevel;

private final Map<String, String> mimeMappings;
private final List<String> welcomeFiles;
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,
String defaultEncoding, boolean useListenerEncoding, boolean ignoreFlush, boolean eagerFilterInit, int defaultSessionTimeout,
boolean disableCachingForSecuredPages, boolean websocketsEnabled, boolean dispatchWebsocketInvocationToWorker, Map<String, String> mimeMappings,
List<String> welcomeFiles, Boolean directoryListingEnabled, boolean proactiveAuth, int sessionIdLength, Map<String, AuthenticationMechanismFactory> authenticationMechanisms, Integer maxSessions, CrawlerSessionManagerConfig crawlerSessionManagerConfig, boolean disableFileWatchService) {
boolean disableCachingForSecuredPages, boolean websocketsEnabled, boolean dispatchWebsocketInvocationToWorker, boolean perMessageDeflate,
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.stackTraces = stackTraces;
this.sessionCookieConfig = sessionCookieConfig;
Expand All @@ -95,6 +101,8 @@ public ServletContainerService(boolean allowNonStandardWrappers, ServletStackTra
this.disableCachingForSecuredPages = disableCachingForSecuredPages;
this.websocketsEnabled = websocketsEnabled;
this.dispatchWebsocketInvocationToWorker = dispatchWebsocketInvocationToWorker;
this.perMessageDeflate = perMessageDeflate;
this.deflaterLevel = deflaterLevel;
this.directoryListingEnabled = directoryListingEnabled;
this.proactiveAuth = proactiveAuth;
this.maxSessions = maxSessions;
Expand Down Expand Up @@ -169,6 +177,14 @@ public InjectedValue<Pool<ByteBuffer>> getWebsocketsBufferPool() {
return websocketsBufferPool;
}

public boolean isPerMessageDeflate() {
return perMessageDeflate;
}

public int getDeflaterLevel() {
return deflaterLevel;
}

public boolean isWebsocketsEnabled() {
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)
.getAttributeBuilder()
.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();

builder.addChildResource(UndertowExtension.PATH_FILTERS)
Expand Down
Expand Up @@ -204,7 +204,9 @@ public class UndertowSubsystemParser_4_0 extends PersistentResourceXMLParser {
.addAttributes(
WebsocketsDefinition.WORKER,
WebsocketsDefinition.BUFFER_POOL,
WebsocketsDefinition.DISPATCH_TO_WORKER
WebsocketsDefinition.DISPATCH_TO_WORKER,
WebsocketsDefinition.PER_MESSAGE_DEFLATE,
WebsocketsDefinition.DEFLATER_LEVEL
)
)
.addChild(builder(MimeMappingDefinition.INSTANCE)
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.jboss.as.controller.RestartParentResourceRemoveHandler;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.operations.validation.IntRangeValidator;
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
Expand Down Expand Up @@ -68,10 +69,27 @@ class WebsocketsDefinition extends PersistentResourceDefinition {
.setDefaultValue(new ModelNode(true))
.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 = {
BUFFER_POOL,
WORKER,
DISPATCH_TO_WORKER
DISPATCH_TO_WORKER,
PER_MESSAGE_DEFLATE,
DEFLATER_LEVEL
};
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();
String bufferPool = BUFFER_POOL.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 {
Expand Down Expand Up @@ -149,12 +169,16 @@ public static class WebSocketInfo {
private final String worker;
private final String bufferPool;
private final boolean dispatchToWorker;
private final boolean perMessageDeflate;
private final int deflaterLevel;


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

public String getWorker() {
Expand All @@ -168,5 +192,13 @@ public String getBufferPool() {
public boolean isDispatchToWorker() {
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.session.CodecSessionConfigWrapper;
import org.wildfly.extension.undertow.session.SharedSessionManagerConfig;
import org.wildfly.security.manager.WildFlySecurityManager;
import org.xnio.IoUtils;

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

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

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.worker=The worker 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.add=Adds 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="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="per-message-deflate" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="deflater-level" use="optional" type="xs:int"/>
</xs:complexType>

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

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

@Test
public void testRuntime() throws Exception {
setProperty();
Expand Down
Expand Up @@ -89,7 +89,7 @@
http-only="true"
max-age="1000"/>
<!--<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-mapping name="txt" value="text/plain" />
</mime-mappings>
Expand Down

0 comments on commit 0f399e2

Please sign in to comment.