Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PerMessageDeflate Extension support, see #574 #866

Merged
merged 8 commits into from Mar 17, 2020
72 changes: 72 additions & 0 deletions src/main/example/PerMessageDeflateExample.java
@@ -0,0 +1,72 @@
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.server.WebSocketServer;

import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;

/**
* This class only serves the purpose of showing how to enable PerMessageDeflateExtension for both server and client sockets.<br>
* Extensions are required to be registered in
* @see Draft objects and both
* @see WebSocketClient and
* @see WebSocketServer accept a
* @see Draft object in their constructors.
* This example shows how to achieve it for both server and client sockets.
* Once the connection has been established, PerMessageDeflateExtension will be enabled
* and any messages (binary or text) will be compressed/decompressed automatically.<br>
* Since no additional code is required when sending or receiving messages, this example skips those parts.
*/
public class PerMessageDeflateExample {

private static final Draft perMessageDeflateDraft = new Draft_6455(new PerMessageDeflateExtension());
private static final int PORT = 8887;

private static class DeflateClient extends WebSocketClient {

public DeflateClient() throws URISyntaxException {
super(new URI("ws://localhost:" + PORT), perMessageDeflateDraft);
}

@Override
public void onOpen(ServerHandshake handshakedata) { }

@Override
public void onMessage(String message) { }

@Override
public void onClose(int code, String reason, boolean remote) { }

@Override
public void onError(Exception ex) { }
}

private static class DeflateServer extends WebSocketServer {

public DeflateServer() {
super(new InetSocketAddress(PORT), Collections.singletonList(perMessageDeflateDraft));
}

@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) { }

@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) { }

@Override
public void onMessage(WebSocket conn, String message) { }

@Override
public void onError(WebSocket conn, Exception ex) { }

@Override
public void onStart() { }
}
}
27 changes: 27 additions & 0 deletions src/main/java/org/java_websocket/drafts/Draft_6455.java
Expand Up @@ -427,6 +427,12 @@ private ByteBuffer createByteBufferFromFramedata( Framedata framedata ) {
byte optcode = fromOpcode( framedata.getOpcode() );
byte one = ( byte ) ( framedata.isFin() ? -128 : 0 );
one |= optcode;
if(framedata.isRSV1())
one |= getRSVByte(1);
if(framedata.isRSV2())
one |= getRSVByte(2);
if(framedata.isRSV3())
one |= getRSVByte(3);
buf.put( one );
byte[] payloadlengthbytes = toByteArray( mes.remaining(), sizebytes );
assert ( payloadlengthbytes.length == sizebytes );
Expand Down Expand Up @@ -585,6 +591,27 @@ private void translateSingleFrameCheckPacketSize(int maxpacketsize, int realpack
}
}

/**
* Get a byte that can set RSV bits when OR(|)'d.
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-------+
* |F|R|R|R| opcode|
* |I|S|S|S| (4) |
* |N|V|V|V| |
* | |1|2|3| |
* @param rsv Can only be {0, 1, 2, 3}
* @return byte that represents which RSV bit is set.
*/
private byte getRSVByte(int rsv){
if(rsv == 1) // 0100 0000
return 0x40;
if(rsv == 2) // 0010 0000
return 0x20;
if(rsv == 3) // 0001 0000
return 0x10;
return 0;
}

/**
* Get the mask byte if existing
* @param mask is mask active or not
Expand Down
@@ -0,0 +1,52 @@
package org.java_websocket.extensions;

import java.util.LinkedHashMap;
import java.util.Map;

public class ExtensionRequestData {

public static String EMPTY_VALUE = "";

private Map<String, String> extensionParameters;
private String extensionName;

private ExtensionRequestData() {
extensionParameters = new LinkedHashMap<String, String>();
}

public static ExtensionRequestData parseExtensionRequest(String extensionRequest) {
ExtensionRequestData extensionData = new ExtensionRequestData();
String[] parts = extensionRequest.split(";");
extensionData.extensionName = parts[0].trim();

for(int i = 1; i < parts.length; i++) {
String[] keyValue = parts[i].split("=");
String value = EMPTY_VALUE;

// Some parameters don't take a value. For those that do, parse the value.
if(keyValue.length > 1) {
String tempValue = keyValue[1].trim();

// If the value is wrapped in quotes, just get the data between them.
if((tempValue.startsWith("\"") && tempValue.endsWith("\""))
|| (tempValue.startsWith("'") && tempValue.endsWith("'"))
&& tempValue.length() > 2)
tempValue = tempValue.substring(1, tempValue.length() - 1);

value = tempValue;
}

extensionData.extensionParameters.put(keyValue[0].trim(), value);
}

return extensionData;
}

public String getExtensionName() {
return extensionName;
}

public Map<String, String> getExtensionParameters() {
return extensionParameters;
}
}