package org.smartly.packages.http.impl.handlers; /* ------------------------------------------------------------ */ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.ContextHandler; import org.smartly.commons.logging.Logger; import org.smartly.commons.logging.util.LoggingUtils; import org.smartly.packages.http.impl.AbstractHttpServer; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java. If _exitJvm ist set to true a hard System.exit() call is being * made. * <p/> * This handler is a contribution from Johannes Brodwall: https://bugs.eclipse.org/bugs/show_bug.cgi?id=357687 * <p/> * Usage: * <p/> * <pre> * Server server = new Server(8080); * HandlerList handlers = new HandlerList(); * handlers.setHandlers(new Handler[] * { someOtherHandler, new ShutdownHandler(server,"secret password") }); * server.setHandler(handlers); * server.start(); * </pre> * <p/> * <pre> * public static void attemptShutdown(int port, String shutdownCookie) { * try { * URL url = new URL("http://localhost:" + port + "/shutdown?cookie=" + shutdownCookie); * HttpURLConnection connection = (HttpURLConnection)url.openConnection(); * connection.setRequestMethod("POST"); * connection.getResponseCode(); * logger.info("Shutting down " + url + ": " + connection.getResponseMessage()); * } catch (SocketException e) { * logger.debug("Not running"); * // Okay - the server is not running * } catch (IOException e) { * throw new RuntimeException(e); * } * } * </pre> */ public class SmartlyShutdownHandler extends ContextHandler { private static final Logger logger = LoggingUtils.getLogger(SmartlyShutdownHandler.class); private final String _shutdownToken; private final AbstractHttpServer _server; private boolean _exitJvm = false; /** * Creates a listener that lets the server be shut down remotely (but only from localhost). * * @param server the Jetty instance that should be shut down * @param shutdownToken a secret password to avoid unauthorized shutdown attempts */ public SmartlyShutdownHandler(final AbstractHttpServer server, final String shutdownToken) { _server = server; _shutdownToken = shutdownToken; super.setContextPath("/shutdown"); } public void setExitJvm(boolean exitJvm) { this._exitJvm = exitJvm; } public void doHandle(final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { // accept only clean commands if (!target.equals("/")) { return; } // ok, command path is valid baseRequest.setHandled(true); if (!request.getMethod().equals("POST") && !request.getMethod().equals("GET")) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } if (!hasCorrectSecurityToken(request)) { logger.warning("Unauthorized shutdown attempt from " + getRemoteAddr(request)); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return; } if (!requestFromLocalhost(request)) { logger.warning("Unauthorized shutdown attempt from " + getRemoteAddr(request)); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return; } logger.info("Shutting down by request from " + getRemoteAddr(request)); new Thread() { public void run() { try { shutdownServer(); } catch (InterruptedException ignored) { } catch (Exception e) { throw new RuntimeException("Shutting down server", e); } } }.start(); } // ------------------------------------------------------------------------ // p r i v a t e // ------------------------------------------------------------------------ private boolean requestFromLocalhost(final HttpServletRequest request) { return "127.0.0.1".equals(getRemoteAddr(request)); } protected String getRemoteAddr(final HttpServletRequest request) { return request.getRemoteAddr(); } private boolean hasCorrectSecurityToken(final HttpServletRequest request) { return _shutdownToken.equals(request.getParameter("token")); } private void shutdownServer() throws Exception { _server.stop(); if (_exitJvm) { System.exit(0); } } }