blob: a8669e4639a36c311935b3d47ce260e8fc746d6e [file] [log] [blame]
Jake Slack03928ae2014-05-13 18:41:56 -07001//
2// ========================================================================
3// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4// ------------------------------------------------------------------------
5// All rights reserved. This program and the accompanying materials
6// are made available under the terms of the Eclipse Public License v1.0
7// and Apache License v2.0 which accompanies this distribution.
8//
9// The Eclipse Public License is available at
10// http://www.eclipse.org/legal/epl-v10.html
11//
12// The Apache License v2.0 is available at
13// http://www.opensource.org/licenses/apache2.0.php
14//
15// You may elect to redistribute this code under either of these licenses.
16// ========================================================================
17//
18
19package org.eclipse.jetty.server.handler;
20
21import java.io.IOException;
22
23import javax.servlet.ServletException;
24import javax.servlet.http.HttpServletRequest;
25import javax.servlet.http.HttpServletResponse;
26
27import org.eclipse.jetty.server.Request;
28import org.eclipse.jetty.server.Server;
29import org.eclipse.jetty.util.log.Log;
30import org.eclipse.jetty.util.log.Logger;
31
32/* ------------------------------------------------------------ */
33/**
34 * 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
35 * made.
36 *
37 * This handler is a contribution from Johannes Brodwall: https://bugs.eclipse.org/bugs/show_bug.cgi?id=357687
38 *
39 * Usage:
40 *
41 * <pre>
42 Server server = new Server(8080);
43 HandlerList handlers = new HandlerList();
44 handlers.setHandlers(new Handler[]
45 { someOtherHandler, new ShutdownHandler(server,&quot;secret password&quot;) });
46 server.setHandler(handlers);
47 server.start();
48 </pre>
49 *
50 <pre>
51 public static void attemptShutdown(int port, String shutdownCookie) {
52 try {
53 URL url = new URL("http://localhost:" + port + "/shutdown?token=" + shutdownCookie);
54 HttpURLConnection connection = (HttpURLConnection)url.openConnection();
55 connection.setRequestMethod("POST");
56 connection.getResponseCode();
57 logger.info("Shutting down " + url + ": " + connection.getResponseMessage());
58 } catch (SocketException e) {
59 logger.debug("Not running");
60 // Okay - the server is not running
61 } catch (IOException e) {
62 throw new RuntimeException(e);
63 }
64 }
65 </pre>
66 */
67public class ShutdownHandler extends AbstractHandler
68{
69 private static final Logger LOG = Log.getLogger(ShutdownHandler.class);
70
71 private final String _shutdownToken;
72
73 private final Server _server;
74
75 private boolean _exitJvm = false;
76
77
78
79 /**
80 * Creates a listener that lets the server be shut down remotely (but only from localhost).
81 *
82 * @param server
83 * the Jetty instance that should be shut down
84 * @param shutdownToken
85 * a secret password to avoid unauthorized shutdown attempts
86 */
87 public ShutdownHandler(Server server, String shutdownToken)
88 {
89 this._server = server;
90 this._shutdownToken = shutdownToken;
91 }
92
93 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
94 {
95 if (!target.equals("/shutdown"))
96 {
97 return;
98 }
99
100 if (!request.getMethod().equals("POST"))
101 {
102 response.sendError(HttpServletResponse.SC_BAD_REQUEST);
103 return;
104 }
105 if (!hasCorrectSecurityToken(request))
106 {
107 LOG.warn("Unauthorized shutdown attempt from " + getRemoteAddr(request));
108 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
109 return;
110 }
111 if (!requestFromLocalhost(request))
112 {
113 LOG.warn("Unauthorized shutdown attempt from " + getRemoteAddr(request));
114 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
115 return;
116 }
117
118 LOG.info("Shutting down by request from " + getRemoteAddr(request));
119
120 new Thread()
121 {
122 public void run ()
123 {
124 try
125 {
126 shutdownServer();
127 }
128 catch (InterruptedException e)
129 {
130 LOG.ignore(e);
131 }
132 catch (Exception e)
133 {
134 throw new RuntimeException("Shutting down server",e);
135 }
136 }
137 }.start();
138 }
139
140 private boolean requestFromLocalhost(HttpServletRequest request)
141 {
142 return "127.0.0.1".equals(getRemoteAddr(request));
143 }
144
145 protected String getRemoteAddr(HttpServletRequest request)
146 {
147 return request.getRemoteAddr();
148 }
149
150 private boolean hasCorrectSecurityToken(HttpServletRequest request)
151 {
152 return _shutdownToken.equals(request.getParameter("token"));
153 }
154
155 private void shutdownServer() throws Exception
156 {
157 _server.stop();
158
159 if (_exitJvm)
160 {
161 System.exit(0);
162 }
163 }
164
165 public void setExitJvm(boolean exitJvm)
166 {
167 this._exitJvm = exitJvm;
168 }
169
170}