/** * Copyright (C) 2014 Red Hat, Inc, and individual contributors. * Copyright (C) 2011-2012 VMware, Inc. */ package org.projectodd.sockjs; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Handlers from sockjs-node's webjs.coffee */ public class WebHandler { public DispatchFunction handle405 = new DispatchFunction() { @Override @SuppressWarnings("unchecked") public Object handle(SockJsRequest req, SockJsResponse res, Object data) throws SockJsException { List<String> methods = (List<String>) data; res.setHeader("Allow", Utils.join(methods, ", ")); res.writeHead(405); res.end(); return true; } }; public DispatchFunction handleError = new DispatchFunction() { @Override public Object handle(SockJsRequest req, SockJsResponse res, Object data) throws SockJsException { Exception x = (Exception) data; if (res.finished()) { return x; } log.log(Level.FINER, "handleError", x); if (x instanceof DispatchException) { DispatchException dx = (DispatchException) x; log.log(Level.FINE, "DispatchException message: {0}", dx.message); res.writeHead(dx.status); String message = dx.message; if (message == null) { message = ""; } res.end(message); } else { try { res.writeHead(500); res.end("500 - Internal Server Error"); } catch (Exception e) { // ignore } } return true; } }; public DispatchFunction expose = new DispatchFunction() { @Override public Object handle(SockJsRequest req, SockJsResponse res, Object content) throws SockJsException { if (res.finished()) { return content; } boolean hasContent = content != null && content.toString().length() > 0; if (hasContent && res.getHeader("Content-Type") == null) { res.setHeader("Content-Type", "text/plain"); } if (hasContent) { try { res.setHeader("Content-Length", "" + content.toString().getBytes("UTF-8").length); } catch (IOException ex) { throw new SockJsException("Error writing Content-Length header:", ex); } } res.writeHead(res.statusCode()); res.end(content.toString()); return true; } }; public DispatchFunction cacheFor = new DispatchFunction() { @Override public Object handle(SockJsRequest req, SockJsResponse res, Object content) throws SockJsException { if (res.cacheFor() == null) { res.cacheFor(365 * 24 * 60 * 60); // one year } res.setHeader("Cache-Control", "public, max-age=" + res.cacheFor()); res.setHeader("Expires", Utils.generateExpires(new Date(System.currentTimeMillis() + res.cacheFor() * 1000))); return content; } }; public DispatchFunction hNoCache = new DispatchFunction() { @Override public Object handle(SockJsRequest req, SockJsResponse res, Object content) throws SockJsException { res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); return content; } }; public DispatchFunction expectForm = new DispatchFunction() { @Override public Object handle(final SockJsRequest req, SockJsResponse res, Object _data) throws SockJsException { log.log(Level.FINER, "Expecting form"); final Buffer data = new Buffer(0); req.onData(new SockJsRequest.OnDataHandler() { @Override public void handle(byte[] d) throws SockJsException { log.log(Level.FINER, "onData {0}", d); data.concat(new Buffer(d)); } }); req.onEnd(new SockJsRequest.OnEndHandler() { @Override public void handle() throws SockJsException { log.log(Level.FINER, "onEnd"); String contentType = req.getContentType(); if (contentType == null) { contentType = ""; } Object q; switch(contentType.split(";")[0]) { case "application/x-www-form-urlencoded": // We'll use req.getQueryParameter later to retrieve form data q = new Object(); break; case "text/plain": q = data.toString("UTF-8"); break; default: q = null; break; } log.log(Level.FINER, "Q is {0}", q); req.nextFilter.handle(q); } }); throw new DispatchException(0); } }; public DispatchFunction expectXhr = new DispatchFunction() { @Override public Object handle(final SockJsRequest req, final SockJsResponse res, Object _data) throws SockJsException { log.log(Level.FINER, "Expecting XHR"); final Buffer data = new Buffer(0); req.onData(new SockJsRequest.OnDataHandler() { @Override public void handle(byte[] d) throws SockJsException { log.log(Level.FINER, "onData {0}", d); data.concat(new Buffer(d)); } }); req.onEnd(new SockJsRequest.OnEndHandler() { @Override public void handle() throws SockJsException { log.log(Level.FINER, "onEnd"); String contentType = req.getContentType(); if (contentType == null) { contentType = ""; } String q; switch(contentType.split(";")[0]) { case "text/plain": case "T": case "application/json": case "application/xml": case "": case "text/xml": q = data.toString("UTF-8"); break; default: q = null; break; } log.log(Level.FINER, "Q is {0}", q); req.nextFilter.handle(q); } }); throw new DispatchException(0); } }; public WebHandler(SockJsServer server) { this.server = server; } private SockJsServer server; private static final Logger log = Logger.getLogger(WebHandler.class.getName()); }