View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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  
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  
26  import javax.servlet.ServletException;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  
30  import org.eclipse.jetty.http.HttpHeader;
31  import org.eclipse.jetty.http.HttpMethod;
32  import org.eclipse.jetty.http.HttpStatus;
33  import org.eclipse.jetty.http.MimeTypes;
34  import org.eclipse.jetty.server.Dispatcher;
35  import org.eclipse.jetty.server.Request;
36  import org.eclipse.jetty.server.Response;
37  import org.eclipse.jetty.util.ByteArrayISO8859Writer;
38  import org.eclipse.jetty.util.log.Log;
39  import org.eclipse.jetty.util.log.Logger;
40  
41  /* ------------------------------------------------------------ */
42  /** Handler for Error pages
43   * An ErrorHandler is registered with {@link ContextHandler#setErrorHandler(ErrorHandler)} or
44   * {@link org.eclipse.jetty.server.Server#addBean(Object)}.
45   * It is called by the HttpResponse.sendError method to write a error page.
46   *
47   */
48  public class ErrorHandler extends AbstractHandler
49  {    
50      private static final Logger LOG = Log.getLogger(ErrorHandler.class);
51      public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
52      
53      boolean _showStacks=true;
54      boolean _showMessageInTitle=true;
55      String _cacheControl="must-revalidate,no-cache,no-store";
56  
57      /* ------------------------------------------------------------ */
58      /*
59       * @see org.eclipse.jetty.server.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
60       */
61      @Override
62      public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
63      {
64          String method = request.getMethod();
65          if (!HttpMethod.GET.is(method) && !HttpMethod.POST.is(method) && !HttpMethod.HEAD.is(method))
66          {
67              baseRequest.setHandled(true);
68              return;
69          }
70          
71          if (this instanceof ErrorPageMapper)
72          {
73              String error_page=((ErrorPageMapper)this).getErrorPage(request);
74              if (error_page!=null && request.getServletContext()!=null)
75              {
76                  String old_error_page=(String)request.getAttribute(ERROR_PAGE);
77                  if (old_error_page==null || !old_error_page.equals(error_page))
78                  {
79                      request.setAttribute(ERROR_PAGE, error_page);
80  
81                      Dispatcher dispatcher = (Dispatcher) request.getServletContext().getRequestDispatcher(error_page);
82                      try
83                      {
84                          if(dispatcher!=null)
85                          {
86                              dispatcher.error(request, response);
87                              return;
88                          }
89                          LOG.warn("No error page "+error_page);
90                      }
91                      catch (ServletException e)
92                      {
93                          LOG.warn(Log.EXCEPTION, e);
94                          return;
95                      }
96                  }
97              }
98          }
99          
100         baseRequest.setHandled(true);
101         response.setContentType(MimeTypes.Type.TEXT_HTML_8859_1.asString());    
102         if (_cacheControl!=null)
103             response.setHeader(HttpHeader.CACHE_CONTROL.asString(), _cacheControl);
104         ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(4096);
105         String reason=(response instanceof Response)?((Response)response).getReason():null;
106         handleErrorPage(request, writer, response.getStatus(), reason);
107         writer.flush();
108         response.setContentLength(writer.size());
109         writer.writeTo(response.getOutputStream());
110         writer.destroy();
111     }
112 
113     /* ------------------------------------------------------------ */
114     protected void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message)
115         throws IOException
116     {
117         writeErrorPage(request, writer, code, message, _showStacks);
118     }
119 
120     /* ------------------------------------------------------------ */
121     protected void writeErrorPage(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks)
122         throws IOException
123     {
124         if (message == null)
125             message=HttpStatus.getMessage(code);
126 
127         writer.write("<html>\n<head>\n");
128         writeErrorPageHead(request,writer,code,message);
129         writer.write("</head>\n<body>");
130         writeErrorPageBody(request,writer,code,message,showStacks);
131         writer.write("\n</body>\n</html>\n");
132     }
133 
134     /* ------------------------------------------------------------ */
135     protected void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message)
136         throws IOException
137         {
138         writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>\n");
139         writer.write("<title>Error ");
140         writer.write(Integer.toString(code));
141 
142         if (_showMessageInTitle)
143         {
144             writer.write(' ');
145             write(writer,message);
146         }
147         writer.write("</title>\n");
148     }
149 
150     /* ------------------------------------------------------------ */
151     protected void writeErrorPageBody(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks)
152         throws IOException
153     {
154         String uri= request.getRequestURI();
155 
156         writeErrorPageMessage(request,writer,code,message,uri);
157         if (showStacks)
158             writeErrorPageStacks(request,writer);
159         writer.write("<hr><i><small>Powered by Jetty://</small></i><hr/>\n");
160     }
161 
162     /* ------------------------------------------------------------ */
163     protected void writeErrorPageMessage(HttpServletRequest request, Writer writer, int code, String message,String uri)
164     throws IOException
165     {
166         writer.write("<h2>HTTP ERROR ");
167         writer.write(Integer.toString(code));
168         writer.write("</h2>\n<p>Problem accessing ");
169         write(writer,uri);
170         writer.write(". Reason:\n<pre>    ");
171         write(writer,message);
172         writer.write("</pre></p>");
173     }
174 
175     /* ------------------------------------------------------------ */
176     protected void writeErrorPageStacks(HttpServletRequest request, Writer writer)
177         throws IOException
178     {
179         Throwable th = (Throwable)request.getAttribute("javax.servlet.error.exception");
180         while(th!=null)
181         {
182             writer.write("<h3>Caused by:</h3><pre>");
183             StringWriter sw = new StringWriter();
184             PrintWriter pw = new PrintWriter(sw);
185             th.printStackTrace(pw);
186             pw.flush();
187             write(writer,sw.getBuffer().toString());
188             writer.write("</pre>\n");
189 
190             th =th.getCause();
191         }
192     }
193 
194 
195     /* ------------------------------------------------------------ */
196     /** Get the cacheControl.
197      * @return the cacheControl header to set on error responses.
198      */
199     public String getCacheControl()
200     {
201         return _cacheControl;
202     }
203 
204     /* ------------------------------------------------------------ */
205     /** Set the cacheControl.
206      * @param cacheControl the cacheControl header to set on error responses.
207      */
208     public void setCacheControl(String cacheControl)
209     {
210         _cacheControl = cacheControl;
211     }
212 
213     /* ------------------------------------------------------------ */
214     /**
215      * @return True if stack traces are shown in the error pages
216      */
217     public boolean isShowStacks()
218     {
219         return _showStacks;
220     }
221 
222     /* ------------------------------------------------------------ */
223     /**
224      * @param showStacks True if stack traces are shown in the error pages
225      */
226     public void setShowStacks(boolean showStacks)
227     {
228         _showStacks = showStacks;
229     }
230 
231     /* ------------------------------------------------------------ */
232     /**
233      * @param showMessageInTitle if true, the error message appears in page title
234      */
235     public void setShowMessageInTitle(boolean showMessageInTitle)
236     {
237         _showMessageInTitle = showMessageInTitle;
238     }
239 
240 
241     /* ------------------------------------------------------------ */
242     public boolean getShowMessageInTitle()
243     {
244         return _showMessageInTitle;
245     }
246 
247     /* ------------------------------------------------------------ */
248     protected void write(Writer writer,String string)
249         throws IOException
250     {
251         if (string==null)
252             return;
253 
254         for (int i=0;i<string.length();i++)
255         {
256             char c=string.charAt(i);
257 
258             switch(c)
259             {
260                 case '&' :
261                     writer.write("&amp;");
262                     break;
263                 case '<' :
264                     writer.write("&lt;");
265                     break;
266                 case '>' :
267                     writer.write("&gt;");
268                     break;
269 
270                 default:
271                     if (Character.isISOControl(c) && !Character.isWhitespace(c))
272                         writer.write('?');
273                     else
274                         writer.write(c);
275             }
276         }
277     }
278 
279     /* ------------------------------------------------------------ */
280     public interface ErrorPageMapper
281     {
282         String getErrorPage(HttpServletRequest request);
283     }
284 }