remm 01/09/26 10:44:51 Modified: catalina/src/share/org/apache/catalina/valves ErrorReportValve.java LocalStrings.properties Log: - Error report and dispatching refactoring. - New (and maybe fancier) error reports. - HTML code stolen from the Cocoon 2 error reports. - The only thing missing is the response reset code (which should not be response.reset, but something a bit smarter). Revision Changes Path 1.2 +192 -17 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java Index: ErrorReportValve.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ErrorReportValve.java 2001/09/25 22:11:49 1.1 +++ ErrorReportValve.java 2001/09/26 17:44:51 1.2 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java,v 1.1 2001/09/25 22:11:49 remm Exp $ - * $Revision: 1.1 $ - * $Date: 2001/09/25 22:11:49 $ + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java,v 1.2 2001/09/26 17:44:51 remm Exp $ + * $Revision: 1.2 $ + * $Date: 2001/09/26 17:44:51 $ * * ==================================================================== * @@ -66,6 +66,9 @@ import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; @@ -76,6 +79,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Container; +import org.apache.catalina.Globals; import org.apache.catalina.HttpRequest; import org.apache.catalina.HttpResponse; import org.apache.catalina.Logger; @@ -84,6 +88,7 @@ import org.apache.catalina.Valve; import org.apache.catalina.ValveContext; import org.apache.catalina.connector.HttpResponseWrapper; +import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.StringManager; @@ -92,10 +97,14 @@ * * <p>This Valve should be attached at the Host level, although it will work * if attached to a Context.</p> + * + * <p>HTML code from the Cocoon 2 project.</p> * * @author Remy Maucherat * @author Craig R. McClanahan - * @version $Revision: 1.1 $ $Date: 2001/09/25 22:11:49 $ + * @author <a href="mailto:[EMAIL PROTECTED]">Nicola Ken Barozzi</a> Aisa + * @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a> + * @version $Revision: 1.2 $ $Date: 2001/09/26 17:44:51 $ */ public class ErrorReportValve @@ -106,6 +115,12 @@ /** + * The debugging detail level for this component. + */ + private int debug = 0; + + + /** * The descriptive information related to this implementation. */ private static final String info = @@ -151,24 +166,42 @@ ValveContext context) throws IOException, ServletException { - // Skip logging for non-HTTP requests and responses - if (!(request instanceof HttpRequest) || - !(response instanceof HttpResponse)) { - context.invokeNext(request, response); - return; - } - HttpRequest hrequest = (HttpRequest) request; - HttpResponse hresponse = (HttpResponse) response; - HttpServletRequest hreq = - (HttpServletRequest) hrequest.getRequest(); - HttpServletResponse hres = - (HttpServletResponse) hresponse.getResponse(); - // Perform the request context.invokeNext(request, response); + ServletResponse sresp = response.getResponse(); + if (sresp.isCommitted()) + return; + + ServletRequest sreq = request.getRequest(); + Throwable throwable = + (Throwable) sreq.getAttribute(Globals.EXCEPTION_ATTR); + + if (throwable != null) { + + // The response is an error + response.setError(); + + // Reset the response (if possible) + try { + response.getResponse().reset(); + } catch (IllegalStateException e) { + ; + } + + ServletResponse sresponse = response.getResponse(); + if (sresponse instanceof HttpServletResponse) + ((HttpServletResponse) sresponse).sendError + (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + try { + report(request, response, throwable); + } catch (Throwable tt) { + tt.printStackTrace(); + } + } @@ -186,6 +219,148 @@ // ------------------------------------------------------ Protected Methods + + + /** + * Prints out an error report. + * + * @param request The request being processed + * @param response The response being generated + * @param exception The exception that occurred (which possibly wraps + * a root cause exception + */ + protected void report(Request request, Response response, + Throwable throwable) + throws IOException { + + // Do nothing on non-HTTP responses + if (!(response instanceof HttpResponse)) + return; + HttpResponse hresponse = (HttpResponse) response; + if (!(response.getResponse() instanceof HttpServletResponse)) + return; + HttpServletResponse hres = + (HttpServletResponse) response.getResponse(); + int statusCode = hresponse.getStatus(); + String message = RequestUtil.filter(hresponse.getMessage()); + if (message == null) + message = ""; + + // Do nothing on a 1xx status + if (statusCode < 200) + return; + // Do nothing on an OK status + if (statusCode == HttpServletResponse.SC_OK) + return; + // Do nothing on a NO MODIFIED status + if (statusCode == HttpServletResponse.SC_NOT_MODIFIED) + return; + // Do nothing on a NO CONTENT status + if (statusCode == HttpServletResponse.SC_NO_CONTENT) + return; + + // FIXME: Reset part of the request +/* + try { + if (hresponse.isError()) + hresponse.reset(statusCode, message); + } catch (IllegalStateException e) { + ; + } +*/ + + Throwable rootCause = null; + + if (throwable != null) { + + if (throwable instanceof ServletException) + rootCause = ((ServletException) throwable).getRootCause(); + + } + + // Do nothing if there is no report for the specified status code + String report = null; + try { + report = sm.getString("http." + statusCode, message); + } catch (Throwable t) { + ; + } + if (report == null) + return; + + try { + hres.setContentType("text/html"); + } catch (Throwable t) { + if (debug >= 1) + log("status.setContentType", t); + } + + StringBuffer sb = new StringBuffer(); + + sb.append("<html><head><title>"); + sb.append(Globals.SERVER_INFO).append(" - "); + sb.append(sm.getString("errorReportValve.errorReport")); + sb.append("</title>"); + sb.append("<STYLE><!--H1{font-family : sans-serif,Arial,Tahoma;color : white;background-color : #0086b2;} "); + sb.append("BODY{font-family : sans-serif,Arial,Tahoma;color : black;background-color : white;} "); + sb.append("B{color : white;background-color : #0086b2;} "); + sb.append("HR{color : #0086b2;} "); + sb.append("--></STYLE> "); + sb.append("</head><body>"); + sb.append("<h1>").append(Globals.SERVER_INFO).append(" - "); + sb.append(sm.getString("errorReportValve.statusHeader", + "" + statusCode, message)).append("</h1>"); + sb.append("<HR size=\"1\" noshade>"); + sb.append("<p><b>type</b> "); + if (throwable != null) { + sb.append(sm.getString("errorReportValve.exceptionReport")); + } else { + sb.append(sm.getString("errorReportValve.statusReport")); + } + sb.append("</p>"); + sb.append("<p><b>"); + sb.append(sm.getString("errorReportValve.message")); + sb.append("</b> <u>"); + sb.append(message).append("</u></p>"); + sb.append("<p><b>"); + sb.append(sm.getString("errorReportValve.description")); + sb.append("</b> <u>"); + sb.append(report); + sb.append("</u></p>"); + + if (throwable != null) { + StringWriter stackTrace = new StringWriter(); + throwable.printStackTrace(new PrintWriter(stackTrace)); + sb.append("<p><b>"); + sb.append(sm.getString("errorReportValve.exception")); + sb.append("</b> <pre>"); + sb.append(stackTrace.toString()); + sb.append("</pre></p>"); + if (rootCause != null) { + stackTrace = new StringWriter(); + rootCause.printStackTrace(new PrintWriter(stackTrace)); + sb.append("<p><b>"); + sb.append(sm.getString("errorReportValve.rootCause")); + sb.append("</b> <pre>"); + sb.append(stackTrace.toString()); + sb.append("</pre></p>"); + } + } + + sb.append("<HR size=\"1\" noshade>"); + sb.append("</body></html>"); + + try { + Writer writer = response.getReporter(); + writer.write(sb.toString()); + writer.flush(); + } catch (IOException e) { + ; + } catch (IllegalStateException e) { + ; + } + + } /** 1.3 +54 -0 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/valves/LocalStrings.properties Index: LocalStrings.properties =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/valves/LocalStrings.properties,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- LocalStrings.properties 2000/10/31 23:53:29 1.2 +++ LocalStrings.properties 2001/09/26 17:44:51 1.3 @@ -7,3 +7,57 @@ requestFilterValve.next=No 'next' valve has been configured requestFilterValve.syntax=Syntax error in request filter pattern {0} valveBase.noNext=Configuration error: No 'next' valve configured + +# Error report valve +errorReportValve.errorReport=Error report +errorReportValve.statusHeader=HTTP Status {0} - {1} +errorReportValve.exceptionReport=Exception report +errorReportValve.statusReport=Status report +errorReportValve.message=message +errorReportValve.description=description +errorReportValve.exception=exception +errorReportValve.rootCause=root cause + +# HTTP status reports +http.100=The client may continue ({0}). +http.101=The server is switching protocols according to the "Upgrade" header ({0}). +http.201=The request succeeded and a new resource ({0}) has been created on the server. +http.202=This request was accepted for processing, but has not been completed ({0}). +http.203=The meta information presented by the client did not originate from the server ({0}). +http.204=The request succeeded but there is no information to return ({0}). +http.205=The client should reset the document view which caused this request to be sent ({0}). +http.206=The server has fulfilled a partial GET request for this resource ({0}). +http.207=Multiple status values have been returned ({0}). +http.300=The requested resource ({0}) corresponds to any one of a set of representations, each with its own specific location. +http.301=The requested resource ({0}) has moved permanently to a new location. +http.302=The requested resource ({0}) has moved temporarily to a new location. +http.303=The response to this request can be found under a different URI ({0}). +http.304=The requested resource ({0}) is available and has not been modified. +http.305=The requested resource ({0}) must be accessed through the proxy given by the "Location" header. +http.400=The request sent by the client was syntactically incorrect ({0}). +http.401=This request requires HTTP authentication ({0}). +http.402=Payment is required for access to this resource ({0}). +http.403=Access to the specified resource ({0}) has been forbidden. +http.404=The requested resource ({0}) is not available. +http.405=The specified HTTP method is not allowed for the requested resource ({0}). +http.406=The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ({0}). +http.407=The client must first authenticate itself with the proxy ({0}). +http.408=The client did not produce a request within the time that the server was prepared to wait ({0}). +http.409=The request could not be completed due to a conflict with the current state of the resource ({0}). +http.410=The requested resource ({0}) is no longer available, and no forwarding address is known. +http.411=This request cannot be handled without a defined content length ({0}). +http.412=A specified precondition has failed for this request ({0}). +http.413=The request entity is larger than the server is willing or able to process. +http.414=The server refused this request because the request URI was too long ({0}). +http.415=The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ({0}). +http.416=The requested byte range cannot be satisfied ({0}). +http.417=The expectation given in the "Expect" request header ({0}) could not be fulfilled. +http.422=The server understood the content type and syntax of the request but was unable to process the contained instructions ({0}). +http.423=The source or destination resource of a method is locked ({0}). +http.500=The server encountered an internal error ({0}) that prevented it from fulfilling this request. +http.501=The server does not support the functionality needed to fulfill this request ({0}). +http.502=This server received an invalid response from a server it consulted when acting as a proxy or gateway ({0}). +http.503=The requested service ({0}) is not currently available. +http.504=The server received a timeout from an upstream server while acting as a gateway or proxy ({0}). +http.505=The server does not support the requested HTTP protocol version ({0}). +http.507=The resource does not have sufficient space to record the state of the resource after execution of this method ({0}).