From 018aa11173d32284591f82d6ecd69d406a296202 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Tue, 18 Mar 2014 16:26:22 -0400 Subject: [PATCH] hatch websocket cont. Signed-off-by: Bill Erickson --- src/org/evergreen_ils/hatch/HatchSocket.java | 238 ++++++++++++++++++++- .../evergreen_ils/hatch/HatchWebSocketServlet.java | 18 +- 2 files changed, 243 insertions(+), 13 deletions(-) diff --git a/src/org/evergreen_ils/hatch/HatchSocket.java b/src/org/evergreen_ils/hatch/HatchSocket.java index 14316ce37..bfcb77224 100644 --- a/src/org/evergreen_ils/hatch/HatchSocket.java +++ b/src/org/evergreen_ils/hatch/HatchSocket.java @@ -1,40 +1,258 @@ package org.evergreen_ils.hatch; - -import org.eclipse.jetty.util.FutureCallback; - import java.io.IOException; +import java.io.File; +import java.io.BufferedReader; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; import org.eclipse.jetty.websocket.api.annotations.WebSocket; +import javax.servlet.ServletConfig; + +import org.eclipse.jetty.util.ajax.JSON; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import java.util.Arrays; +import java.util.List; @WebSocket public class HatchSocket { private Session session; + static String[] trustedDomains; + static String trustedDomainsString; + static boolean trustAllDomains = false; + static String profileDirectory; + private static final Logger logger = Log.getLogger("HatchSocket"); + + /** + * config is passed in from our WebSocketServlet container, + * hence the public+static. Possible to access directly? + */ + public static void configure(ServletConfig config) { + logger.info("HatchSocket.configure()"); + + trustedDomainsString = + config.getServletContext().getInitParameter("trusted-domains"); + + profileDirectory = + config.getServletContext().getInitParameter("profile-directory"); + + // default to ~/.evergreen + if (profileDirectory == null) { + String home = System.getProperty("user.home"); + profileDirectory = new File(home, ".evergreen").getPath(); + if (profileDirectory == null) { + logger.info("Unable to set profile directory"); + } + } + + if (trustedDomainsString == null) { + logger.info("No trusted domains configured"); + + } else { + + if (trustedDomainsString.equals("*")) { + trustAllDomains = true; + logger.info("All domains trusted"); + + } else { + + trustedDomains = trustedDomainsString.split(","); + for(String domain : trustedDomains) { + logger.info("Trusted domain: " + domain); + } + } + } + } + + protected boolean verifyOriginDomain() { + logger.info("received connection from IP " + + session.getRemoteAddress().getAddress()); + + String origin = session.getUpgradeRequest().getHeader("Origin"); + + if (origin == null) { + logger.warn("No Origin header in request; Dropping connection"); + return false; + } + + logger.info("connection origin is " + origin); + + if (trustAllDomains) return true; + + if (java.util.Arrays.asList(trustedDomains).indexOf(origin) < 0) { + logger.warn("Request from un-trusted domain: " + origin); + return false; + } + + return true; + } + @OnWebSocketConnect public void onConnect(Session session) { - System.out.println("Connect: " + session.getRemoteAddress().getAddress()); this.session = session; + if (!verifyOriginDomain()) session.close(); } @OnWebSocketClose public void onClose(int statusCode, String reason) { - System.out.println("Close: statusCode=" + statusCode + ", reason=" + reason); + logger.info("onClose() statusCode=" + statusCode + ", reason=" + reason); this.session = null; } - @OnWebSocketMessage - public void onMessage(String message) { - System.out.println("Message: " + message); + private void sendJSONMessage(Object json) { try { - session.getRemote().sendString("hello : " + message); + session.getRemote().sendString(JSON.toString(json)); } catch (IOException e) { - e.printStackTrace(); + logger.warn(e); + } + } + + @OnWebSocketMessage + public void onMessage(String message) { + if (session == null || !session.isOpen()) return; + logger.info("onMessage() " + message); + + FileIO io; + /* + * TODO: inbound message should be a JSON blob + String action = request.getParameter("action"); + String key = request.getParameter("key"); + String value = request.getParameter("value"); + */ + String action = "keys"; + String key = ""; + String value = ""; + + // all requests require an action + /* + if (action == null || action.equals("")) { + String err = JSON.toString("No action specified in request"); + sendJSONMessage(err); + logger.info(err); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + */ + + if (action.equals("keys")) { + io = new FileIO(profileDirectory); + String[] keys = io.keys(key); // OK for key to be null + + if (keys != null) { + sendJSONMessage(keys); + } else { + /* + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + */ + } + return; + } + + if (action.equals("printers")) { + List printers = new PrintDriver().getPrinters(); + //response.setStatus(HttpServletResponse.SC_OK); + sendJSONMessage(printers); + return; + } + + // all remaining requests require a key + if (key == null || key.equals("")) { + String err = "No key specified in request"; + sendJSONMessage(err); + logger.info(err); + //response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; } + + if (action.equals("get")) { + io = new FileIO(profileDirectory); + BufferedReader reader = io.get(key); + if (reader != null) { + String line; + //response.setStatus(HttpServletResponse.SC_OK); + try { + while ( (line = reader.readLine()) != null) { + // relay lines of text to the caller as we read them + // assume the text content is JSON and return it + // un-JSON-ified. + sendJSONMessage(line); + } + } catch (IOException e) { + logger.warn(e); + } + } else { + /* + response.setStatus( + HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + */ + } + return; + } + + if (action.equals("delete")) { + io = new FileIO(profileDirectory); + if (io.delete(key)) { + //response.setStatus(HttpServletResponse.SC_OK); + } else { + //response.setStatus( + //HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + return; + } + + // all remaining actions require value + if (value == null) { + String err = "No value specified in request"; + sendJSONMessage(err); + logger.info(err); + //response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + switch(action) { + + case "print" : + boolean ok = new PrintDriver().printWithDialog(key, value); + if (ok) { + //response.setStatus(HttpServletResponse.SC_OK); + } else { + //response.setStatus( + //HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + break; + + case "set" : + io = new FileIO(profileDirectory); + if (io.set(key, value)) { + //response.setStatus(HttpServletResponse.SC_OK); + } else { + //response.setStatus( + //HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + break; + + case "append" : + io = new FileIO(profileDirectory); + if (io.append(key, value)) { + //response.setStatus(HttpServletResponse.SC_OK); + } else { + //response.setStatus( + //HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + break; + + default: + //response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + sendJSONMessage( + "\"No Such Action: " + action + "\""); + logger.info("No such action: " + action); + } + } } diff --git a/src/org/evergreen_ils/hatch/HatchWebSocketServlet.java b/src/org/evergreen_ils/hatch/HatchWebSocketServlet.java index 2c3612d63..464b0b996 100644 --- a/src/org/evergreen_ils/hatch/HatchWebSocketServlet.java +++ b/src/org/evergreen_ils/hatch/HatchWebSocketServlet.java @@ -1,15 +1,27 @@ package org.evergreen_ils.hatch; import javax.servlet.annotation.WebServlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; import org.eclipse.jetty.websocket.servlet.WebSocketServlet; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; - -@SuppressWarnings("serial") -//@WebServlet(name = "Hatch WebSocket Servlet", urlPatterns = { "/ws" }) +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + public class HatchWebSocketServlet extends WebSocketServlet { + + private static final Logger logger = + Log.getLogger("HatchWebSocketServlet"); + @Override public void configure(WebSocketServletFactory factory) { factory.register(HatchSocket.class); } + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); // required for WS + HatchSocket.configure(config); + } } -- 2.11.0