|
What this is
Other links
The source code/* * Copyright 1999-2004 The Apache Sofware Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.tomcat.modules.generators; import java.io.IOException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; import org.apache.tomcat.core.BaseInterceptor; import org.apache.tomcat.core.Context; import org.apache.tomcat.core.ContextManager; import org.apache.tomcat.core.Handler; import org.apache.tomcat.core.Request; import org.apache.tomcat.core.Response; import org.apache.tomcat.core.TomcatException; import org.apache.tomcat.util.http.HttpMessages; import org.apache.tomcat.util.http.LocaleToCharsetMap; import org.apache.tomcat.util.log.Log; import org.apache.tomcat.util.qlog.Logger; import org.apache.tomcat.util.res.StringManager; /** * Handle errors - this is the default handler, you can replace it * with customized versions * * @author Costin Manolache */ public final class ErrorHandler extends BaseInterceptor { private Context rootContext=null; boolean showDebugInfo=true; int defaultRedirectStatus=301; public ErrorHandler() { } public void setShowDebugInfo( boolean b ) { showDebugInfo=b; } public void setDefaultRedirectStatus( String s ) { if( "302".equals(s) ) defaultRedirectStatus=302; else if( "301".equals(s) ) defaultRedirectStatus=301; else defaultRedirectStatus=301; } public void engineInit(ContextManager cm ) { } /** Check that we are in a stable state. */ public void engineStart(ContextManager cm ) throws TomcatException { /* It is very possible to configure Tomcat without a rootContext. We make certain here that the rootContext is set. Note that we can't add the context, since we don't have a docRoot. This one is only used for error handling. If somebody subsequently adds a default context, then this one just harmlessly goes to gc (since it's not part of the app, we don't have to follow Life Cycle) */ if(rootContext == null){ rootContext = cm.createContext(); rootContext.setContextManager(cm); rootContext.setPath(""); contextInit(rootContext); } } /** Add default error handlers */ public void contextInit( Context ctx) throws TomcatException { if( ctx.getHost() == null && ctx.getPath().equals("")) rootContext = ctx; ContextManager cm=ctx.getContextManager(); String dI=cm.getProperty( "showDebugInfo" ); if( dI!=null && ( dI.equalsIgnoreCase("no") || dI.equalsIgnoreCase("false"))) { showDebugInfo=false; } // override with per/context setting dI=ctx.getProperty( "showDebugInfo" ); if( dI!=null && ( dI.equalsIgnoreCase("no") || dI.equalsIgnoreCase("false"))) { showDebugInfo=false; } if( dI!=null && ( dI.equalsIgnoreCase("yes") || dI.equalsIgnoreCase("true"))) { showDebugInfo=true; } ctx.addServlet( new ExceptionHandler(this, showDebugInfo)); ctx.addServlet( new StatusHandler(this, showDebugInfo)); // Default status handlers // Assume existing error pages are valid. Don't overwrite with default. RedirectHandler rh = new RedirectHandler(this); rh.setDefaultRedirectStatus(defaultRedirectStatus); ctx.addServlet( rh ); if (ctx.getErrorPage("302") == null) ctx.addErrorPage( "302", "tomcat.redirectHandler"); if (ctx.getErrorPage("301") == null) ctx.addErrorPage( "301", "tomcat.redirectHandler"); ctx.addServlet( new NotFoundHandler(this, showDebugInfo)); if (ctx.getErrorPage("404") == null) ctx.addErrorPage( "404", "tomcat.notFoundHandler"); if( debug > 0 ) log( "Init " + ctx + " " + showDebugInfo); } public int handleError( Request req, Response res, Throwable t ) { ContextManager cm=req.getContextManager(); Context ctx = req.getContext(); if(ctx==null) { // that happens only if the request can't pass contextMap // hook. The reason for that is a malformed request, or any // other error. ctx=rootContext; } if( debug > 0 ) log( "In error handler " +t ); if( t==null ) { handleStatusImpl( cm, ctx, req, res, res.getStatus() ); } else { handleErrorImpl( cm, ctx, req, res, t ); } return 200; } // -------------------- Implementation of handleError // Originally in ContextManager. private final void handleStatusImpl( ContextManager cm, Context ctx, Request req, Response res, int code ) { String errorPath=null; Handler errorServlet=null; // don't log normal cases ( redirect and need_auth ), they are not // error // XXX this log was intended to debug the status code generation. // it can be removed for all cases. if( code > 401 ) {// tuneme if( ctx==null ) cm.log( "Status code:" + code + " request:" + req + " msg:" + req.getAttribute("javax.servlet.error.message")); else ctx.log( "Status code:" + code + " request:" + req + " msg:" + req.getAttribute("javax.servlet.error.message")); } errorPath = ctx.getErrorPage( code ); if( errorPath != null ) { errorServlet=getHandlerForPath( cm, ctx, errorPath ); String cpath=ctx.getPath(); if( "/".equals(cpath)) cpath=""; // Make sure Jsps will work - needed if the error page is a jsp if ( null!=errorPath && errorPath.startsWith("/") ) { req.setAttribute( "javax.servlet.include.request_uri", cpath + errorPath ); } else { req.setAttribute( "javax.servlet.include.request_uri", cpath + "/" + errorPath ); } req.setAttribute( "javax.servlet.include.servlet_path", errorPath ); } boolean isDefaultHandler = false; if ( statusLoop( ctx, req, code ) ){ log( "Error loop for " + req + " error code " + code); return; } if( errorServlet==null ) { if( code == 404 ) errorServlet=ctx.getServletByName( "tomcat.notFoundHandler"); else errorServlet=ctx.getServletByName( "tomcat.statusHandler"); isDefaultHandler = true; } if (errorServlet == null) { ctx.log( "Handler errorServlet is null! errorPath:" + errorPath); return; } // XXX The original code didn't reset the buffer if // isDefaultHandler : if (!isDefaultHandler && ... // Is there any reason for that ? // I also think we should reset the buffer anyway, to get // in a stable state - even if the buffer is commited if ( !res.isBufferCommitted()) res.resetBuffer(); req.setAttribute("javax.servlet.error.status_code",new Integer( code)); req.setAttribute("tomcat.servlet.error.request", req); if( debug>0 ) ctx.log( "Handler " + errorServlet + " " + errorPath); // reset error exception res.setErrorException( null ); Exception ex=null; try { errorServlet.service( req, res ); ex=res.getErrorException(); } catch (Exception ex1 ) { ex=ex1; } if( ex!=null && ! (ex instanceof IOException) ) { // we can ignore IOException - probably the user // has clicked "STOP" // we need to log any other error - something may be // broken if the error servlet has errors. ctx.log( "Error in default status handler", ex); } } // XXX XXX Security - we should log the message, but nothing // should show up to the user - it gives up information // about the internal system ! // Developers can/should use the logs !!! /** General error handling mechanism. It will try to find an error handler * or use the default handler. */ void handleErrorImpl( ContextManager cm, Context ctx, Request req, Response res , Throwable t ) { if( debug>0 ) log( "Handle error in " + req + " " + t.getMessage() ); /** The exception must be available to the user. Note that it is _WRONG_ to send the trace back to the client. AFAIK the trace is the _best_ debugger. */ if( t instanceof IllegalStateException ) { ctx.log("IllegalStateException in " + req, t); // Nothing special in jasper exception treatement, no deps //} else if( t instanceof org.apache.jasper.JasperException ) { // ctx.log("JasperException in " + req, t); } else if( t instanceof IOException ) { if( "Broken pipe".equals(t.getMessage())) { ctx.log("Broken pipe in " + req, t, Log.DEBUG); // tuneme return; } if( "Connection reset by peer".equals(t.getMessage())) { ctx.log("Connection reset by peer in " + req, t, Log.DEBUG); // tuneme return; } ctx.log("IOException in " + req, t ); } else { ctx.log("Exception in " + req , t ); } if(null!=req.getAttribute("tomcat.servlet.error.defaultHandler")){ // we are in handleRequest for the "default" error handler log("ERROR: can't find default error handler, or error in default error page", t); } String errorPath=null; Handler errorServlet=null; // Scan the exception's inheritance tree looking for a rule // that this type of exception should be forwarded Class clazz = t.getClass(); while (errorPath == null && clazz != null) { String name = clazz.getName(); errorPath = ctx.getErrorPage(name); clazz = clazz.getSuperclass(); } // Bug 3233, ps@psncc.at (Peter Stamfest) if (errorPath == null ) { // Use introspection - the error handler is at a lower level, // doesn't depend on servlet api Throwable t2=null; try { Method m=t.getClass().getMethod( "getRootCause", new Class[] {} ); t2 = (Throwable)m.invoke( t, new Object[] {} ); } catch(Exception ex) { } if (t2 != null) { clazz = t2.getClass(); while (errorPath == null && clazz != null) { String name = clazz.getName(); errorPath = ctx.getErrorPage(name); clazz = clazz.getSuperclass(); } } if (errorPath != null) t = t2; } if( errorPath != null ) { errorServlet=getHandlerForPath( cm, ctx, errorPath ); String cpath=ctx.getPath(); if( "/".equals( cpath )) cpath=""; // Make sure Jsps will work - needed if the error page is a jsp if ( null!=errorPath && errorPath.startsWith("/") ) { req.setAttribute( "javax.servlet.include.request_uri", cpath + errorPath ); } else { req.setAttribute( "javax.servlet.include.request_uri", cpath + "/" + errorPath ); } req.setAttribute( "javax.servlet.include.servlet_path", errorPath ); } boolean isDefaultHandler = false; if ( errorLoop( ctx, req ) ){ log( "Error loop for " + req + " error " + t); return; } if ( errorServlet==null) { errorServlet = ctx.getServletByName("tomcat.exceptionHandler"); isDefaultHandler = true; if( debug>0 ) ctx.log( "Using default handler " + errorServlet ); } if (errorServlet == null) { ctx.log( "Handler errorServlet is null! errorPath:" + errorPath); return; } // XXX The original code didn't reset the buffer if // isDefaultHandler : if (!isDefaultHandler && ... // Is there any reason for that ? // I also think we should reset the buffer anyway, to get // in a stable state - even if the buffer is commited if ( !res.isBufferCommitted()) res.resetBuffer(); req.setAttribute("javax.servlet.error.exception_type", t.getClass()); req.setAttribute("javax.servlet.error.message", t.getMessage()); req.setAttribute("javax.servlet.jsp.jspException", t); req.setAttribute("tomcat.servlet.error.throwable", t); req.setAttribute("tomcat.servlet.error.request", req); if( debug>0 ) ctx.log( "Handler " + errorServlet + " " + errorPath); // reset error exception res.setErrorException( null ); Exception ex=null; try { errorServlet.service( req, res ); ex=res.getErrorException(); } catch(Exception ex1 ) { ex=ex1; } if( ex!=null && ! (ex instanceof IOException) ) { // we can ignore IOException - probably the user // has clicked "STOP" // we need to log any other error - something may be // broken if the error servlet has errors. ctx.log( "Error in errorServlet: ", ex); } } public final Handler getHandlerForPath( ContextManager cm, Context ctx, String path ) { if( ! path.startsWith( "/" ) ) { return ctx.getServletByName( path ); } Request req1=cm.createRequest(ctx, path); cm.processRequest( req1 ); return req1.getHandler(); } /** Handle the case of error handler generating an error or special status */ private boolean errorLoop( Context ctx, Request req ) { if( req.getAttribute("javax.servlet.error.status_code") != null || req.getAttribute("javax.servlet.error.exception_type")!=null) { if( ctx.getDebug() > 0 ) ctx.log( "Error: exception inside exception servlet " + req.getAttribute("javax.servlet.error.status_code") + " " + req. getAttribute("javax.servlet.error.exception_type")); return true; } return false; } /** Handle the case of status handler generating an error */ private boolean statusLoop( Context ctx, Request req, int newCode ) { Integer lastCode = (Integer)req.getAttribute("javax.servlet.error.status_code"); // If status code repeated, assume recursive loop if ( lastCode != null && lastCode.intValue() == newCode) { if( ctx.getDebug() > 0 ) ctx.log( "Error: nested error inside status servlet " + newCode); return true; } return false; } } class NotFoundHandler extends Handler { static StringManager sm=StringManager. getManager("org.apache.tomcat.resources"); int sbNote=0; boolean showDebugInfo=true; NotFoundHandler(BaseInterceptor bi, boolean showDebugInfo) { // setOrigin( Handler.ORIGIN_INTERNAL ); name="tomcat.notFoundHandler"; setModule(bi); this.showDebugInfo=showDebugInfo; } public void doService(Request req, Response res) throws Exception { String msg=(String)req.getAttribute("javax.servlet.error.message"); String charset = LocaleToCharsetMap.getCharset(Locale.getDefault()); if (charset == null) { res.setContentType("text/html"); } else { res.setContentType("text/html; charset=" + charset); res.setUsingWriter(true); } // "javax.servlet.include.request_uri" is set to this handler String requestURI = req.requestURI().toString(); if( sbNote==0 ) { sbNote=req.getContextManager().getNoteId(ContextManager.REQUEST_NOTE, "NotFoundHandler.buff"); } // we can recycle it because // we don't call toString(); StringBuffer buf=(StringBuffer)req.getNote( sbNote ); if( buf==null ) { buf = new StringBuffer(); req.setNote( sbNote, buf ); } boolean needsHead = res.getBuffer().isNew(); // only include ... if reset was successful if (needsHead) { buf.append(" |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.