/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.catalina.core;
/** * Valve that implements the default basic behavior for the <code>StandardHost</code> container implementation. * <p> * <b>USAGE CONSTRAINT</b>: This implementation is likely to be useful only when processing HTTP requests. * * @author Craig R. McClanahan * @author Remy Maucherat
*/ finalclass StandardHostValve extends ValveBase {
privatestaticfinal Log log = LogFactory.getLog(StandardHostValve.class); privatestaticfinal StringManager sm = StringManager.getManager(StandardHostValve.class);
// Saves a call to getClassLoader() on very request. Under high load these // calls took just long enough to appear as a hot spot (although a very // minor one) in a profiler. privatestaticfinal ClassLoader MY_CLASSLOADER = StandardHostValve.class.getClassLoader();
// --------------------------------------------------------- Public Methods
/** * Select the appropriate child Context to process this request, based on the specified request URI. If no matching * Context can be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred
*/
@Override publicvoid invoke(Request request, Response response) throws IOException, ServletException {
// Select the Context to be used for this Request
Context context = request.getContext(); if (context == null) { // Don't overwrite an existing error if (!response.isError()) {
response.sendError(404);
} return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(context.getPipeline().isAsyncSupported());
}
if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) { // Don't fire listeners during async processing (the listener // fired for the request that called startAsync()). // If a request init listener throws an exception, the request // is aborted. return;
}
// Ask this Context to process this request. Requests that are // already in error must have been routed here to check for // application defined error pages so DO NOT forward them to the // application for processing. try { if (!response.isErrorReportRequired()) {
context.getPipeline().getFirst().invoke(request, response);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
container.getLogger().error("Exception Processing " + request.getRequestURI(), t); // If a new error occurred while trying to report a previous // error allow the original error to be reported. if (!response.isErrorReportRequired()) {
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
throwable(request, response, t);
}
}
// Now that the request/response pair is back under container // control lift the suspension so that the error handling can // complete and/or the container can flush any remaining data
response.setSuspended(false);
Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
// Protect against NPEs if the context was destroyed during a // long running request. if (!context.getState().isAvailable()) { return;
}
// Look for (and render if found) an application level error page if (response.isErrorReportRequired()) { // If an error has occurred that prevents further I/O, don't waste time // producing an error report that will never be read
AtomicBoolean result = new AtomicBoolean(false);
response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result); if (result.get()) { if (t != null) {
throwable(request, response, t);
} else {
status(request, response);
}
}
}
if (!request.isAsync() && !asyncAtStart) {
context.fireRequestDestroyEvent(request.getRequest());
}
} finally { // Access a session (if present) to update last accessed time, based // on a strict interpretation of the specification if (context.getAlwaysAccessSession()) {
request.getSession(false);
}
/** * 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
*/ privatevoid 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.isErrorReportRequired()) {
response.setAppCommitted(false);
request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, Integer.valueOf(statusCode));
/** * 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
*/
@SuppressWarnings("deprecation") protectedvoid 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;
}
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,
Integer.valueOf(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. * Set the status to 500 if an error status has not already been set and check for custom error-page for * the status.
*/ if (response.getStatus() < HttpServletResponse.SC_BAD_REQUEST) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} // The response is an error
response.setError();
status(request, response);
}
}
/** * Handle an HTTP status code or Java exception by forwarding control to the location included in the specified * errorPage object. It is assumed that the caller has already recorded any request attributes that are to be * forwarded to this page. Return <code>true</code> if we successfully utilized the specified error page location, * or <code>false</code> if the default error report should be rendered. * * @param request The request being processed * @param response The response being generated * @param errorPage The errorPage directive we are obeying
*/ privateboolean custom(Request request, Response response, ErrorPage errorPage) {
if (container.getLogger().isDebugEnabled()) {
container.getLogger().debug("Processing " + errorPage);
}
try { // Forward control to the specified location
ServletContext servletContext = request.getContext().getServletContext();
RequestDispatcher rd = servletContext.getRequestDispatcher(errorPage.getLocation());
if (rd == null) {
container.getLogger()
.error(sm.getString("standardHostValue.customStatusFailed", errorPage.getLocation())); returnfalse;
}
if (response.isCommitted()) { // Response is committed - including the error page is the // best we can do
rd.include(request.getRequest(), response.getResponse());
// Ensure the combined incomplete response and error page is // written to the client try {
response.flushBuffer();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
}
// Now close immediately as an additional signal to the client // that something went wrong
response.getCoyoteResponse().action(ActionCode.CLOSE_NOW,
request.getAttribute(RequestDispatcher.ERROR_EXCEPTION));
} else { // Reset the response (keeping the real error code and message)
response.resetBuffer(true);
response.setContentLength(-1);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.