Skip to content

Commit 3b29042

Browse files
authored
Merge pull request #1439 from marci4/fix/Issue1437
Clone PerMessageDeflateExtension values correctly
2 parents c4bf44e + dfca00b commit 3b29042

File tree

2 files changed

+141
-43
lines changed

2 files changed

+141
-43
lines changed

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

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@
1313
import org.java_websocket.extensions.CompressionExtension;
1414
import org.java_websocket.extensions.ExtensionRequestData;
1515
import org.java_websocket.extensions.IExtension;
16-
import org.java_websocket.framing.BinaryFrame;
1716
import org.java_websocket.framing.CloseFrame;
1817
import org.java_websocket.framing.ContinuousFrame;
1918
import org.java_websocket.framing.DataFrame;
2019
import org.java_websocket.framing.Framedata;
2120
import org.java_websocket.framing.FramedataImpl1;
22-
import org.java_websocket.framing.TextFrame;
2321

2422
/**
2523
* PerMessage Deflate Extension (<a href="https://tools.ietf.org/html/rfc7692#section-7">7&#46; The
@@ -53,23 +51,37 @@ public class PerMessageDeflateExtension extends CompressionExtension {
5351
// For WebSocketClients, this variable holds the extension parameters that client himself has requested.
5452
private Map<String, String> requestedParameters = new LinkedHashMap<>();
5553

56-
private Inflater inflater = new Inflater(true);
57-
private Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
54+
private final int compressionLevel;
5855

59-
public Inflater getInflater() {
60-
return inflater;
61-
}
56+
private final Inflater inflater;
57+
private final Deflater deflater;
6258

63-
public void setInflater(Inflater inflater) {
64-
this.inflater = inflater;
59+
/**
60+
* Constructor for the PerMessage Deflate Extension (<a href="https://tools.ietf.org/html/rfc7692#section-7">7&#46; Thepermessage-deflate" Extension</a>)
61+
*
62+
* Uses {@link java.util.zip.Deflater#DEFAULT_COMPRESSION} as the compression level for the {@link java.util.zip.Deflater#Deflater(int)}
63+
*/
64+
public PerMessageDeflateExtension() {
65+
this(Deflater.DEFAULT_COMPRESSION);
6566
}
6667

