Skip to content

Commit ce28e70

Browse files
committed
PermessageDeflate should handle uncompressed messages
Fixes TooTallNate#1164
1 parent 14fa2ad commit ce28e70

File tree

3 files changed

+73
-8
lines changed

3 files changed

+73
-8
lines changed

src/main/java/org/java_websocket/extensions/permessage_deflate/PerMessageDeflateExtension.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ public class PerMessageDeflateExtension extends CompressionExtension {
4444
private static final byte[] TAIL_BYTES = {(byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF};
4545
private static final int BUFFER_SIZE = 1 << 10;
4646

47+
private int threshold = 1024;
48+
4749
private boolean serverNoContextTakeover = true;
4850
private boolean clientNoContextTakeover = false;
4951

@@ -70,6 +72,24 @@ public void setDeflater(Deflater deflater) {
7072
this.deflater = deflater;
7173
}
7274

75+
/**
76+
* Get the size threshold for doing the compression
77+
* @return Size (in bytes) below which messages will not be compressed
78+
* @since 1.5.3
79+
*/
80+
public int getThreshold() {
81+
return threshold;
82+
}
83+
84+
/**
85+
* Set the size when payloads smaller than this will not be compressed.
86+
* @param threshold the size in bytes
87+
* @since 1.5.3
88+
*/
89+
public void setThreshold(int threshold) {
90+
this.threshold = threshold;
91+
}
92+
7393
/**
7494
* Access the "server_no_context_takeover" extension parameter
7595
*
@@ -127,6 +147,10 @@ public void decodeFrame(Framedata inputFrame) throws InvalidDataException {
127147
throw new InvalidDataException(CloseFrame.POLICY_VALIDATION,
128148
"RSV1 bit can only be set for the first frame.");
129149
}
150+
// If rsv1 is not set, we dont have a compressed message
151+
if (!inputFrame.isRSV1()) {
152+
return;
153+
}
130154

131155
// Decompressed output buffer.
132156
ByteArrayOutputStream output = new ByteArrayOutputStream();
@@ -190,12 +214,16 @@ public void encodeFrame(Framedata inputFrame) {
190214
return;
191215
}
192216

217+
byte[] payloadData = inputFrame.getPayloadData().array();
218+
if (payloadData.length < threshold) {
219+
return;
220+
}
193221
// Only the first frame's RSV1 must be set.
194222
if (!(inputFrame instanceof ContinuousFrame)) {
195223
((DataFrame) inputFrame).setRSV1(true);
196224
}
197225

198-
deflater.setInput(inputFrame.getPayloadData().array());
226+
deflater.setInput(payloadData);
199227
// Compressed output buffer.
200228
ByteArrayOutputStream output = new ByteArrayOutputStream();
201229
// Temporary buffer to hold compressed output.
@@ -316,10 +344,6 @@ public IExtension copyInstance() {
316344
*/
317345
@Override
318346
public void isFrameValid(Framedata inputFrame) throws InvalidDataException {
319-
if ((inputFrame instanceof TextFrame || inputFrame instanceof BinaryFrame) && !inputFrame
320-
.isRSV1()) {
321-
throw new InvalidFrameException("RSV1 bit must be set for DataFrames.");
322-
}
323347
if ((inputFrame instanceof ContinuousFrame) && (inputFrame.isRSV1() || inputFrame.isRSV2()
324348
|| inputFrame.isRSV3())) {
325349
throw new InvalidFrameException(
@@ -333,4 +357,6 @@ public void isFrameValid(Framedata inputFrame) throws InvalidDataException {
333357
public String toString() {
334358
return "PerMessageDeflateExtension";
335359
}
360+
361+
336362
}

src/test/java/org/java_websocket/example/AutobahnServerTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,10 @@ public static void main(String[] args) throws UnknownHostException {
101101
System.out.println("No limit specified. Defaulting to MaxInteger");
102102
limit = Integer.MAX_VALUE;
103103
}
104+
PerMessageDeflateExtension perMessageDeflateExtension = new PerMessageDeflateExtension();
105+
perMessageDeflateExtension.setThreshold(0);
104106
AutobahnServerTest test = new AutobahnServerTest(port, limit,
105-
new Draft_6455(new PerMessageDeflateExtension()));
107+
new Draft_6455(perMessageDeflateExtension));
106108
test.setConnectionLostTimeout(0);
107109
test.start();
108110
}

src/test/java/org/java_websocket/extensions/PerMessageDeflateExtensionTest.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.zip.Inflater;
1212
import org.java_websocket.exceptions.InvalidDataException;
1313
import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
14+
import org.java_websocket.framing.BinaryFrame;
1415
import org.java_websocket.framing.ContinuousFrame;
1516
import org.java_websocket.framing.TextFrame;
1617
import org.junit.Test;
@@ -20,6 +21,7 @@ public class PerMessageDeflateExtensionTest {
2021
@Test
2122
public void testDecodeFrame() throws InvalidDataException {
2223
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
24+
deflateExtension.setThreshold(0);
2325
String str = "This is a highly compressable text"
2426
+ "This is a highly compressable text"
2527
+ "This is a highly compressable text"
@@ -29,13 +31,30 @@ public void testDecodeFrame() throws InvalidDataException {
2931
TextFrame frame = new TextFrame();
3032
frame.setPayload(ByteBuffer.wrap(message));
3133
deflateExtension.encodeFrame(frame);
34+
assertTrue(frame.isRSV1());
3235
deflateExtension.decodeFrame(frame);
3336
assertArrayEquals(message, frame.getPayloadData().array());
3437
}
38+
@Test
39+
public void testDecodeFrameIfRSVIsNotSet() throws InvalidDataException {
40+
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
41+
String str = "This is a highly compressable text"
42+
+ "This is a highly compressable text"
43+
+ "This is a highly compressable text"
44+
+ "This is a highly compressable text"
45+
+ "This is a highly compressable text";
46+
byte[] message = str.getBytes();
47+
TextFrame frame = new TextFrame();
48+
frame.setPayload(ByteBuffer.wrap(message));
49+
deflateExtension.decodeFrame(frame);
50+
assertArrayEquals(message, frame.getPayloadData().array());
51+
assertFalse(frame.isRSV1());
52+
}
3553

3654
@Test
3755
public void testEncodeFrame() {
3856
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
57+
deflateExtension.setThreshold(0);
3958
String str = "This is a highly compressable text"
4059
+ "This is a highly compressable text"
4160
+ "This is a highly compressable text"
@@ -47,6 +66,25 @@ public void testEncodeFrame() {
4766
deflateExtension.encodeFrame(frame);
4867
assertTrue(message.length > frame.getPayloadData().array().length);
4968
}
69+
@Test
70+
public void testEncodeFrameBelowThreshold() {
71+
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
72+
deflateExtension.setThreshold(11);
73+
String str = "Hello World";
74+
byte[] message = str.getBytes();
75+
TextFrame frame = new TextFrame();
76+
frame.setPayload(ByteBuffer.wrap(message));
77+
deflateExtension.encodeFrame(frame);
78+
// Message length is equal to the threshold --> encode
79+
assertTrue(frame.isRSV1());
80+
str = "Hello Worl";
81+
message = str.getBytes();
82+
frame = new TextFrame();
83+
frame.setPayload(ByteBuffer.wrap(message));
84+
deflateExtension.encodeFrame(frame);
85+
// Message length is below to the threshold --> do NOT encode
86+
assertFalse(frame.isRSV1());
87+
}
5088

5189
@Test
5290
public void testAcceptProvidedExtensionAsServer() {
@@ -72,9 +110,8 @@ public void testIsFrameValid() {
72110
TextFrame frame = new TextFrame();
73111
try {
74112
deflateExtension.isFrameValid(frame);
75-
fail("Frame not valid. RSV1 must be set.");
76113
} catch (Exception e) {
77-
//
114+
fail("RSV1 is optional and should therefore not fail");
78115
}
79116
frame.setRSV1(true);
80117
try {

0 commit comments

Comments
 (0)