/** * Handle the HTTP status code (and corresponding message) generated while processing the * specified Request to produce the specified Response. Any exceptions that occur during * generation of the error report are logged and swallowed. * * @param request The request being processed * @param response The response being generated */ private void status(Request request, Response response) { int statusCode = response.getStatus(); // Handle a custom error page for this status code Context context = request.getContext(); if (context == null) return; /* Only look for error pages when isError() is set. * isError() is set when response.sendError() is invoked. This * allows custom error pages without relying on default from * web.xml. */ if (!response.isError()) return; ErrorPage errorPage = context.findErrorPage(statusCode); if (errorPage == null) { // Look for a default error page errorPage = context.findErrorPage(0); } if (errorPage != null && response.setErrorReported()) { response.setAppCommitted(false); request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, Integer.valueOf(statusCode)); String message = response.getMessage(); if (message == null) message = ""; request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation()); request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR); Wrapper wrapper = request.getWrapper(); if (wrapper != null) request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName()); request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); if (custom(request, response, errorPage)) { try { response.finishResponse(); } catch (ClientAbortException e) { // Ignore } catch (IOException e) { container.getLogger().warn("Exception Processing " + errorPage, e); } } } }
private static ServletInfo getServletInfo(Wrapper wrapper, String contextName) { ServletInfo si = new ServletInfo(); si.setApplicationName(contextName.length() > 0 ? contextName : "/"); si.setServletName(wrapper.getName()); si.setServletClass(wrapper.getServletClass()); si.setAvailable(!wrapper.isUnavailable()); si.setLoadOnStartup(wrapper.getLoadOnStartup()); si.setRunAs(wrapper.getRunAs()); si.getMappings().addAll(Arrays.asList(wrapper.findMappings())); if (wrapper instanceof StandardWrapper) { StandardWrapper sw = (StandardWrapper) wrapper; si.setAllocationCount(sw.getCountAllocated()); si.setErrorCount(sw.getErrorCount()); si.setLoadTime(sw.getLoadTime()); si.setMaxInstances(sw.getMaxInstances()); si.setMaxTime(sw.getMaxTime()); si.setMinTime(sw.getMinTime() == Long.MAX_VALUE ? 0 : sw.getMinTime()); si.setProcessingTime(sw.getProcessingTime()); si.setRequestCount(sw.getRequestCount()); si.setSingleThreaded(sw.isSingleThreadModel()); } return si; }
/** * Handle the specified Throwable encountered while processing the specified Request to produce * the specified Response. Any exceptions that occur during generation of the exception report are * logged and swallowed. * * @param request The request being processed * @param response The response being generated * @param throwable The exception that occurred (which possibly wraps a root cause exception */ protected void throwable(Request request, Response response, Throwable throwable) { Context context = request.getContext(); if (context == null) return; Throwable realError = throwable; if (realError instanceof ServletException) { realError = ((ServletException) realError).getRootCause(); if (realError == null) { realError = throwable; } } // If this is an aborted request from a client just log it and return if (realError instanceof ClientAbortException) { if (log.isDebugEnabled()) { log.debug(sm.getString("standardHost.clientAbort", realError.getCause().getMessage())); } return; } ErrorPage errorPage = findErrorPage(context, throwable); if ((errorPage == null) && (realError != throwable)) { errorPage = findErrorPage(context, realError); } if (errorPage != null) { if (response.setErrorReported()) { response.setAppCommitted(false); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation()); request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR); request.setAttribute( RequestDispatcher.ERROR_STATUS_CODE, new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); request.setAttribute(RequestDispatcher.ERROR_MESSAGE, throwable.getMessage()); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, realError); Wrapper wrapper = request.getWrapper(); if (wrapper != null) request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName()); request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, realError.getClass()); if (custom(request, response, errorPage)) { try { response.finishResponse(); } catch (IOException e) { container.getLogger().warn("Exception Processing " + errorPage, e); } } } } else { // A custom error-page has not been defined for the exception // that was thrown during request processing. Check if an // error-page for error code 500 was specified and if so, // send that page back as the response. response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // The response is an error response.setError(); status(request, response); } }
/** * Serve the specified request, creating the corresponding response. After the first time a * particular servlet class is requested, it will be served directly (like any registered servlet) * because it will have been registered and mapped in our associated Context. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ public void serveRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Disallow calling this servlet via a named dispatcher if (request.getAttribute(Globals.NAMED_DISPATCHER_ATTR) != null) throw new ServletException(sm.getString("invokerServlet.notNamed")); // Identify the input parameters and our "included" state String inRequestURI = null; String inServletPath = null; String inPathInfo = null; boolean included = (request.getAttribute(Globals.REQUEST_URI_ATTR) != null); if (included) { inRequestURI = (String) request.getAttribute(Globals.REQUEST_URI_ATTR); inServletPath = (String) request.getAttribute(Globals.SERVLET_PATH_ATTR); inPathInfo = (String) request.getAttribute(Globals.PATH_INFO_ATTR); } else { inRequestURI = request.getRequestURI(); inServletPath = request.getServletPath(); inPathInfo = request.getPathInfo(); } if (debug >= 1) { log("included='" + included + "', requestURI='" + inRequestURI + "'"); log(" servletPath='" + inServletPath + "', pathInfo='" + inPathInfo + "'"); } // Make sure a servlet name or class name was specified if (inPathInfo == null) { if (debug >= 1) log("Invalid pathInfo '" + inPathInfo + "'"); if (included) throw new ServletException(sm.getString("invokerServlet.invalidPath", inRequestURI)); else { response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI); return; } } // Identify the outgoing servlet name or class, and outgoing path info String pathInfo = inPathInfo; String servletClass = pathInfo.substring(1); int slash = servletClass.indexOf('/'); // if (debug >= 2) // log(" Calculating with servletClass='" + servletClass + // "', pathInfo='" + pathInfo + "', slash=" + slash); if (slash >= 0) { pathInfo = servletClass.substring(slash); servletClass = servletClass.substring(0, slash); } else { pathInfo = ""; } if (servletClass.startsWith("org.apache.catalina")) { response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI); return; } if (debug >= 1) log("Processing servlet '" + servletClass + "' with path info '" + pathInfo + "'"); String name = "org.apache.catalina.INVOKER." + servletClass; String pattern = inServletPath + "/" + servletClass + "/*"; Wrapper wrapper = null; // Synchronize to avoid race conditions when multiple requests // try to initialize the same servlet at the same time synchronized (this) { // Are we referencing an existing servlet class or name? wrapper = (Wrapper) context.findChild(servletClass); if (wrapper == null) wrapper = (Wrapper) context.findChild(name); if (wrapper != null) { if (debug >= 1) log( "Using wrapper for servlet '" + wrapper.getName() + "' with mapping '" + pattern + "'"); context.addServletMapping(pattern, wrapper.getName()); } // No, create a new wrapper for the specified servlet class else { if (debug >= 1) log("Creating wrapper for '" + servletClass + "' with mapping '" + pattern + "'"); try { wrapper = context.createWrapper(); wrapper.setName(name); wrapper.setLoadOnStartup(1); wrapper.setServletClass(servletClass); context.addChild(wrapper); context.addServletMapping(pattern, name); } catch (Throwable t) { log(sm.getString("invokerServlet.cannotCreate", inRequestURI), t); context.removeServletMapping(pattern); context.removeChild(wrapper); if (included) throw new ServletException( sm.getString("invokerServlet.cannotCreate", inRequestURI), t); else { response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI); return; } } } } // Create a request wrapper to pass on to the invoked servlet InvokerHttpRequest wrequest = new InvokerHttpRequest(request); wrequest.setRequestURI(inRequestURI); StringBuffer sb = new StringBuffer(inServletPath); sb.append("/"); sb.append(servletClass); wrequest.setServletPath(sb.toString()); if ((pathInfo == null) || (pathInfo.length() < 1)) { wrequest.setPathInfo(null); wrequest.setPathTranslated(null); } else { wrequest.setPathInfo(pathInfo); wrequest.setPathTranslated(getServletContext().getRealPath(pathInfo)); } // Allocate a servlet instance to perform this request Servlet instance = null; try { // if (debug >= 2) // log(" Allocating servlet instance"); instance = wrapper.allocate(); } catch (ServletException e) { log(sm.getString("invokerServlet.allocate", inRequestURI), e); context.removeServletMapping(pattern); context.removeChild(wrapper); Throwable rootCause = e.getRootCause(); if (rootCause == null) rootCause = e; if (rootCause instanceof ClassNotFoundException) { response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI); return; } else if (rootCause instanceof IOException) { throw (IOException) rootCause; } else if (rootCause instanceof RuntimeException) { throw (RuntimeException) rootCause; } else if (rootCause instanceof ServletException) { throw (ServletException) rootCause; } else { throw new ServletException( sm.getString("invokerServlet.allocate", inRequestURI), rootCause); } } catch (Throwable e) { log(sm.getString("invokerServlet.allocate", inRequestURI), e); context.removeServletMapping(pattern); context.removeChild(wrapper); throw new ServletException(sm.getString("invokerServlet.allocate", inRequestURI), e); } // After loading the wrapper, restore some of the fields when including if (included) { wrequest.setRequestURI(request.getRequestURI()); wrequest.setPathInfo(request.getPathInfo()); wrequest.setServletPath(request.getServletPath()); } // Invoke the service() method of the allocated servlet try { String jspFile = wrapper.getJspFile(); if (jspFile != null) request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); else request.removeAttribute(Globals.JSP_FILE_ATTR); request.setAttribute(Globals.INVOKED_ATTR, request.getServletPath()); // if (debug >= 2) // log(" Calling service() method, jspFile=" + // jspFile); instance.service(wrequest, response); request.removeAttribute(Globals.INVOKED_ATTR); request.removeAttribute(Globals.JSP_FILE_ATTR); } catch (IOException e) { // if (debug >= 2) // log(" service() method IOException", e); request.removeAttribute(Globals.INVOKED_ATTR); request.removeAttribute(Globals.JSP_FILE_ATTR); try { wrapper.deallocate(instance); } catch (Throwable f) {; } throw e; } catch (UnavailableException e) { // if (debug >= 2) // log(" service() method UnavailableException", e); context.removeServletMapping(pattern); request.removeAttribute(Globals.INVOKED_ATTR); request.removeAttribute(Globals.JSP_FILE_ATTR); try { wrapper.deallocate(instance); } catch (Throwable f) {; } throw e; } catch (ServletException e) { // if (debug >= 2) // log(" service() method ServletException", e); request.removeAttribute(Globals.INVOKED_ATTR); request.removeAttribute(Globals.JSP_FILE_ATTR); try { wrapper.deallocate(instance); } catch (Throwable f) {; } throw e; } catch (RuntimeException e) { // if (debug >= 2) // log(" service() method RuntimeException", e); request.removeAttribute(Globals.INVOKED_ATTR); request.removeAttribute(Globals.JSP_FILE_ATTR); try { wrapper.deallocate(instance); } catch (Throwable f) {; } throw e; } catch (Throwable e) { // if (debug >= 2) // log(" service() method Throwable", e); request.removeAttribute(Globals.INVOKED_ATTR); request.removeAttribute(Globals.JSP_FILE_ATTR); try { wrapper.deallocate(instance); } catch (Throwable f) {; } throw new ServletException("Invoker service() exception", e); } // Deallocate the allocated servlet instance try { // if (debug >= 2) // log(" deallocate servlet instance"); wrapper.deallocate(instance); } catch (ServletException e) { log(sm.getString("invokerServlet.deallocate", inRequestURI), e); throw e; } catch (Throwable e) { log(sm.getString("invokerServlet.deallocate", inRequestURI), e); throw new ServletException(sm.getString("invokerServlet.deallocate", inRequestURI), e); } }