67-
public Deflater getDeflater() {
68-
return deflater;
68+
/**
69+
* Constructor for the PerMessage Deflate Extension (<a href="https://tools.ietf.org/html/rfc7692#section-7">7&#46; Thepermessage-deflate" Extension</a>)
70+
*
71+
* @param compressionLevel The compression level passed to the {@link java.util.zip.Deflater#Deflater(int)}
72+
*/
73+
public PerMessageDeflateExtension(int compressionLevel) {
74+
this.compressionLevel = compressionLevel;
75+
this.deflater = new Deflater(this.compressionLevel, true);
76+
this.inflater = new Inflater(true);
6977
}
7078

71-
public void setDeflater(Deflater deflater) {
72-
this.deflater = deflater;
79+
/**
80+
* Get the compression level used for the compressor.
81+
* @return the compression level
82+
*/
83+
public int getCompressionLevel() {
84+
return this.compressionLevel;
7385
}
7486

7587
/**
@@ -166,15 +178,15 @@ We can check the getRemaining() method to see whether the data we supplied has b
166178
Note that this behavior doesn't occur if the message is "first compressed and then fragmented".
167179
*/
168180
if (inflater.getRemaining() > 0) {
169-
inflater = new Inflater(true);
181+
inflater.reset();
170182
decompress(inputFrame.getPayloadData().array(), output);
171183
}
172184

173185
if (inputFrame.isFin()) {
174186
decompress(TAIL_BYTES, output);
175187
// If context takeover is disabled, inflater can be reset.
176188
if (clientNoContextTakeover) {
177-
inflater = new Inflater(true);
189+
inflater.reset();
178190
}
179191
}
180192
} catch (DataFormatException e) {
@@ -244,8 +256,7 @@ public void encodeFrame(Framedata inputFrame) {
244256
}
245257

246258
if (serverNoContextTakeover) {
247-
deflater.end();
248-
deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
259+
deflater.reset();
249260
}
250261
}
251262

@@ -330,7 +341,11 @@ public String getProvidedExtensionAsServer() {
330341

331342
@Override
332343
public IExtension copyInstance() {
333-
return new PerMessageDeflateExtension();
344+
PerMessageDeflateExtension clone = new PerMessageDeflateExtension(this.getCompressionLevel());
345+
clone.setThreshold(this.getThreshold());
346+
clone.setClientNoContextTakeover(this.isClientNoContextTakeover());
347+
clone.setServerNoContextTakeover(this.isServerNoContextTakeover());
348+
return clone;
334349
}
335350

336351
/**

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

Lines changed: 108 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
import static org.junit.Assert.fail;
88

99
import java.nio.ByteBuffer;
10+
import java.util.Arrays;
1011
import java.util.zip.Deflater;
11-
import java.util.zip.Inflater;
12+
1213
import org.java_websocket.exceptions.InvalidDataException;
1314
import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
14-
import org.java_websocket.framing.BinaryFrame;
1515
import org.java_websocket.framing.ContinuousFrame;
1616
import org.java_websocket.framing.TextFrame;
1717
import org.junit.Test;
@@ -51,6 +51,79 @@ public void testDecodeFrameIfRSVIsNotSet() throws InvalidDataException {
5151
assertFalse(frame.isRSV1());
5252
}
5353

54+
@Test
55+
public void testDecodeFrameNoCompression() throws InvalidDataException {
56+
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension(Deflater.NO_COMPRESSION);
57+
deflateExtension.setThreshold(0);
58+
String str = "This is a highly compressable text"
59+
+ "This is a highly compressable text"
60+
+ "This is a highly compressable text"
61+
+ "This is a highly compressable text"
62+
+ "This is a highly compressable text";
63+
byte[] message = str.getBytes();
64+
TextFrame frame = new TextFrame();
65+
frame.setPayload(ByteBuffer.wrap(message));
66+
deflateExtension.encodeFrame(frame);
67+
byte[] payloadArray = frame.getPayloadData().array();
68+
assertArrayEquals(message, Arrays.copyOfRange(payloadArray, 5,payloadArray.length-5));
69+
assertTrue(frame.isRSV1());
70+
deflateExtension.decodeFrame(frame);
71+
assertArrayEquals(message, frame.getPayloadData().array());
72+
}
73+
74+
@Test
75+
public void testDecodeFrameBestSpeedCompression() throws InvalidDataException {
76+
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension(Deflater.BEST_SPEED);
77+
deflateExtension.setThreshold(0);
78+
String str = "This is a highly compressable text"
79+
+ "This is a highly compressable text"
80+
+ "This is a highly compressable text"
81+
+ "This is a highly compressable text"
82+
+ "This is a highly compressable text";
83+
byte[] message = str.getBytes();
84+
TextFrame frame = new TextFrame();
85+
frame.setPayload(ByteBuffer.wrap(message));
86+
87+
Deflater localDeflater = new Deflater(Deflater.BEST_SPEED,true);
88+
localDeflater.setInput(ByteBuffer.wrap(message).array());
89+
byte[] buffer = new byte[1024];
90+
int bytesCompressed = localDeflater.deflate(buffer, 0, buffer.length, Deflater.SYNC_FLUSH);
91+
92+
deflateExtension.encodeFrame(frame);
93+
byte[] payloadArray = frame.getPayloadData().array();
94+
assertArrayEquals(Arrays.copyOfRange(buffer,0, bytesCompressed), Arrays.copyOfRange(payloadArray,0,payloadArray.length));
95+
assertTrue(frame.isRSV1());
96+
deflateExtension.decodeFrame(frame);
97+
assertArrayEquals(message, frame.getPayloadData().array());
98+
}
99+
100+
@Test
101+
public void testDecodeFrameBestCompression() throws InvalidDataException {
102+
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension(Deflater.BEST_COMPRESSION);
103+
deflateExtension.setThreshold(0);
104+
String str = "This is a highly compressable text"
105+
+ "This is a highly compressable text"
106+
+ "This is a highly compressable text"
107+
+ "This is a highly compressable text"
108+
+ "This is a highly compressable text";
109+
byte[] message = str.getBytes();
110+
TextFrame frame = new TextFrame();
111+
frame.setPayload(ByteBuffer.wrap(message));
112+
113+
Deflater localDeflater = new Deflater(Deflater.BEST_COMPRESSION,true);
114+
localDeflater.setInput(ByteBuffer.wrap(message).array());
115+
byte[] buffer = new byte[1024];
116+
int bytesCompressed = localDeflater.deflate(buffer, 0, buffer.length, Deflater.SYNC_FLUSH);
117+
118+
deflateExtension.encodeFrame(frame);
119+
byte[] payloadArray = frame.getPayloadData().array();
120+
assertArrayEquals(Arrays.copyOfRange(buffer,0, bytesCompressed), Arrays.copyOfRange(payloadArray,0,payloadArray.length));
121+
assertTrue(frame.isRSV1());
122+
deflateExtension.decodeFrame(frame);
123+
assertArrayEquals(message, frame.getPayloadData().array());
124+
}
125+
126+
54127
@Test
55128
public void testEncodeFrame() {
56129
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
@@ -191,35 +264,45 @@ public void testSetClientNoContextTakeover() {
191264
@Test
192265
public void testCopyInstance() {
193266
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
194-
IExtension newDeflateExtension = deflateExtension.copyInstance();
195-
assertEquals(deflateExtension.toString(), newDeflateExtension.toString());
196-
}
267+
PerMessageDeflateExtension newDeflateExtension = (PerMessageDeflateExtension)deflateExtension.copyInstance();
268+
assertEquals("PerMessageDeflateExtension", newDeflateExtension.toString());
269+
// Also check the values
270+
assertEquals(deflateExtension.getThreshold(), newDeflateExtension.getThreshold());
271+
assertEquals(deflateExtension.isClientNoContextTakeover(), newDeflateExtension.isClientNoContextTakeover());
272+
assertEquals(deflateExtension.isServerNoContextTakeover(), newDeflateExtension.isServerNoContextTakeover());
273+
assertEquals(deflateExtension.getCompressionLevel(), newDeflateExtension.getCompressionLevel());
197274

198-
@Test
199-
public void testGetInflater() {
200-
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
201-
assertEquals(deflateExtension.getInflater().getRemaining(), new Inflater(true).getRemaining());
202-
}
203275

204-
@Test
205-
public void testSetInflater() {
206-
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
207-
deflateExtension.setInflater(new Inflater(false));
208-
assertEquals(deflateExtension.getInflater().getRemaining(), new Inflater(false).getRemaining());
209-
}
276+
deflateExtension = new PerMessageDeflateExtension(Deflater.BEST_COMPRESSION);
277+
deflateExtension.setThreshold(512);
278+
deflateExtension.setServerNoContextTakeover(false);
279+
deflateExtension.setClientNoContextTakeover(true);
280+
newDeflateExtension = (PerMessageDeflateExtension)deflateExtension.copyInstance();
210281

211-
@Test
212-
public void testGetDeflater() {
213-
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
214-
assertEquals(deflateExtension.getDeflater().finished(),
215-
new Deflater(Deflater.DEFAULT_COMPRESSION, true).finished());
282+
assertEquals(deflateExtension.getThreshold(), newDeflateExtension.getThreshold());
283+
assertEquals(deflateExtension.isClientNoContextTakeover(), newDeflateExtension.isClientNoContextTakeover());
284+
assertEquals(deflateExtension.isServerNoContextTakeover(), newDeflateExtension.isServerNoContextTakeover());
285+
assertEquals(deflateExtension.getCompressionLevel(), newDeflateExtension.getCompressionLevel());
286+
287+
288+
deflateExtension = new PerMessageDeflateExtension(Deflater.NO_COMPRESSION);
289+
deflateExtension.setThreshold(64);
290+
deflateExtension.setServerNoContextTakeover(true);
291+
deflateExtension.setClientNoContextTakeover(false);
292+
newDeflateExtension = (PerMessageDeflateExtension)deflateExtension.copyInstance();
293+
294+
assertEquals(deflateExtension.getThreshold(), newDeflateExtension.getThreshold());
295+
assertEquals(deflateExtension.isClientNoContextTakeover(), newDeflateExtension.isClientNoContextTakeover());
296+
assertEquals(deflateExtension.isServerNoContextTakeover(), newDeflateExtension.isServerNoContextTakeover());
297+
assertEquals(deflateExtension.getCompressionLevel(), newDeflateExtension.getCompressionLevel());
216298
}
217299

218300
@Test
219-
public void testSetDeflater() {
301+
public void testDefaults() {
220302
PerMessageDeflateExtension deflateExtension = new PerMessageDeflateExtension();
221-
deflateExtension.setDeflater(new Deflater(Deflater.DEFAULT_COMPRESSION, false));
222-
assertEquals(deflateExtension.getDeflater().finished(),
223-
new Deflater(Deflater.DEFAULT_COMPRESSION, false).finished());
303+
assertFalse(deflateExtension.isClientNoContextTakeover());
304+
assertTrue(deflateExtension.isServerNoContextTakeover());
305+
assertEquals(1024, deflateExtension.getThreshold());
306+
assertEquals(Deflater.DEFAULT_COMPRESSION, deflateExtension.getCompressionLevel());
224307
}
225308
}

0 commit comments

Comments
 (0)