Skip to content

Commit 4232021

Browse files
authored
Merge pull request TooTallNate#866 from haruntuncay/master
Add PerMessageDeflate Extension support, see TooTallNate#574
2 parents eacb4f0 + 48a35ce commit 4232021

File tree

6 files changed

+509
-1
lines changed

6 files changed

+509
-1
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import org.java_websocket.WebSocket;
2+
import org.java_websocket.client.WebSocketClient;
3+
import org.java_websocket.drafts.Draft;
4+
import org.java_websocket.drafts.Draft_6455;
5+
import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
6+
import org.java_websocket.handshake.ClientHandshake;
7+
import org.java_websocket.handshake.ServerHandshake;
8+
import org.java_websocket.server.WebSocketServer;
9+
10+
import java.net.InetSocketAddress;
11+
import java.net.URI;
12+
import java.net.URISyntaxException;
13+
import java.util.Collections;
14+
15+
/**
16+
* This class only serves the purpose of showing how to enable PerMessageDeflateExtension for both server and client sockets.<br>
17+
* Extensions are required to be registered in
18+
* @see Draft objects and both
19+
* @see WebSocketClient and
20+
* @see WebSocketServer accept a
21+
* @see Draft object in their constructors.
22+
* This example shows how to achieve it for both server and client sockets.
23+
* Once the connection has been established, PerMessageDeflateExtension will be enabled
24+
* and any messages (binary or text) will be compressed/decompressed automatically.<br>
25+
* Since no additional code is required when sending or receiving messages, this example skips those parts.
26+
*/
27+
public class PerMessageDeflateExample {
28+
29+
private static final Draft perMessageDeflateDraft = new Draft_6455(new PerMessageDeflateExtension());
30+
private static final int PORT = 8887;
31+
32+
private static class DeflateClient extends WebSocketClient {
33+
34+
public DeflateClient() throws URISyntaxException {
35+
super(new URI("ws://localhost:" + PORT), perMessageDeflateDraft);
36+
}
37+
38+
@Override
39+
public void onOpen(ServerHandshake handshakedata) { }
40+
41+
@Override
42+
public void onMessage(String message) { }
43+
44+
@Override
45+
public void onClose(int code, String reason, boolean remote) { }
46+
47+
@Override
48+
public void onError(Exception ex) { }
49+
}
50+
51+
private static class DeflateServer extends WebSocketServer {
52+
53+
public DeflateServer() {
54+
super(new InetSocketAddress(PORT), Collections.singletonList(perMessageDeflateDraft));
55+
}
56+
57+
@Override
58+
public void onOpen(WebSocket conn, ClientHandshake handshake) { }
59+
60+
@Override
61+
public void onClose(WebSocket conn, int code, String reason, boolean remote) { }
62+
63+
@Override
64+
public void onMessage(WebSocket conn, String message) { }
65+
66+
@Override
67+
public void onError(WebSocket conn, Exception ex) { }
68+
69+
@Override
70+
public void onStart() { }
71+
}
72+
}

src/main/java/org/java_websocket/drafts/Draft_6455.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,12 @@ private ByteBuffer createByteBufferFromFramedata( Framedata framedata ) {
427427
byte optcode = fromOpcode( framedata.getOpcode() );
428428
byte one = ( byte ) ( framedata.isFin() ? -128 : 0 );
429429
one |= optcode;
430+
if(framedata.isRSV1())
431+
one |= getRSVByte(1);
432+
if(framedata.isRSV2())
433+
one |= getRSVByte(2);
434+
if(framedata.isRSV3())
435+
one |= getRSVByte(3);
430436
buf.put( one );
431437
byte[] payloadlengthbytes = toByteArray( mes.remaining(), sizebytes );
432438
assert ( payloadlengthbytes.length == sizebytes );
@@ -585,6 +591,27 @@ private void translateSingleFrameCheckPacketSize(int maxpacketsize, int realpack
585591
}
586592
}
587593

594+
/**
595+
* Get a byte that can set RSV bits when OR(|)'d.
596+
* 0 1 2 3 4 5 6 7
597+
* +-+-+-+-+-------+
598+
* |F|R|R|R| opcode|
599+
* |I|S|S|S| (4) |
600+
* |N|V|V|V| |
601+
* | |1|2|3| |
602+
* @param rsv Can only be {0, 1, 2, 3}
603+
* @return byte that represents which RSV bit is set.
604+
*/
605+
private byte getRSVByte(int rsv){
606+
if(rsv == 1) // 0100 0000
607+
return 0x40;
608+
if(rsv == 2) // 0010 0000
609+
return 0x20;
610+
if(rsv == 3) // 0001 0000
611+
return 0x10;
612+
return 0;
613+
}
614+
588615
/**
589616
* Get the mask byte if existing
590617
* @param mask is mask active or not
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.java_websocket.extensions;
2+
3+
import java.util.LinkedHashMap;
4+
import java.util.Map;
5+
6+
public class ExtensionRequestData {
7+
8+
public static String EMPTY_VALUE = "";
9+
10+
private Map<String, String> extensionParameters;
11+
private String extensionName;
12+
13+
private ExtensionRequestData() {
14+
extensionParameters = new LinkedHashMap<String, String>();
15+
}
16+
17+
public static ExtensionRequestData parseExtensionRequest(String extensionRequest) {
18+
ExtensionRequestData extensionData = new ExtensionRequestData();
19+
String[] parts = extensionRequest.split(";");
20+
extensionData.extensionName = parts[0].trim();
21+
22+
for(int i = 1; i < parts.length; i++) {
23+
String[] keyValue = parts[i].split("=");
24+
String value = EMPTY_VALUE;
25+
26+
// Some parameters don't take a value. For those that do, parse the value.
27+
if(keyValue.length > 1) {
28+
String tempValue = keyValue[1].trim();
29+
30+
// If the value is wrapped in quotes, just get the data between them.
31+
if((tempValue.startsWith("\"") && tempValue.endsWith("\""))
32+
|| (tempValue.startsWith("'") && tempValue.endsWith("'"))
33+
&& tempValue.length() > 2)
34+
tempValue = tempValue.substring(1, tempValue.length() - 1);
35+
36+
value = tempValue;
37+
}
38+
39+
extensionData.extensionParameters.put(keyValue[0].trim(), value);
40+
}
41+
42+
return extensionData;
43+
}
44+
45+
public String getExtensionName() {
46+
return extensionName;
47+
}
48+
49+
public Map<String, String> getExtensionParameters() {
50+
return extensionParameters;
51+
}
52+
}

0 commit comments

Comments
 (0)