1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.server.handler;
20
21 import java.io.IOException;
22 import java.net.HttpURLConnection;
23 import java.net.InetSocketAddress;
24 import java.net.SocketException;
25 import java.net.URL;
26
27 import javax.servlet.ServletException;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 import org.eclipse.jetty.server.Connector;
32 import org.eclipse.jetty.server.NetworkConnector;
33 import org.eclipse.jetty.server.Request;
34 import org.eclipse.jetty.server.Server;
35 import org.eclipse.jetty.util.log.Log;
36 import org.eclipse.jetty.util.log.Logger;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public class ShutdownHandler extends HandlerWrapper
78 {
79 private static final Logger LOG = Log.getLogger(ShutdownHandler.class);
80
81 private final String _shutdownToken;
82 private boolean _sendShutdownAtStart;
83 private boolean _exitJvm = false;
84
85
86
87
88
89
90
91
92
93
94 @Deprecated
95 public ShutdownHandler(Server server, String shutdownToken)
96 {
97 this(shutdownToken);
98 }
99
100 public ShutdownHandler(String shutdownToken)
101 {
102 this(shutdownToken,false,false);
103 }
104
105
106
107
108
109
110
111
112
113 public ShutdownHandler(String shutdownToken, boolean exitJVM, boolean sendShutdownAtStart)
114 {
115 this._shutdownToken = shutdownToken;
116 setExitJvm(exitJVM);
117 setSendShutdownAtStart(sendShutdownAtStart);
118 }
119
120
121 public void sendShutdown() throws IOException
122 {
123 URL url = new URL(getServerUrl() + "/shutdown?token=" + _shutdownToken);
124 try
125 {
126 HttpURLConnection connection = (HttpURLConnection)url.openConnection();
127 connection.setRequestMethod("POST");
128 connection.getResponseCode();
129 LOG.info("Shutting down " + url + ": " + connection.getResponseCode() + " " + connection.getResponseMessage());
130 }
131 catch (SocketException e)
132 {
133 LOG.debug("Not running");
134
135 }
136 catch (IOException e)
137 {
138 throw new RuntimeException(e);
139 }
140 }
141
142 @SuppressWarnings("resource")
143 private String getServerUrl()
144 {
145 NetworkConnector connector=null;
146 for (Connector c: getServer().getConnectors())
147 {
148 if (c instanceof NetworkConnector)
149 {
150 connector=(NetworkConnector)c;
151 break;
152 }
153 }
154
155 if (connector==null)
156 return "http://localhost";
157
158 return "http://localhost:" + connector.getPort();
159 }
160
161
162 @Override
163 protected void doStart() throws Exception
164 {
165 super.doStart();
166 if (_sendShutdownAtStart)
167 sendShutdown();
168 }
169
170 @Override
171 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
172 {
173 if (!target.equals("/shutdown"))
174 {
175 super.handle(target,baseRequest,request,response);
176 return;
177 }
178
179 if (!request.getMethod().equals("POST"))
180 {
181 response.sendError(HttpServletResponse.SC_BAD_REQUEST);
182 return;
183 }
184 if (!hasCorrectSecurityToken(request))
185 {
186 LOG.warn("Unauthorized tokenless shutdown attempt from " + request.getRemoteAddr());
187 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
188 return;
189 }
190 if (!requestFromLocalhost(baseRequest))
191 {
192 LOG.warn("Unauthorized non-loopback shutdown attempt from " + request.getRemoteAddr());
193 response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
194 return;
195 }
196
197 LOG.info("Shutting down by request from " + request.getRemoteAddr());
198 doShutdown(baseRequest, response);
199 }
200
201 protected void doShutdown(Request baseRequest, HttpServletResponse response) throws IOException
202 {
203 for (Connector connector : getServer().getConnectors())
204 {
205 connector.shutdown();
206 }
207
208 response.sendError(200, "Connectors closed, commencing full shutdown");
209 baseRequest.setHandled(true);
210
211 final Server server=getServer();
212 new Thread()
213 {
214 @Override
215 public void run ()
216 {
217 try
218 {
219 shutdownServer(server);
220 }
221 catch (InterruptedException e)
222 {
223 LOG.ignore(e);
224 }
225 catch (Exception e)
226 {
227 throw new RuntimeException("Shutting down server",e);
228 }
229 }
230 }.start();
231 }
232
233 private boolean requestFromLocalhost(Request request)
234 {
235 InetSocketAddress addr = request.getRemoteInetSocketAddress();
236 if (addr == null)
237 {
238 return false;
239 }
240 return addr.getAddress().isLoopbackAddress();
241 }
242
243 private boolean hasCorrectSecurityToken(HttpServletRequest request)
244 {
245 String tok = request.getParameter("token");
246 if (LOG.isDebugEnabled())
247 LOG.debug("Token: {}", tok);
248 return _shutdownToken.equals(tok);
249 }
250
251 private void shutdownServer(Server server) throws Exception
252 {
253 server.stop();
254
255 if (_exitJvm)
256 {
257 System.exit(0);
258 }
259 }
260
261 public void setExitJvm(boolean exitJvm)
262 {
263 this._exitJvm = exitJvm;
264 }
265
266 public boolean isSendShutdownAtStart()
267 {
268 return _sendShutdownAtStart;
269 }
270
271 public void setSendShutdownAtStart(boolean sendShutdownAtStart)
272 {
273 _sendShutdownAtStart = sendShutdownAtStart;
274 }
275
276 public String getShutdownToken()
277 {
278 return _shutdownToken;
279 }
280
281 public boolean isExitJvm()
282 {
283 return _exitJvm;
284 }
285
286 }