aboutsummaryrefslogtreecommitdiff
path: root/websocket
diff options
context:
space:
mode:
authorPaul Hawke <paul.hawke@gmail.com>2014-04-23 23:08:57 -0500
committerPaul Hawke <paul.hawke@gmail.com>2014-04-23 23:08:57 -0500
commitc6c080a6f4377fb18fc869111714e9514c36331a (patch)
tree1ac1f8ad3486e39bd2591bd5d603dcd09de8f0e9 /websocket
parent6d3737c76afdb1c991bf8d96e3dd2cc622435f09 (diff)
downloadnanohttpd-c6c080a6f4377fb18fc869111714e9514c36331a.tar.gz
websockets: final polish before release. Tested on IE, Chrome and Firefox
Diffstat (limited to 'websocket')
-rw-r--r--websocket/pom.xml2
-rw-r--r--websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java (renamed from websocket/src/main/java/fi/iki/elonen/NanoWSD.java)19
-rw-r--r--websocket/src/main/java/fi/iki/elonen/WebSocket.java4
-rw-r--r--websocket/src/test/java/fi/iki/elonen/DebugWebSocket.java61
-rw-r--r--websocket/src/test/java/fi/iki/elonen/DebugWebSocketServer.java19
-rw-r--r--websocket/src/test/java/fi/iki/elonen/EchoSocket.java70
-rw-r--r--websocket/src/test/java/fi/iki/elonen/EchoSocketSample.java20
-rw-r--r--websocket/src/test/resources/echo-test.html58
8 files changed, 174 insertions, 79 deletions
diff --git a/websocket/pom.xml b/websocket/pom.xml
index 04ecc4b..7d94041 100644
--- a/websocket/pom.xml
+++ b/websocket/pom.xml
@@ -75,7 +75,7 @@
</descriptorRefs>
<archive>
<manifest>
- <mainClass>fi.iki.elonen.NanoWSD</mainClass>
+ <mainClass>fi.iki.elonen.NanoWebSocketServer</mainClass>
</manifest>
</archive>
</configuration>
diff --git a/websocket/src/main/java/fi/iki/elonen/NanoWSD.java b/websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java
index 2b2933a..7a5e588 100644
--- a/websocket/src/main/java/fi/iki/elonen/NanoWSD.java
+++ b/websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java
@@ -6,7 +6,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
-public abstract class NanoWSD extends NanoHTTPD {
+public abstract class NanoWebSocketServer extends NanoHTTPD {
public static final String HEADER_UPGRADE = "upgrade";
public static final String HEADER_UPGRADE_VALUE = "websocket";
public static final String HEADER_CONNECTION = "connection";
@@ -19,11 +19,11 @@ public abstract class NanoWSD extends NanoHTTPD {
public final static String WEBSOCKET_KEY_MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- public NanoWSD(int port) {
+ public NanoWebSocketServer(int port) {
super(port);
}
- public NanoWSD(String hostname, int port) {
+ public NanoWebSocketServer(String hostname, int port) {
super(hostname, port);
}
@@ -32,7 +32,7 @@ public abstract class NanoWSD extends NanoHTTPD {
Map<String, String> headers = session.getHeaders();
if (isWebsocketRequested(session)) {
if (!HEADER_UPGRADE_VALUE.equalsIgnoreCase(headers.get(HEADER_UPGRADE))
- || !HEADER_CONNECTION_VALUE.equalsIgnoreCase(headers.get(HEADER_CONNECTION))) {
+ || !isWebSocketConnectionHeader(session.getHeaders())) {
return new Response(Response.Status.BAD_REQUEST, NanoHTTPD.MIME_PLAINTEXT, "Invalid Websocket handshake");
}
if (!HEADER_WEBSOCKET_VERSION_VALUE.equalsIgnoreCase(headers.get(HEADER_WEBSOCKET_VERSION))) {
@@ -61,8 +61,15 @@ public abstract class NanoWSD extends NanoHTTPD {
protected boolean isWebsocketRequested(IHTTPSession session) {
Map<String, String> headers = session.getHeaders();
- return ((HEADER_UPGRADE_VALUE.equalsIgnoreCase(headers.get(HEADER_UPGRADE)))
- && (HEADER_CONNECTION_VALUE.equalsIgnoreCase(headers.get(HEADER_CONNECTION))));
+ String upgrade = headers.get(HEADER_UPGRADE);
+ boolean isCorrectConnection = isWebSocketConnectionHeader(headers);
+ boolean isUpgrade = HEADER_UPGRADE_VALUE.equalsIgnoreCase(upgrade);
+ return (isUpgrade && isCorrectConnection);
+ }
+
+ private boolean isWebSocketConnectionHeader(Map<String, String> headers) {
+ String connection = headers.get(HEADER_CONNECTION);
+ return (connection != null && connection.toLowerCase().contains(HEADER_CONNECTION_VALUE.toLowerCase()));
}
public static String makeAcceptKey(String key) throws NoSuchAlgorithmException {
diff --git a/websocket/src/main/java/fi/iki/elonen/WebSocket.java b/websocket/src/main/java/fi/iki/elonen/WebSocket.java
index dcba8c0..84bf259 100644
--- a/websocket/src/main/java/fi/iki/elonen/WebSocket.java
+++ b/websocket/src/main/java/fi/iki/elonen/WebSocket.java
@@ -40,8 +40,8 @@ public abstract class WebSocket {
this.handshakeRequest = handshakeRequest;
this.in = handshakeRequest.getInputStream();
- handshakeResponse.addHeader(NanoWSD.HEADER_UPGRADE, NanoWSD.HEADER_UPGRADE_VALUE);
- handshakeResponse.addHeader(NanoWSD.HEADER_CONNECTION, NanoWSD.HEADER_CONNECTION_VALUE);
+ handshakeResponse.addHeader(NanoWebSocketServer.HEADER_UPGRADE, NanoWebSocketServer.HEADER_UPGRADE_VALUE);
+ handshakeResponse.addHeader(NanoWebSocketServer.HEADER_CONNECTION, NanoWebSocketServer.HEADER_CONNECTION_VALUE);
}
// --------------------------------IO--------------------------------------
diff --git a/websocket/src/test/java/fi/iki/elonen/DebugWebSocket.java b/websocket/src/test/java/fi/iki/elonen/DebugWebSocket.java
new file mode 100644
index 0000000..e6c66ad
--- /dev/null
+++ b/websocket/src/test/java/fi/iki/elonen/DebugWebSocket.java
@@ -0,0 +1,61 @@
+package fi.iki.elonen;
+
+import java.io.IOException;
+
+/**
+* @author Paul S. Hawke (paul.hawke@gmail.com)
+* On: 4/23/14 at 10:34 PM
+*/
+class DebugWebSocket extends WebSocket {
+ private final boolean DEBUG;
+
+ public DebugWebSocket(NanoHTTPD.IHTTPSession handshake, boolean debug) {
+ super(handshake);
+ DEBUG = debug;
+ }
+
+ @Override
+ protected void onPong(WebSocketFrame pongFrame) {
+ if (DEBUG) {
+ System.out.println("P " + pongFrame);
+ }
+ }
+
+ @Override
+ protected void onMessage(WebSocketFrame messageFrame) {
+ try {
+ messageFrame.setUnmasked();
+ sendFrame(messageFrame);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected void onClose(WebSocketFrame.CloseCode code, String reason, boolean initiatedByRemote) {
+ if (DEBUG) {
+ System.out.println("C [" + (initiatedByRemote ? "Remote" : "Self") + "] " + (code != null ? code : "UnknownCloseCode[" + code + "]") + (reason != null && !reason.isEmpty() ? ": " + reason : ""));
+ }
+ }
+
+ @Override
+ protected void onException(IOException e) {
+ e.printStackTrace();
+ }
+
+ @Override
+ protected void handleWebsocketFrame(WebSocketFrame frame) throws IOException {
+ if (DEBUG) {
+ System.out.println("R " + frame);
+ }
+ super.handleWebsocketFrame(frame);
+ }
+
+ @Override
+ public synchronized void sendFrame(WebSocketFrame frame) throws IOException {
+ if (DEBUG) {
+ System.out.println("S " + frame);
+ }
+ super.sendFrame(frame);
+ }
+}
diff --git a/websocket/src/test/java/fi/iki/elonen/DebugWebSocketServer.java b/websocket/src/test/java/fi/iki/elonen/DebugWebSocketServer.java
new file mode 100644
index 0000000..49fbe4d
--- /dev/null
+++ b/websocket/src/test/java/fi/iki/elonen/DebugWebSocketServer.java
@@ -0,0 +1,19 @@
+package fi.iki.elonen;
+
+/**
+* @author Paul S. Hawke (paul.hawke@gmail.com)
+* On: 4/23/14 at 10:31 PM
+*/
+class DebugWebSocketServer extends NanoWebSocketServer {
+ private final boolean debug;
+
+ public DebugWebSocketServer(int port, boolean debug) {
+ super(port);
+ this.debug = debug;
+ }
+
+ @Override
+ protected WebSocket openWebSocket(IHTTPSession handshake) {
+ return new DebugWebSocket(handshake, debug);
+ }
+}
diff --git a/websocket/src/test/java/fi/iki/elonen/EchoSocket.java b/websocket/src/test/java/fi/iki/elonen/EchoSocket.java
deleted file mode 100644
index ef39796..0000000
--- a/websocket/src/test/java/fi/iki/elonen/EchoSocket.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package fi.iki.elonen;
-
-import java.io.IOException;
-
-public class EchoSocket {
- public static void main(String[] args) throws IOException {
- final boolean DEBUG = args.length >= 2 && args[1].toLowerCase().equals("-d");
- NanoWSD ws = new NanoWSD(Integer.parseInt(args[0])) {
- @Override
- protected WebSocket openWebSocket(IHTTPSession handshake) {
- return new WebSocket(handshake) {
- @Override
- protected void onPong(WebSocketFrame pongFrame) {
- if (DEBUG) {
- System.out.println("P " + pongFrame);
- }
- }
-
- @Override
- protected void onMessage(WebSocketFrame messageFrame) {
- try {
- messageFrame.setUnmasked();
- sendFrame(messageFrame);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- protected void onClose(WebSocketFrame.CloseCode code, String reason, boolean initiatedByRemote) {
- if (DEBUG) {
- System.out.println("C [" + (initiatedByRemote ? "Remote" : "Self") + "] " + (code != null ? code : "UnknownCloseCode[" + code + "]") + (reason != null && !reason.isEmpty() ? ": " + reason : ""));
- }
- }
-
- @Override
- protected void onException(IOException e) {
- e.printStackTrace();
- }
-
- @Override
- protected void handleWebsocketFrame(WebSocketFrame frame) throws IOException {
- if (DEBUG) {
- System.out.println("R " + frame);
- }
- super.handleWebsocketFrame(frame);
- }
-
- @Override
- public synchronized void sendFrame(WebSocketFrame frame) throws IOException {
- if (DEBUG) {
- System.out.println("S " + frame);
- }
- super.sendFrame(frame);
- }
- };
- }
- };
-
- ws.start();
- System.out.println("Server started, hit Enter to stop.\n");
- try {
- System.in.read();
- } catch (IOException ignored) {
- }
- ws.stop();
- System.out.println("Server stopped.\n");
- }
-}
-
diff --git a/websocket/src/test/java/fi/iki/elonen/EchoSocketSample.java b/websocket/src/test/java/fi/iki/elonen/EchoSocketSample.java
new file mode 100644
index 0000000..091dfc0
--- /dev/null
+++ b/websocket/src/test/java/fi/iki/elonen/EchoSocketSample.java
@@ -0,0 +1,20 @@
+package fi.iki.elonen;
+
+import java.io.IOException;
+
+public class EchoSocketSample {
+ public static void main(String[] args) throws IOException {
+ final boolean debugMode = args.length >= 2 && args[1].toLowerCase().equals("-d");
+ NanoWebSocketServer ws = new DebugWebSocketServer(Integer.parseInt(args[0]), debugMode);
+ ws.start();
+ System.out.println("Server started, hit Enter to stop.\n");
+ try {
+ System.in.read();
+ } catch (IOException ignored) {
+ }
+ ws.stop();
+ System.out.println("Server stopped.\n");
+ }
+
+}
+
diff --git a/websocket/src/test/resources/echo-test.html b/websocket/src/test/resources/echo-test.html
new file mode 100644
index 0000000..4b60b80
--- /dev/null
+++ b/websocket/src/test/resources/echo-test.html
@@ -0,0 +1,58 @@
+<html>
+<head>
+ <meta charset="utf-8"/>
+ <title>WebSocket Test</title>
+ <script language="javascript" type="text/javascript">
+ var wsUri = "ws://localhost:9090/";
+ var output;
+ function init() {
+ output = document.getElementById("output");
+ testWebSocket();
+ }
+ function testWebSocket() {
+ websocket = new WebSocket(wsUri);
+ websocket.onopen = function (evt) {
+ onOpen(evt)
+ };
+ websocket.onclose = function (evt) {
+ onClose(evt)
+ };
+ websocket.onmessage = function (evt) {
+ onMessage(evt)
+ };
+ websocket.onerror = function (evt) {
+ onError(evt)
+ };
+ }
+ function onOpen(evt) {
+ writeToScreen("CONNECTED");
+ doSend("WebSocket rocks");
+ }
+ function onClose(evt) {
+ writeToScreen("DISCONNECTED");
+ }
+ function onMessage(evt) {
+ writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data + '</span>');
+ websocket.close();
+ }
+ function onError(evt) {
+ writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
+ }
+ function doSend(message) {
+ writeToScreen("SENT: " + message);
+ websocket.send(message);
+ }
+ function writeToScreen(message) {
+ var pre = document.createElement("p");
+ pre.style.wordWrap = "break-word";
+ pre.innerHTML = message;
+ output.appendChild(pre);
+ }
+ window.addEventListener("load", init, false); </script>
+</head>
+<body>
+<h2>WebSocket Test</h2>
+
+<div id="output"></div>
+</body>
+</html> \ No newline at end of file