You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2023/07/24 14:26:49 UTC

[tomcat] branch 10.1.x updated: Fix BZ 66681 - NPE on batch flush when permessage-deflate enabled

This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/10.1.x by this push:
     new 978ff4af95 Fix BZ 66681 - NPE on batch flush when permessage-deflate enabled
978ff4af95 is described below

commit 978ff4af95a78ba06208e387c6613008627f3c66
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Jul 24 15:26:24 2023 +0100

    Fix BZ 66681 - NPE on batch flush when permessage-deflate enabled
    
    https://bz.apache.org/bugzilla/show_bug.cgi?id=66681
---
 .../apache/tomcat/websocket/PerMessageDeflate.java | 11 +++--
 .../tomcat/websocket/TestPerMessageDeflate.java    | 49 ++++++++++++++++++++++
 webapps/docs/changelog.xml                         |  9 ++++
 3 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/java/org/apache/tomcat/websocket/PerMessageDeflate.java b/java/org/apache/tomcat/websocket/PerMessageDeflate.java
index 665cfd24f4..6e6797d812 100644
--- a/java/org/apache/tomcat/websocket/PerMessageDeflate.java
+++ b/java/org/apache/tomcat/websocket/PerMessageDeflate.java
@@ -314,13 +314,16 @@ public class PerMessageDeflate implements Transformation {
 
         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
+                // and must not be compressed. Pass it straight through.
                 allCompressedParts.add(uncompressedPart);
-            } else if (emptyMessage && uncompressedPart.isFin()) {
+                continue;
+            }
+
+            boolean emptyPart = uncompressedPart.getPayload().limit() == 0;
+            emptyMessage = emptyMessage && emptyPart;
+            if (emptyMessage && uncompressedPart.isFin()) {
                 // Zero length messages can't be compressed so pass the
                 // final (empty) part straight through.
                 allCompressedParts.add(uncompressedPart);
diff --git a/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java b/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
index a8301c8277..51f3b31e28 100644
--- a/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
+++ b/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
@@ -101,6 +101,55 @@ public class TestPerMessageDeflate {
     }
 
 
+    /*
+     * https://bz.apache.org/bugzilla/show_bug.cgi?id=66681
+     */
+    @Test
+    public void testFlushBatchMessagePart() throws IOException {
+        // Set up the extension using defaults
+        List<Parameter> parameters = Collections.emptyList();
+        List<List<Parameter>> preferences = new ArrayList<>();
+        preferences.add(parameters);
+
+        // Set up the compression and sending of the message.
+        PerMessageDeflate perMessageDeflateTx = PerMessageDeflate.negotiate(preferences, true);
+        perMessageDeflateTx.setNext(new TesterTransformation());
+
+        List<MessagePart> uncompressedParts = new ArrayList<>();
+
+        // First message part
+        byte[] data = new byte[1024];
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        MessagePart mp1 = new MessagePart(true, 0, Constants.OPCODE_BINARY, bb, null, null, -1);
+        uncompressedParts.add(mp1);
+
+        // Flush message (replicates result of calling flushBatch()
+        MessagePart mp2 = new MessagePart(true, 0, Constants.INTERNAL_OPCODE_FLUSH, null, null, null, -1);
+        uncompressedParts.add(mp2);
+
+        List<MessagePart> compressedParts = perMessageDeflateTx.sendMessagePart(uncompressedParts);
+
+        Assert.assertEquals(2,  compressedParts.size());
+
+        // Check the first compressed part
+        MessagePart compressedPart1 = compressedParts.get(0);
+
+        // Set up the decompression and process the received message
+        PerMessageDeflate perMessageDeflateRx = PerMessageDeflate.negotiate(preferences, true);
+        perMessageDeflateRx.setNext(new TesterTransformation(compressedPart1.getPayload()));
+
+        ByteBuffer received = ByteBuffer.allocate(8192);
+
+        TransformationResult tr = perMessageDeflateRx.getMoreData(compressedPart1.getOpCode(), compressedPart1.isFin(),
+                compressedPart1.getRsv(), received);
+
+        Assert.assertEquals(1024, received.position());
+        Assert.assertEquals(TransformationResult.END_OF_FRAME, tr);
+
+        // Check the second compressed part (should be passed through unchanged)
+        Assert.assertEquals(mp2, compressedParts.get(1));
+    }
+
     /*
      * Minimal implementation to enable other transformations to be tested. It is NOT robust.
      */
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3a9a5e18b7..460ea09733 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -124,6 +124,15 @@
       </fix>
     </changelog>
   </subsection>
+  <subsection name="WebSocket">
+    <changelog>
+      <fix>
+        <bug>66681</bug>: Fix a <code>NullPointerException</code> when flushing
+        batched messages with compression enabled using
+        <code>permessage-deflate</code>. (markt)
+      </fix>
+    </changelog>
+  </subsection>
 </section>
 <section name="Tomcat 10.1.11 (schultz)" rtext="Released 2023-07-10">
   <subsection name="Catalina">


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