Author: markt
Date: Fri Sep  8 08:50:30 2017
New Revision: 1807686

URL: http://svn.apache.org/viewvc?rev=1807686&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=61491
When using the permessage-deflate extension, correctly handle the sending of 
empty messages after non-empty messages to avoid the IllegalArgumentException

Added:
    tomcat/trunk/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java   
(with props)
Modified:
    tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java?rev=1807686&r1=1807685&r2=1807686&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java 
(original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java Fri 
Sep  8 08:50:30 2017
@@ -315,16 +315,20 @@ public class PerMessageDeflate implement
     public List<MessagePart> sendMessagePart(List<MessagePart> 
uncompressedParts) {
         List<MessagePart> allCompressedParts = new ArrayList<>();
 
+        // Flag to track if a message is completely empty
+        boolean emptyMessage = true;
+
         for (MessagePart uncompressedPart : uncompressedParts) {
             byte opCode = uncompressedPart.getOpCode();
+            boolean emptyPart = uncompressedPart.getPayload().limit() == 0;
+            emptyMessage = emptyMessage && emptyPart;
             if (Util.isControl(opCode)) {
                 // Control messages can appear in the middle of other messages
                 // and must not be compressed. Pass it straight through
                 allCompressedParts.add(uncompressedPart);
-            } else if (uncompressedPart.getPayload().limit() == 0 && 
uncompressedPart.isFin() &&
-                    deflater.getBytesRead() == 0) {
-                // Zero length messages can't be compressed so pass them
-                // straight through.
+            } else if (emptyMessage && uncompressedPart.isFin()) {
+                // Zero length messages can't be compressed so pass the
+                // final (empty) part straight through.
                 allCompressedParts.add(uncompressedPart);
             } else {
                 List<MessagePart> compressedParts = new ArrayList<>();

Added: tomcat/trunk/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java?rev=1807686&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java 
(added)
+++ tomcat/trunk/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java 
Fri Sep  8 08:50:30 2017
@@ -0,0 +1,95 @@
+/*
+ * 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.tomcat.websocket;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.websocket.Extension;
+import javax.websocket.Extension.Parameter;
+
+import org.junit.Test;
+
+public class TestPerMessageDeflate {
+
+    /*
+     * https://bz.apache.org/bugzilla/show_bug.cgi?id=61491
+     */
+    @Test
+    public void testSendEmptyMessagePartWithContextTakeover() {
+
+        // Set up the extension using defaults
+        List<Parameter> parameters = Collections.emptyList();
+        List<List<Parameter>> preferences = new ArrayList<>();
+        preferences.add(parameters);
+
+        PerMessageDeflate perMessageDeflate = 
PerMessageDeflate.negotiate(preferences, true);
+        perMessageDeflate.setNext(new TesterTransformation());
+
+        ByteBuffer bb1 = ByteBuffer.wrap("A".getBytes(StandardCharsets.UTF_8));
+        MessagePart mp1 = new MessagePart(true, 0, Constants.OPCODE_TEXT, bb1, 
null, null, -1);
+
+        List<MessagePart> uncompressedParts1 = new ArrayList<>();
+        uncompressedParts1.add(mp1);
+        perMessageDeflate.sendMessagePart(uncompressedParts1);
+
+        ByteBuffer bb2 = ByteBuffer.wrap("".getBytes(StandardCharsets.UTF_8));
+        MessagePart mp2 = new MessagePart(true, 0, Constants.OPCODE_TEXT, bb2, 
null, null, -1);
+
+        List<MessagePart> uncompressedParts2 = new ArrayList<>();
+        uncompressedParts2.add(mp2);
+        perMessageDeflate.sendMessagePart(uncompressedParts2);
+    }
+
+
+    /*
+     * Minimal implementation to enable other transformations to be tested.
+     */
+    private static class TesterTransformation implements Transformation {
+        @Override
+        public boolean validateRsvBits(int i) {
+            return false;
+        }
+        @Override
+        public boolean validateRsv(int rsv, byte opCode) {
+            return false;
+        }
+        @Override
+        public void setNext(Transformation t) {
+        }
+        @Override
+        public List<MessagePart> sendMessagePart(List<MessagePart> 
messageParts) {
+            return messageParts;
+        }
+        @Override
+        public TransformationResult getMoreData(byte opCode, boolean fin, int 
rsv, ByteBuffer dest)
+                throws IOException {
+            return null;
+        }
+        @Override
+        public Extension getExtensionResponse() {
+            return null;
+        }
+        @Override
+        public void close() {
+        }
+    }
+}

Propchange: 
tomcat/trunk/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1807686&r1=1807685&r2=1807686&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Sep  8 08:50:30 2017
@@ -174,6 +174,12 @@
         messages by not flushing between the header and the payload when the
         two are written together. (markt)
       </fix>
+      <fix>
+        <bug>61491</bug>: When using the <code>permessage-deflate</code>
+        extension, correctly handle the sending of empty messages after
+        non-empty messages to avoid the <code>IllegalArgumentException</code>.
+        (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Web applications">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to