Author: remy.maucherat(a)jboss.com
Date: 2014-10-08 14:19:05 -0400 (Wed, 08 Oct 2014)
New Revision: 2522
Modified:
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/Constants.java
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/PerMessageDeflate.java
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/TransformationFactory.java
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsFrameClient.java
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/server/UpgradeUtil.java
branches/7.5.x/src/main/java/org/jboss/web/WebsocketsMessages.java
Log:
Port patch adding client support for deflate.
Modified: branches/7.5.x/src/main/java/org/apache/tomcat/websocket/Constants.java
===================================================================
--- branches/7.5.x/src/main/java/org/apache/tomcat/websocket/Constants.java 2014-10-07
15:34:13 UTC (rev 2521)
+++ branches/7.5.x/src/main/java/org/apache/tomcat/websocket/Constants.java 2014-10-08
18:19:05 UTC (rev 2522)
@@ -61,6 +61,8 @@
WS_PROTOCOL_HEADER_NAME.toLowerCase(Locale.ENGLISH);
public static final String WS_EXTENSIONS_HEADER_NAME =
"Sec-WebSocket-Extensions";
+ public static final String WS_EXTENSIONS_HEADER_NAME_LOWER =
+ WS_EXTENSIONS_HEADER_NAME.toLowerCase(Locale.ENGLISH);
public static final boolean STRICT_SPEC_COMPLIANCE =
Boolean.getBoolean(
Modified: branches/7.5.x/src/main/java/org/apache/tomcat/websocket/PerMessageDeflate.java
===================================================================
---
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/PerMessageDeflate.java 2014-10-07
15:34:13 UTC (rev 2521)
+++
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/PerMessageDeflate.java 2014-10-08
18:19:05 UTC (rev 2522)
@@ -46,6 +46,7 @@
private final int serverMaxWindowBits;
private final boolean clientContextTakeover;
private final int clientMaxWindowBits;
+ private final boolean isServer;
private final Inflater inflater = new Inflater(true);
private final ByteBuffer readBuffer =
ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE);
private final Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
@@ -56,8 +57,8 @@
private volatile ByteBuffer writeBuffer =
ByteBuffer.allocate(Constants.DEFAULT_BUFFER_SIZE);
private volatile boolean firstCompressedFrameWritten = false;
- static PerMessageDeflate negotiate(List<List<Parameter>> preferences) {
- // Accept the first preference that the server is able to support
+ static PerMessageDeflate negotiate(List<List<Parameter>> preferences,
boolean isServer) {
+ // Accept the first preference that the endpoint is able to support
for (List<Parameter> preference : preferences) {
boolean ok = true;
boolean serverContextTakeover = true;
@@ -127,7 +128,7 @@
}
if (ok) {
return new PerMessageDeflate(serverContextTakeover, serverMaxWindowBits,
- clientContextTakeover, clientMaxWindowBits);
+ clientContextTakeover, clientMaxWindowBits, isServer);
}
}
// Failed to negotiate agreeable terms
@@ -136,11 +137,12 @@
private PerMessageDeflate(boolean serverContextTakeover, int serverMaxWindowBits,
- boolean clientContextTakeover, int clientMaxWindowBits) {
+ boolean clientContextTakeover, int clientMaxWindowBits, boolean isServer) {
this.serverContextTakeover = serverContextTakeover;
this.serverMaxWindowBits = serverMaxWindowBits;
this.clientContextTakeover = clientContextTakeover;
this.clientMaxWindowBits = clientMaxWindowBits;
+ this.isServer = isServer;
}
@@ -196,7 +198,8 @@
}
}
} else if (written == 0) {
- if (fin && !serverContextTakeover) {
+ if (fin && (isServer && !serverContextTakeover ||
+ !isServer && !clientContextTakeover)) {
inflater.reset();
}
return TransformationResult.END_OF_FRAME;
@@ -408,7 +411,7 @@
private void startNewMessage() {
firstCompressedFrameWritten = false;
- if (!clientContextTakeover) {
+ if (isServer && !clientContextTakeover || !isServer &&
!serverContextTakeover) {
deflater.reset();
}
}
Modified:
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/TransformationFactory.java
===================================================================
---
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/TransformationFactory.java 2014-10-07
15:34:13 UTC (rev 2521)
+++
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/TransformationFactory.java 2014-10-08
18:19:05 UTC (rev 2522)
@@ -34,9 +34,10 @@
return factory;
}
- public Transformation create(String name, List<List<Extension.Parameter>>
preferences) {
+ public Transformation create(String name, List<List<Extension.Parameter>>
preferences,
+ boolean isServer) {
if (PerMessageDeflate.NAME.equals(name)) {
- return PerMessageDeflate.negotiate(preferences);
+ return PerMessageDeflate.negotiate(preferences, isServer);
}
throw MESSAGES.unsupportedExtension(name);
}
Modified: branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsFrameClient.java
===================================================================
--- branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsFrameClient.java 2014-10-07
15:34:13 UTC (rev 2521)
+++ branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsFrameClient.java 2014-10-08
18:19:05 UTC (rev 2522)
@@ -31,9 +31,8 @@
private ByteBuffer response;
public WsFrameClient(ByteBuffer response, AsyncChannelWrapper channel,
- WsSession wsSession) {
- // TODO Add support for extensions to the client side code
- super(wsSession, null);
+ WsSession wsSession, Transformation transformation) {
+ super(wsSession, transformation);
this.response = response;
this.channel = channel;
this.handler = new WsFrameClientCompletionHandler();
Modified:
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
===================================================================
---
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsWebSocketContainer.java 2014-10-07
15:34:13 UTC (rev 2521)
+++
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/WsWebSocketContainer.java 2014-10-08
18:19:05 UTC (rev 2522)
@@ -272,6 +272,9 @@
ByteBuffer response;
String subProtocol;
boolean success = false;
+ List<Extension> extensionsAgreed = new ArrayList<Extension>();
+ Transformation transformation = null;
+
try {
fConnect.get(timeout, TimeUnit.MILLISECONDS);
@@ -299,15 +302,43 @@
// Sub-protocol
// Header names are always stored in lower case
- List<String> values = handshakeResponse.getHeaders().get(
+ List<String> protocolHeaders = handshakeResponse.getHeaders().get(
Constants.WS_PROTOCOL_HEADER_NAME_LOWER);
- if (values == null || values.size() == 0) {
+ if (protocolHeaders == null || protocolHeaders.size() == 0) {
subProtocol = null;
- } else if (values.size() == 1) {
- subProtocol = values.get(0);
+ } else if (protocolHeaders.size() == 1) {
+ subProtocol = protocolHeaders.get(0);
} else {
throw new DeploymentException(MESSAGES.invalidProtocolHeader());
}
+
+ // Extensions
+ // Should normally only be one header but handle the case of
+ // multiple headers
+ List<String> extHeaders = handshakeResponse.getHeaders().get(
+ Constants.WS_EXTENSIONS_HEADER_NAME_LOWER);
+ if (extHeaders != null) {
+ for (String extHeader : extHeaders) {
+ Util.parseExtensionHeader(extensionsAgreed, extHeader);
+ }
+ }
+
+ // Build the transformations
+ TransformationFactory factory = TransformationFactory.getInstance();
+ for (Extension extension : extensionsAgreed) {
+ List<List<Extension.Parameter>> wrapper = new
ArrayList<List<Extension.Parameter>>(1);
+ wrapper.add(extension.getParameters());
+ Transformation t = factory.create(extension.getName(), wrapper, false);
+ if (t == null) {
+ throw new DeploymentException(MESSAGES.unsupportedParameters());
+ }
+ if (transformation == null) {
+ transformation = t;
+ } else {
+ transformation.setNext(t);
+ }
+ }
+
success = true;
} catch (ExecutionException e) {
throw new DeploymentException(MESSAGES.httpRequestFailed(), e);
@@ -329,12 +360,12 @@
WsRemoteEndpointImplClient wsRemoteEndpointClient = new
WsRemoteEndpointImplClient(channel);
WsSession wsSession = new WsSession(endpoint, wsRemoteEndpointClient,
- this, null, null, null, null, null,
Collections.<Extension>emptyList(),
+ this, null, null, null, null, null, extensionsAgreed,
subProtocol, Collections.<String,String>emptyMap(), secure,
clientEndpointConfiguration);
WsFrameClient wsFrameClient = new WsFrameClient(response, channel,
- wsSession);
+ wsSession, transformation);
// WsFrame adds the necessary final transformations. Copy the
// completed transformation chain to the remote end point.
wsRemoteEndpointClient.setTransformation(wsFrameClient.getTransformation());
@@ -466,6 +497,7 @@
header.append(value);
}
}
+ result.add(header.toString());
}
return result;
}
Modified:
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/server/UpgradeUtil.java
===================================================================
---
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/server/UpgradeUtil.java 2014-10-07
15:34:13 UTC (rev 2521)
+++
branches/7.5.x/src/main/java/org/apache/tomcat/websocket/server/UpgradeUtil.java 2014-10-08
18:19:05 UTC (rev 2522)
@@ -260,7 +260,7 @@
for (Map.Entry<String,List<List<Extension.Parameter>>> entry :
extensionPreferences.entrySet()) {
- Transformation transformation = factory.create(entry.getKey(),
entry.getValue());
+ Transformation transformation = factory.create(entry.getKey(),
entry.getValue(), true);
if (transformation != null) {
result.add(transformation);
}
Modified: branches/7.5.x/src/main/java/org/jboss/web/WebsocketsMessages.java
===================================================================
--- branches/7.5.x/src/main/java/org/jboss/web/WebsocketsMessages.java 2014-10-07 15:34:13
UTC (rev 2521)
+++ branches/7.5.x/src/main/java/org/jboss/web/WebsocketsMessages.java 2014-10-08 18:19:05
UTC (rev 2522)
@@ -332,4 +332,7 @@
@Message(id = 8598, value = "Invalid token value %s")
IllegalArgumentException invalidTokenValue(String value);
+ @Message(id = 8599, value = "Client requested parameters it could not
support")
+ String unsupportedParameters();
+
}