Skip to content

Commit

Permalink
Expose query parameter on WebSocketUpgrade requestUrl to the library …
Browse files Browse the repository at this point in the history
…consumers (#5)
  • Loading branch information
SreeramGarlapati authored Apr 26, 2018
1 parent e9c6b29 commit 64503af
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 284 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,20 @@ public enum WebSocketFrameReadState {
*
* @param host the hots name
* @param path the resource path
* @param query the query
* @param port the port
* @param protocol the base protocol
* @param additionalHeaders the Map of additional headers
* @param webSocketHandler the web socket handler
*/
void configure(String host, String path, int port, String protocol, Map<String, String> additionalHeaders, WebSocketHandler webSocketHandler);
void configure(
String host,
String path,
String query,
int port,
String protocol,
Map<String, String> additionalHeaders,
WebSocketHandler webSocketHandler);

/**
* Add WebSocket frame to send the given buffer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ public enum WebSocketMessageType {
}

String createUpgradeRequest(
String hostName, String webSocketPath, int webSocketPort, String webSocketProtocol, Map<String, String> additionalHeaders);
String hostName,
String webSocketPath,
String webSocketQuery,
int webSocketPort,
String webSocketProtocol,
Map<String, String> additionalHeaders);

Boolean validateUpgradeReply(ByteBuffer buffer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ public class WebSocketHandlerImpl implements WebSocketHandler {
public String createUpgradeRequest(
String hostName,
String webSocketPath,
String webSocketQuery,
int webSocketPort,
String webSocketProtocol,
Map<String, String> additionalHeaders) {
webSocketUpgrade = createWebSocketUpgrade(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
webSocketUpgrade = createWebSocketUpgrade(hostName, webSocketPath, webSocketQuery, webSocketPort, webSocketProtocol, additionalHeaders);
return webSocketUpgrade.createUpgradeRequest();
}

Expand Down Expand Up @@ -217,8 +218,13 @@ public WebsocketTuple unwrapBuffer(ByteBuffer srcBuffer) {
}

protected WebSocketUpgrade createWebSocketUpgrade(
String hostName, String webSocketPath, int webSocketPort, String webSocketProtocol, Map<String, String> additionalHeaders) {
return new WebSocketUpgrade(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
String hostName,
String webSocketPath,
String webSocketQuery,
int webSocketPort,
String webSocketProtocol,
Map<String, String> additionalHeaders) {
return new WebSocketUpgrade(hostName, webSocketPath, webSocketQuery, webSocketPort, webSocketProtocol, additionalHeaders);
}

protected byte[] createRandomMaskingKey() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class WebSocketImpl implements WebSocket, TransportLayer {

private String host = "";
private String path = "";
private String query = "";
private int port = 0;
private String protocol = "";
private Map<String, String> additionalHeaders = null;
Expand All @@ -57,7 +58,7 @@ public class WebSocketImpl implements WebSocket, TransportLayer {

/**
* Create WebSocket transport layer - which, after configuring using
* the {@link #configure(String, String, int, String, Map, WebSocketHandler)} API
* the {@link #configure(String, String, String, int, String, Map, WebSocketHandler)} API
* is ready for layering in qpid-proton-j transport layers, using
* {@link org.apache.qpid.proton.engine.impl.TransportInternal#addTransportLayer(TransportLayer)} API.
*/
Expand Down Expand Up @@ -86,6 +87,7 @@ protected boolean isDeterminationMade() {
public void configure(
String host,
String path,
String query,
int port,
String protocol,
Map<String, String> additionalHeaders,
Expand Down Expand Up @@ -168,6 +170,7 @@ public String toString() {
.append(", protocol=").append(protocol)
.append(", host=").append(host)
.append(", path=").append(path)
.append(", query=").append(query)
.append(", port=").append(port);

if ((additionalHeaders != null) && (!additionalHeaders.isEmpty())) {
Expand All @@ -188,7 +191,7 @@ public String toString() {

protected void writeUpgradeRequest() {
outputBuffer.clear();
String request = webSocketHandler.createUpgradeRequest(host, path, port, protocol, additionalHeaders);
String request = webSocketHandler.createUpgradeRequest(host, path, query, port, protocol, additionalHeaders);
outputBuffer.put(request.getBytes());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,103 +13,47 @@
import java.util.Scanner;

public class WebSocketUpgrade {
public static final String RFC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private final String rfcGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private final char questionMark = '?';
private final char slash = '/';
private String host = "";
private String path = "";
private String port = "";
private String protocol = "";
private String webSocketKey = "";
private Map<String, String> additionalHeaders = null;
private boolean certAvailability = false;
private final String query;
private final String host;
private final String path;
private final String port;
private final String protocol;
private final Map<String, String> additionalHeaders;

private volatile String webSocketKey = "";

/**
* Create {@link WebSocketUpgrade} instance, which can be used for websocket upgrade hand-shake with http server
* as per RFC https://tools.ietf.org/html/rfc6455.
* @param hostName host name to send the request to
* @param webSocketPath path on the request url where WebSocketUpgrade will be sent to
* @param webSocketQuery query on the request url where WebSocketUpgrade will be sent to
* @param webSocketPort port on the request url where WebSocketUpgrade will be sent to
* @param webSocketProtocol value for Sec-WebSocket-Protocol header on the WebSocketUpgrade request
* @param additionalHeaders any additional headers to be part of the WebSocketUpgrade request
*/
public WebSocketUpgrade(
String hostName, String webSocketPath, int webSocketPort, String webSocketProtocol, Map<String, String> additionalHeaders) {
setHost(hostName);
setPath(webSocketPath);
setPort(webSocketPort);
setProtocol(webSocketProtocol);
setAdditionalHeaders(additionalHeaders);
}

/**
* Set host value in host header.
*
* @param host The host header field value.
*/
public void setHost(String host) {
this.host = host;
}

/**
* Set port value in host header.
*
* @param port The port header field value.
*/
public void setPort(int port) {
this.port = "";

if (port != 0) {
this.port = String.valueOf(port);
}
}

/**
* Set path value in handshake.
*
* @param path The path field value.
*/
public void setPath(String path) {
this.path = path;

if (!this.path.isEmpty()) {
if (this.path.charAt(0) != this.slash) {
this.path = this.slash + this.path;
}
}
}

/**
* Set protocol value in protocol header.
*
* @param protocol The protocol header field value.
*/
public void setProtocol(String protocol) {
this.protocol = protocol;
}

/**
* Add field-value pairs to HTTP header.
*
* @param additionalHeaders The Map containing the additional headers.
*/
public void setAdditionalHeaders(Map<String, String> additionalHeaders) {
String hostName,
String webSocketPath,
String webSocketQuery,
int webSocketPort,
String webSocketProtocol,
Map<String, String> additionalHeaders) {
this.host = hostName;
this.path = webSocketPath.isEmpty() || webSocketPath.charAt(0) == this.slash
? webSocketPath
: this.slash + webSocketPath;
this.query = webSocketQuery.isEmpty() || webSocketQuery.charAt(0) == this.questionMark
? webSocketQuery
: this.questionMark + webSocketQuery;
this.port = webSocketPort == 0 ? "" : String.valueOf(webSocketPort);
this.protocol = webSocketProtocol;
this.additionalHeaders = additionalHeaders;
}

/**
* Utility function to clear all additional headers.
*/
public void clearAdditionalHeaders() {
additionalHeaders.clear();
}

/**
* Set protocol value in protocol header.
*/
public void setClientCertAvailable() {
certAvailability = true;
}

/**
* Utility function to create random, Base64 encoded key.
*/
Expand Down Expand Up @@ -138,9 +82,12 @@ public String createUpgradeRequest() {

this.webSocketKey = createWebSocketKey();

String endOfLine = "\r\n";
StringBuilder stringBuilder = new StringBuilder().append("GET https://").append(this.host).append(this.path)
.append("?").append("iothub-no-client-cert=").append(!this.certAvailability)
final String endOfLine = "\r\n";
final StringBuilder stringBuilder = new StringBuilder()
.append("GET https://")
.append(this.host)
.append(this.path)
.append(this.query)
.append(" HTTP/1.1").append(endOfLine)
.append("Connection: Upgrade,Keep-Alive").append(endOfLine)
.append("Upgrade: websocket").append(endOfLine)
Expand All @@ -166,18 +113,18 @@ public String createUpgradeRequest() {
* @return value indicating if the websockets upgrade succeeded
*/
public Boolean validateUpgradeReply(byte[] responseBytes) {
String httpString = new String(responseBytes, StandardCharsets.UTF_8);
final String httpString = new String(responseBytes, StandardCharsets.UTF_8);

Boolean isStatusLineOk = false;
Boolean isUpgradeHeaderOk = false;
Boolean isConnectionHeaderOk = false;
Boolean isProtocolHeaderOk = false;
Boolean isAcceptHeaderOk = false;

Scanner scanner = new Scanner(httpString);
final Scanner scanner = new Scanner(httpString);

while (scanner.hasNextLine()) {
String line = scanner.nextLine();
final String line = scanner.nextLine();

if ((line.toLowerCase().contains("http/1.1"))
&& (line.contains("101"))
Expand Down Expand Up @@ -215,7 +162,8 @@ public Boolean validateUpgradeReply(byte[] responseBytes) {
break;
}

String expectedKey = Base64.encodeBase64StringLocal(messageDigest.digest((this.webSocketKey + RFC_GUID).getBytes())).trim();
final String expectedKey = Base64.encodeBase64StringLocal(
messageDigest.digest((this.webSocketKey + this.rfcGuid).getBytes())).trim();

if (line.contains(expectedKey)) {
isAcceptHeaderOk = true;
Expand All @@ -236,7 +184,7 @@ public Boolean validateUpgradeReply(byte[] responseBytes) {

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
final StringBuilder builder = new StringBuilder();
builder.append("WebSocketUpgrade [host=")
.append(host)
.append(", path=")
Expand All @@ -255,7 +203,7 @@ public String toString() {
builder.append(entry.getKey() + ":" + entry.getValue()).append(", ");
}

int lastIndex = builder.lastIndexOf(", ");
final int lastIndex = builder.lastIndexOf(", ");
builder.delete(lastIndex, lastIndex + 2);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void testCreateUpgradeRequest() {

WebSocketHandlerImpl webSocketHandler = new WebSocketHandlerImpl();

String actual = webSocketHandler.createUpgradeRequest(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
String actual = webSocketHandler.createUpgradeRequest(hostName, webSocketPath, queryKey + queryValue, webSocketPort, webSocketProtocol, additionalHeaders);

Boolean isLineCountOk = false;
Boolean isStatusLineOk = false;
Expand Down Expand Up @@ -150,9 +150,9 @@ public void testCreateUpgradeRequest_verify_subsequent_call() {

WebSocketUpgrade mockWebSocketUpgrade = mock(WebSocketUpgrade.class);

doReturn(mockWebSocketUpgrade).when(spyWebSocketHandler).createWebSocketUpgrade(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
spyWebSocketHandler.createUpgradeRequest(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
verify(spyWebSocketHandler, times(1)).createWebSocketUpgrade(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
doReturn(mockWebSocketUpgrade).when(spyWebSocketHandler).createWebSocketUpgrade(hostName, webSocketPath, "", webSocketPort, webSocketProtocol, additionalHeaders);
spyWebSocketHandler.createUpgradeRequest(hostName, webSocketPath, "", webSocketPort, webSocketProtocol, additionalHeaders);
verify(spyWebSocketHandler, times(1)).createWebSocketUpgrade(hostName, webSocketPath, "", webSocketPort, webSocketProtocol, additionalHeaders);
verify(mockWebSocketUpgrade, times(1)).createUpgradeRequest();
}

Expand Down Expand Up @@ -224,7 +224,7 @@ public void testValidateUpgradeReply() {
String webSocketPath = "path1/path2";
int webSocketPort = 1234567890;
String webSocketProtocol = "subprotocol_name";
Map<String, String> additionalHeaders = new HashMap<String, String>();
final Map<String, String> additionalHeaders = new HashMap<String, String>();
additionalHeaders.put("header1", "content1");
additionalHeaders.put("header2", "content2");
additionalHeaders.put("header3", "content3");
Expand All @@ -237,10 +237,10 @@ public void testValidateUpgradeReply() {

WebSocketUpgrade mockWebSocketUpgrade = mock(WebSocketUpgrade.class);

doReturn(mockWebSocketUpgrade).when(spyWebSocketHandler).createWebSocketUpgrade(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
doReturn(mockWebSocketUpgrade).when(spyWebSocketHandler).createWebSocketUpgrade(hostName, webSocketPath, "", webSocketPort, webSocketProtocol, additionalHeaders);
doReturn(true).when(mockWebSocketUpgrade).validateUpgradeReply(data);

spyWebSocketHandler.createUpgradeRequest(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
spyWebSocketHandler.createUpgradeRequest(hostName, webSocketPath, "", webSocketPort, webSocketProtocol, additionalHeaders);
assertTrue(spyWebSocketHandler.validateUpgradeReply(buffer));
assertFalse(mockWebSocketUpgrade == null);
verify(mockWebSocketUpgrade, times(1)).validateUpgradeReply(data);
Expand All @@ -266,10 +266,10 @@ public void testValidateUpgradeReply_no_remaining() {

WebSocketUpgrade mockWebSocketUpgrade = mock(WebSocketUpgrade.class);

doReturn(mockWebSocketUpgrade).when(spyWebSocketHandler).createWebSocketUpgrade(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
doReturn(mockWebSocketUpgrade).when(spyWebSocketHandler).createWebSocketUpgrade(hostName, webSocketPath, "", webSocketPort, webSocketProtocol, additionalHeaders);
doReturn(true).when(mockWebSocketUpgrade).validateUpgradeReply(data);

spyWebSocketHandler.createUpgradeRequest(hostName, webSocketPath, webSocketPort, webSocketProtocol, additionalHeaders);
spyWebSocketHandler.createUpgradeRequest(hostName, webSocketPath, "", webSocketPort, webSocketProtocol, additionalHeaders);
assertFalse(spyWebSocketHandler.validateUpgradeReply(buffer));
verify(mockWebSocketUpgrade, times(0)).validateUpgradeReply(data);
}
Expand Down
Loading

0 comments on commit 64503af

Please sign in to comment.