aboutsummaryrefslogtreecommitdiff
path: root/websocket/src/main/java/fi/iki
diff options
context:
space:
mode:
authorPaul Hawke <paul.hawke@gmail.com>2014-04-24 23:21:55 -0500
committerPaul Hawke <paul.hawke@gmail.com>2014-04-24 23:21:55 -0500
commit84a1ab453aafe41149fab0e663b49d85cf0896cb (patch)
tree0e858c7fa82ea5b6971781e73329945018a15de7 /websocket/src/main/java/fi/iki
parent44f52c7b241f235d887ab57bf0ffd97a8ce0f5c4 (diff)
downloadnanohttpd-84a1ab453aafe41149fab0e663b49d85cf0896cb.tar.gz
Simplified the test using Mockito, and expanded what was being tested along with some other minor cleanup
Diffstat (limited to 'websocket/src/main/java/fi/iki')
-rw-r--r--websocket/src/main/java/fi/iki/elonen/IWebSocketFactory.java (renamed from websocket/src/main/java/fi/iki/elonen/WebSocketFactory.java)2
-rw-r--r--websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java17
-rw-r--r--websocket/src/main/java/fi/iki/elonen/WebSocket.java42
-rw-r--r--websocket/src/main/java/fi/iki/elonen/WebSocketResponseHandler.java33
-rw-r--r--websocket/src/main/java/fi/iki/elonen/samples/echo/DebugWebSocket.java67
-rw-r--r--websocket/src/main/java/fi/iki/elonen/samples/echo/DebugWebSocketServer.java22
-rw-r--r--websocket/src/main/java/fi/iki/elonen/samples/echo/EchoSocketSample.java22
7 files changed, 161 insertions, 44 deletions
diff --git a/websocket/src/main/java/fi/iki/elonen/WebSocketFactory.java b/websocket/src/main/java/fi/iki/elonen/IWebSocketFactory.java
index 4a4be16..3e38cd2 100644
--- a/websocket/src/main/java/fi/iki/elonen/WebSocketFactory.java
+++ b/websocket/src/main/java/fi/iki/elonen/IWebSocketFactory.java
@@ -2,6 +2,6 @@ package fi.iki.elonen;
import fi.iki.elonen.NanoHTTPD.IHTTPSession;
-public interface WebSocketFactory {
+public interface IWebSocketFactory {
WebSocket openWebSocket(IHTTPSession handshake);
}
diff --git a/websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java b/websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java
index 44a5e9c..0712371 100644
--- a/websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java
+++ b/websocket/src/main/java/fi/iki/elonen/NanoWebSocketServer.java
@@ -1,10 +1,11 @@
package fi.iki.elonen;
-public class NanoWebSocketServer extends NanoHTTPD implements WebSocketFactory {
-
+public class NanoWebSocketServer extends NanoHTTPD implements IWebSocketFactory {
+ public static final String MISSING_FACTORY_MESSAGE = "You must either override this method or supply a WebSocketFactory in the constructor";
+
private final WebSocketResponseHandler responseHandler;
-
+
public NanoWebSocketServer(int port) {
super(port);
responseHandler = new WebSocketResponseHandler(this);
@@ -14,17 +15,17 @@ public class NanoWebSocketServer extends NanoHTTPD implements WebSocketFactory {
super(hostname, port);
responseHandler = new WebSocketResponseHandler(this);
}
-
- public NanoWebSocketServer(int port, WebSocketFactory webSocketFactory) {
+
+ public NanoWebSocketServer(int port, IWebSocketFactory webSocketFactory) {
super(port);
responseHandler = new WebSocketResponseHandler(webSocketFactory);
}
- public NanoWebSocketServer(String hostname, int port,WebSocketFactory webSocketFactory) {
+ public NanoWebSocketServer(String hostname, int port, IWebSocketFactory webSocketFactory) {
super(hostname, port);
responseHandler = new WebSocketResponseHandler(webSocketFactory);
}
-
+
@Override
public Response serve(IHTTPSession session) {
Response candidate = responseHandler.serve(session);
@@ -32,7 +33,7 @@ public class NanoWebSocketServer extends NanoHTTPD implements WebSocketFactory {
}
public WebSocket openWebSocket(IHTTPSession handshake) {
- throw new Error("You must either override this method or supply a WebSocketFactory in the cosntructor");
+ throw new Error(MISSING_FACTORY_MESSAGE);
}
}
diff --git a/websocket/src/main/java/fi/iki/elonen/WebSocket.java b/websocket/src/main/java/fi/iki/elonen/WebSocket.java
index ba1a446..22b07fb 100644
--- a/websocket/src/main/java/fi/iki/elonen/WebSocket.java
+++ b/websocket/src/main/java/fi/iki/elonen/WebSocket.java
@@ -12,20 +12,24 @@ import java.util.LinkedList;
import java.util.List;
public abstract class WebSocket {
- protected final InputStream in;
- protected /*final*/ OutputStream out;
+ public static enum State {
+ UNCONNECTED, CONNECTING, OPEN, CLOSING, CLOSED
+ }
+
+ protected InputStream in;
+
+ protected OutputStream out;
protected WebSocketFrame.OpCode continuousOpCode = null;
+
protected List<WebSocketFrame> continuousFrames = new LinkedList<WebSocketFrame>();
protected State state = State.UNCONNECTED;
- public static enum State {
- UNCONNECTED, CONNECTING, OPEN, CLOSING, CLOSED
- }
-
protected final NanoHTTPD.IHTTPSession handshakeRequest;
- protected final NanoHTTPD.Response handshakeResponse = new NanoHTTPD.Response(NanoHTTPD.Response.Status.SWITCH_PROTOCOL, null, (InputStream) null) {
+
+ protected final NanoHTTPD.Response handshakeResponse = new NanoHTTPD.Response(
+ NanoHTTPD.Response.Status.SWITCH_PROTOCOL, null, (InputStream) null) {
@Override
protected void send(OutputStream out) {
WebSocket.this.out = out;
@@ -40,8 +44,18 @@ public abstract class WebSocket {
this.handshakeRequest = handshakeRequest;
this.in = handshakeRequest.getInputStream();
- handshakeResponse.addHeader(WebSocketResponseHandler.HEADER_UPGRADE, WebSocketResponseHandler.HEADER_UPGRADE_VALUE);
- handshakeResponse.addHeader(WebSocketResponseHandler.HEADER_CONNECTION, WebSocketResponseHandler.HEADER_CONNECTION_VALUE);
+ handshakeResponse.addHeader(WebSocketResponseHandler.HEADER_UPGRADE,
+ WebSocketResponseHandler.HEADER_UPGRADE_VALUE);
+ handshakeResponse.addHeader(WebSocketResponseHandler.HEADER_CONNECTION,
+ WebSocketResponseHandler.HEADER_CONNECTION_VALUE);
+ }
+
+ public NanoHTTPD.IHTTPSession getHandshakeRequest() {
+ return handshakeRequest;
+ }
+
+ public NanoHTTPD.Response getHandshakeResponse() {
+ return handshakeResponse;
}
// --------------------------------IO--------------------------------------
@@ -190,14 +204,4 @@ public abstract class WebSocket {
doClose(code, reason, false);
}
}
-
- // --------------------------------Getters---------------------------------
-
- public NanoHTTPD.IHTTPSession getHandshakeRequest() {
- return handshakeRequest;
- }
-
- public NanoHTTPD.Response getHandshakeResponse() {
- return handshakeResponse;
- }
}
diff --git a/websocket/src/main/java/fi/iki/elonen/WebSocketResponseHandler.java b/websocket/src/main/java/fi/iki/elonen/WebSocketResponseHandler.java
index 2805889..5c042af 100644
--- a/websocket/src/main/java/fi/iki/elonen/WebSocketResponseHandler.java
+++ b/websocket/src/main/java/fi/iki/elonen/WebSocketResponseHandler.java
@@ -19,38 +19,40 @@ public class WebSocketResponseHandler {
public static final String HEADER_WEBSOCKET_PROTOCOL = "sec-websocket-protocol";
public final static String WEBSOCKET_KEY_MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
-
- private final WebSocketFactory webSocketFactory;
- public WebSocketResponseHandler(WebSocketFactory webSocketFactory) {
- super();
+ private final IWebSocketFactory webSocketFactory;
+
+ public WebSocketResponseHandler(IWebSocketFactory webSocketFactory) {
this.webSocketFactory = webSocketFactory;
}
-
+
public Response serve(final IHTTPSession session) {
Map<String, String> headers = session.getHeaders();
if (isWebsocketRequested(session)) {
- if (!HEADER_UPGRADE_VALUE.equalsIgnoreCase(headers.get(HEADER_UPGRADE))
- || !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))) {
- return new Response(Response.Status.BAD_REQUEST, NanoHTTPD.MIME_PLAINTEXT, "Invalid Websocket-Version " + headers.get(HEADER_WEBSOCKET_VERSION));
+ return new Response(Response.Status.BAD_REQUEST, NanoHTTPD.MIME_PLAINTEXT,
+ "Invalid Websocket-Version " + headers.get(HEADER_WEBSOCKET_VERSION));
}
+
if (!headers.containsKey(HEADER_WEBSOCKET_KEY)) {
- return new Response(Response.Status.BAD_REQUEST, NanoHTTPD.MIME_PLAINTEXT, "Missing Websocket-Key");
+ return new Response(Response.Status.BAD_REQUEST, NanoHTTPD.MIME_PLAINTEXT,
+ "Missing Websocket-Key");
}
WebSocket webSocket = webSocketFactory.openWebSocket(session);
+ Response handshakeResponse = webSocket.getHandshakeResponse();
try {
- webSocket.getHandshakeResponse().addHeader(HEADER_WEBSOCKET_ACCEPT, makeAcceptKey(headers.get(HEADER_WEBSOCKET_KEY)));
+ handshakeResponse.addHeader(HEADER_WEBSOCKET_ACCEPT, makeAcceptKey(headers.get(HEADER_WEBSOCKET_KEY)));
} catch (NoSuchAlgorithmException e) {
- return new Response(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "The SHA-1 Algorithm required for websockets is not available on the server.");
+ return new Response(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT,
+ "The SHA-1 Algorithm required for websockets is not available on the server.");
}
+
if (headers.containsKey(HEADER_WEBSOCKET_PROTOCOL)) {
- webSocket.getHandshakeResponse().addHeader(HEADER_WEBSOCKET_PROTOCOL, headers.get(HEADER_WEBSOCKET_PROTOCOL).split(",")[0]);
+ handshakeResponse.addHeader(HEADER_WEBSOCKET_PROTOCOL, headers.get(HEADER_WEBSOCKET_PROTOCOL).split(",")[0]);
}
- return webSocket.getHandshakeResponse();
+
+ return handshakeResponse;
} else {
return null;
}
@@ -77,7 +79,6 @@ public class WebSocketResponseHandler {
return encodeBase64(sha1hash);
}
-
private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
/**
diff --git a/websocket/src/main/java/fi/iki/elonen/samples/echo/DebugWebSocket.java b/websocket/src/main/java/fi/iki/elonen/samples/echo/DebugWebSocket.java
new file mode 100644
index 0000000..badd7ee
--- /dev/null
+++ b/websocket/src/main/java/fi/iki/elonen/samples/echo/DebugWebSocket.java
@@ -0,0 +1,67 @@
+package fi.iki.elonen.samples.echo;
+
+import fi.iki.elonen.NanoHTTPD;
+import fi.iki.elonen.WebSocket;
+import fi.iki.elonen.WebSocketFrame;
+
+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);
+ this.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/main/java/fi/iki/elonen/samples/echo/DebugWebSocketServer.java b/websocket/src/main/java/fi/iki/elonen/samples/echo/DebugWebSocketServer.java
new file mode 100644
index 0000000..5faf72a
--- /dev/null
+++ b/websocket/src/main/java/fi/iki/elonen/samples/echo/DebugWebSocketServer.java
@@ -0,0 +1,22 @@
+package fi.iki.elonen.samples.echo;
+
+import fi.iki.elonen.NanoWebSocketServer;
+import fi.iki.elonen.WebSocket;
+
+/**
+* @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
+ public WebSocket openWebSocket(IHTTPSession handshake) {
+ return new DebugWebSocket(handshake, debug);
+ }
+}
diff --git a/websocket/src/main/java/fi/iki/elonen/samples/echo/EchoSocketSample.java b/websocket/src/main/java/fi/iki/elonen/samples/echo/EchoSocketSample.java
new file mode 100644
index 0000000..b28a42c
--- /dev/null
+++ b/websocket/src/main/java/fi/iki/elonen/samples/echo/EchoSocketSample.java
@@ -0,0 +1,22 @@
+package fi.iki.elonen.samples.echo;
+
+import fi.iki.elonen.NanoWebSocketServer;
+
+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");
+ }
+
+}
+