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 for (Connector connector : getServer().getConnectors()) {
203 connector.shutdown();
204 }
205
206 response.sendError(200, "Connectors closed, commencing full shutdown");
207 baseRequest.setHandled(true);
208
209 final Server server=getServer();
210 new Thread()
211 {
212 @Override
213 public void run ()
214 {
215 try
216 {
217 shutdownServer(server);
218 }
219 catch (InterruptedException e)
220 {
221 LOG.ignore(e);
222 }
223 catch (Exception e)
224 {
225 throw new RuntimeException("Shutting down server",e);
226 }
227 }
228 }.start();
229 }
230
231 private boolean requestFromLocalhost(Request request)
232 {
233 InetSocketAddress addr = request.getRemoteInetSocketAddress();
234 if (addr == null)
235 {
236 return false;
237 }
238 return addr.getAddress().isLoopbackAddress();
239 }
240
241 private boolean hasCorrectSecurityToken(HttpServletRequest request)
242 {
243 String tok = request.getParameter("token");
244 if (LOG.isDebugEnabled())
245 LOG.debug("Token: {}", tok);
246 return _shutdownToken.equals(tok);
247 }
248
249 private void shutdownServer(Server server) throws Exception
250 {
251 server.stop();
252
253 if (_exitJvm)
254 {
255 System.exit(0);
256 }
257 }
258
259 public void setExitJvm(boolean exitJvm)
260 {
261 this._exitJvm = exitJvm;
262 }
263
264 public boolean isSendShutdownAtStart()
265 {
266 return _sendShutdownAtStart;
267 }
268
269 public void setSendShutdownAtStart(boolean sendShutdownAtStart)
270 {
271 _sendShutdownAtStart = sendShutdownAtStart;
272 }
273
274 public String getShutdownToken()
275 {
276 return _shutdownToken;
277 }
278
279 public boolean isExitJvm()
280 {
281 return _exitJvm;
282 }
283
284 }