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.io.PrintWriter;
23 import java.io.StringWriter;
24 import java.io.Writer;
25 import java.nio.ByteBuffer;
26 import java.nio.charset.Charset;
27 import java.nio.charset.StandardCharsets;
28 import java.util.List;
29
30 import javax.servlet.RequestDispatcher;
31 import javax.servlet.ServletException;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34
35 import org.eclipse.jetty.http.HttpFields;
36 import org.eclipse.jetty.http.HttpHeader;
37 import org.eclipse.jetty.http.HttpMethod;
38 import org.eclipse.jetty.http.HttpStatus;
39 import org.eclipse.jetty.http.MimeTypes;
40 import org.eclipse.jetty.server.Dispatcher;
41 import org.eclipse.jetty.server.Request;
42 import org.eclipse.jetty.server.Server;
43 import org.eclipse.jetty.util.BufferUtil;
44 import org.eclipse.jetty.util.StringUtil;
45 import org.eclipse.jetty.util.log.Log;
46 import org.eclipse.jetty.util.log.Logger;
47
48
49
50
51
52
53
54
55
56 public class ErrorHandler extends AbstractHandler
57 {
58 private static final Logger LOG = Log.getLogger(ErrorHandler.class);
59 public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
60
61 boolean _showStacks=true;
62 boolean _showMessageInTitle=true;
63 String _cacheControl="must-revalidate,no-cache,no-store";
64
65
66
67
68
69 @Override
70 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
71 {
72 String method = request.getMethod();
73 if (!HttpMethod.GET.is(method) && !HttpMethod.POST.is(method) && !HttpMethod.HEAD.is(method))
74 {
75 baseRequest.setHandled(true);
76 return;
77 }
78
79 if (this instanceof ErrorPageMapper)
80 {
81 String error_page=((ErrorPageMapper)this).getErrorPage(request);
82 if (error_page!=null && request.getServletContext()!=null)
83 {
84 String old_error_page=(String)request.getAttribute(ERROR_PAGE);
85 if (old_error_page==null || !old_error_page.equals(error_page))
86 {
87 request.setAttribute(ERROR_PAGE, error_page);
88
89 Dispatcher dispatcher = (Dispatcher) request.getServletContext().getRequestDispatcher(error_page);
90 try
91 {
92 if(dispatcher!=null)
93 {
94 dispatcher.error(request, response);
95 return;
96 }
97 LOG.warn("No error page "+error_page);
98 }
99 catch (ServletException e)
100 {
101 LOG.warn(Log.EXCEPTION, e);
102 return;
103 }
104 }
105 }
106 else
107 {
108 if (LOG.isDebugEnabled())
109 {
110 LOG.debug("No Error Page mapping for request({} {}) (using default)",request.getMethod(),request.getRequestURI());
111 }
112 }
113 }
114
115 if (_cacheControl != null)
116 response.setHeader(HttpHeader.CACHE_CONTROL.asString(), _cacheControl);
117 generateAcceptableResponse(baseRequest,request,response,response.getStatus(),baseRequest.getResponse().getReason());
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132 protected void generateAcceptableResponse(Request baseRequest, HttpServletRequest request, HttpServletResponse response, int code, String message)
133 throws IOException
134 {
135 List<String> acceptable=baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT);
136
137 if (acceptable.isEmpty() && !baseRequest.getHttpFields().contains(HttpHeader.ACCEPT))
138 generateAcceptableResponse(baseRequest,request,response,code,message,MimeTypes.Type.TEXT_HTML.asString());
139 else
140 {
141 for (String mimeType:acceptable)
142 {
143 generateAcceptableResponse(baseRequest,request,response,code,message,mimeType);
144 if (baseRequest.isHandled())
145 return;
146 }
147 }
148 baseRequest.setHandled(true);
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 protected Writer getAcceptableWriter(Request baseRequest, HttpServletRequest request, HttpServletResponse response)
169 throws IOException
170 {
171 List<String> acceptable=baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT_CHARSET);
172 if (acceptable.isEmpty())
173 {
174 response.setCharacterEncoding(StandardCharsets.ISO_8859_1.name());
175 return response.getWriter();
176 }
177
178 for (String charset:acceptable)
179 {
180 try
181 {
182 if ("*".equals(charset))
183 response.setCharacterEncoding(StandardCharsets.UTF_8.name());
184 else
185 response.setCharacterEncoding(Charset.forName(charset).name());
186 return response.getWriter();
187 }
188 catch(Exception e)
189 {
190 LOG.ignore(e);
191 }
192 }
193 return null;
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207
208 protected void generateAcceptableResponse(Request baseRequest, HttpServletRequest request, HttpServletResponse response, int code, String message, String mimeType)
209 throws IOException
210 {
211 switch(mimeType)
212 {
213 case "text/html":
214 case "text/*":
215 case "*/*":
216 {
217 baseRequest.setHandled(true);
218 Writer writer = getAcceptableWriter(baseRequest,request,response);
219 if (writer!=null)
220 {
221 response.setContentType(MimeTypes.Type.TEXT_HTML.asString());
222 handleErrorPage(request, writer, code, message);
223 }
224 }
225 }
226 }
227
228
229 protected void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message)
230 throws IOException
231 {
232 writeErrorPage(request, writer, code, message, _showStacks);
233 }
234
235
236 protected void writeErrorPage(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks)
237 throws IOException
238 {
239 if (message == null)
240 message=HttpStatus.getMessage(code);
241
242 writer.write("<html>\n<head>\n");
243 writeErrorPageHead(request,writer,code,message);
244 writer.write("</head>\n<body>");
245 writeErrorPageBody(request,writer,code,message,showStacks);
246 writer.write("\n</body>\n</html>\n");
247 }
248
249
250 protected void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message)
251 throws IOException
252 {
253 writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n");
254 writer.write("<title>Error ");
255 writer.write(Integer.toString(code));
256
257 if (_showMessageInTitle)
258 {
259 writer.write(' ');
260 write(writer,message);
261 }
262 writer.write("</title>\n");
263 }
264
265
266 protected void writeErrorPageBody(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks)
267 throws IOException
268 {
269 String uri= request.getRequestURI();
270
271 writeErrorPageMessage(request,writer,code,message,uri);
272 if (showStacks)
273 writeErrorPageStacks(request,writer);
274
275 Request.getBaseRequest(request).getHttpChannel().getHttpConfiguration()
276 .writePoweredBy(writer,"<hr>","<hr/>\n");
277 }
278
279
280 protected void writeErrorPageMessage(HttpServletRequest request, Writer writer, int code, String message,String uri)
281 throws IOException
282 {
283 writer.write("<h2>HTTP ERROR ");
284 writer.write(Integer.toString(code));
285 writer.write("</h2>\n<p>Problem accessing ");
286 write(writer,uri);
287 writer.write(". Reason:\n<pre> ");
288 write(writer,message);
289 writer.write("</pre></p>");
290 }
291
292
293 protected void writeErrorPageStacks(HttpServletRequest request, Writer writer)
294 throws IOException
295 {
296 Throwable th = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
297 while(th!=null)
298 {
299 writer.write("<h3>Caused by:</h3><pre>");
300 StringWriter sw = new StringWriter();
301 PrintWriter pw = new PrintWriter(sw);
302 th.printStackTrace(pw);
303 pw.flush();
304 write(writer,sw.getBuffer().toString());
305 writer.write("</pre>\n");
306
307 th =th.getCause();
308 }
309 }
310
311
312
313
314
315
316
317
318
319
320
321
322
323 public ByteBuffer badMessageError(int status, String reason, HttpFields fields)
324 {
325 if (reason==null)
326 reason=HttpStatus.getMessage(status);
327 fields.put(HttpHeader.CONTENT_TYPE,MimeTypes.Type.TEXT_HTML_8859_1.asString());
328 return BufferUtil.toBuffer("<h1>Bad Message " + status + "</h1><pre>reason: " + reason + "</pre>");
329 }
330
331
332
333
334
335 public String getCacheControl()
336 {
337 return _cacheControl;
338 }
339
340
341
342
343
344 public void setCacheControl(String cacheControl)
345 {
346 _cacheControl = cacheControl;
347 }
348
349
350
351
352
353 public boolean isShowStacks()
354 {
355 return _showStacks;
356 }
357
358
359
360
361
362 public void setShowStacks(boolean showStacks)
363 {
364 _showStacks = showStacks;
365 }
366
367
368
369
370
371 public void setShowMessageInTitle(boolean showMessageInTitle)
372 {
373 _showMessageInTitle = showMessageInTitle;
374 }
375
376
377
378 public boolean getShowMessageInTitle()
379 {
380 return _showMessageInTitle;
381 }
382
383
384 protected void write(Writer writer,String string)
385 throws IOException
386 {
387 if (string==null)
388 return;
389
390 writer.write(StringUtil.sanitizeXmlString(string));
391 }
392
393
394 public interface ErrorPageMapper
395 {
396 String getErrorPage(HttpServletRequest request);
397 }
398
399
400 public static ErrorHandler getErrorHandler(Server server, ContextHandler context)
401 {
402 ErrorHandler error_handler=null;
403 if (context!=null)
404 error_handler=context.getErrorHandler();
405 if (error_handler==null && server!=null)
406 error_handler = server.getBean(ErrorHandler.class);
407 return error_handler;
408 }
409 }