From: markt Date: Thu, 3 Jun 2010 15:00:11 +0000 (+0000) Subject: Refactor the hooks from the CoyoteAdapter to the access logs X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=5a9e2dccfaf750f613f5709654063dcb64a3ea00;p=tomcat7.0 Refactor the hooks from the CoyoteAdapter to the access logs - cleaner interface - handles AccessLogs at multiple levels (but not multiple AccessLogs per container) git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@951018 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/catalina/AccessLog.java b/java/org/apache/catalina/AccessLog.java index fc9061d6e..83fedc703 100644 --- a/java/org/apache/catalina/AccessLog.java +++ b/java/org/apache/catalina/AccessLog.java @@ -23,9 +23,8 @@ import org.apache.catalina.connector.Response; /** * Intended for use by a {@link Valve} to indicate that the {@link Valve} - * provides access logging. It is used by the Tomcat internals (the - * {@link org.apache.catalina.connector.CoyoteAdapter} at the time of writing) - * to identify a Valve that logs access requests so requests that are rejected + * provides access logging. It is used by the Tomcat internals to identify a + * Valve that logs access requests so requests that are rejected * earlier in the processing chain can still be added to the access log. * Implementations of this interface should be robust against the provided * {@link Request} and {@link Response} objects being null, having null diff --git a/java/org/apache/catalina/Container.java b/java/org/apache/catalina/Container.java index 7675e8b5e..8e730be6a 100644 --- a/java/org/apache/catalina/Container.java +++ b/java/org/apache/catalina/Container.java @@ -450,4 +450,27 @@ public interface Container extends Lifecycle { * @param data Event data */ public void fireContainerEvent(String type, Object data); + + + /** + * Log a request/response that was destined for this container but has been + * handled earlier in the processing chain so that the request/response + * still appears in the correct access logs. + * @param request Request (associated with the response) to log + * @param response Response (associated with the request) to log + * @param time Time taken to process the request/response in + * milliseconds (use 0 if not known) + * @param useDefault Flag that indicates that the request/response should + * be logged in the engine's default access log + */ + public void logAccess(Request request, Response response, long time, + boolean useDefault); + + + /** + * Identify the AccessLog to use to log a request/response that was destined + * for this container but was handled earlier in the processing chain so + * that the request/response still appears in the correct access logs. + */ + public AccessLog getAccessLog(); } diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java index f0b015bed..4c7547544 100644 --- a/java/org/apache/catalina/connector/CoyoteAdapter.java +++ b/java/org/apache/catalina/connector/CoyoteAdapter.java @@ -24,13 +24,8 @@ import java.util.EnumSet; import javax.servlet.SessionTrackingMode; -import org.apache.catalina.AccessLog; -import org.apache.catalina.Container; import org.apache.catalina.Context; -import org.apache.catalina.Engine; import org.apache.catalina.Globals; -import org.apache.catalina.Host; -import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.tomcat.util.res.StringManager; import org.apache.catalina.comet.CometEvent; @@ -120,11 +115,6 @@ public class CoyoteAdapter implements Adapter { protected static URLEncoder urlEncoder; - /** - * Access log to use for rejected requests - */ - private volatile AccessLog accessLog = null; - // ----------------------------------------------------- Static Initializer @@ -522,14 +512,16 @@ public class CoyoteAdapter implements Adapter { } catch (IOException ioe) { res.setStatus(400); res.setMessage("Invalid URI: " + ioe.getMessage()); - getAccessLog().log(request, response, 0); + connector.getService().getContainer().logAccess( + request, response, 0, true); return false; } // Normalization if (!normalize(req.decodedURI())) { res.setStatus(400); res.setMessage("Invalid URI"); - getAccessLog().log(request, response, 0); + connector.getService().getContainer().logAccess( + request, response, 0, true); return false; } // Character decoding @@ -538,7 +530,8 @@ public class CoyoteAdapter implements Adapter { if (!checkNormalize(req.decodedURI())) { res.setStatus(400); res.setMessage("Invalid URI character encoding"); - getAccessLog().log(request, response, 0); + connector.getService().getContainer().logAccess( + request, response, 0, true); return false; } @@ -598,7 +591,7 @@ public class CoyoteAdapter implements Adapter { res.setStatus(405); res.addHeader("Allow", header); res.setMessage("TRACE method is not allowed"); - getAccessLog().log(request, response, 0); + request.getContext().logAccess(request, response, 0, true); return false; } @@ -637,7 +630,7 @@ public class CoyoteAdapter implements Adapter { redirectPath = redirectPath + "?" + query; } response.sendRedirect(redirectPath); - getAccessLog().log(request, response, 0); + request.getContext().logAccess(request, response, 0, true); return false; } @@ -1088,63 +1081,4 @@ public class CoyoteAdapter implements Adapter { b[pos + dest] = b[pos + src]; } } - - - /** - * Obtain a reference to the access log to use to log rejected requests. - * - * @return - */ - protected AccessLog getAccessLog() { - if (accessLog != null) { - return accessLog; - } - - // First look in Engine for associated service - Engine engine = (Engine) connector.getService().getContainer(); - accessLog = findAccessLog(engine); - if (accessLog != null) { - return accessLog; - } - - // Then look in default host - Host defaultHost = (Host) engine.findChild(engine.getDefaultHost()); - accessLog = findAccessLog(defaultHost); - if (accessLog != null) { - return accessLog; - } - - // Then look in ROOT context of default host - Context defaultContext = (Context) defaultHost.findChild(""); - accessLog = findAccessLog(defaultContext); - if (accessLog != null) { - return accessLog; - } - - accessLog = new NoopAccessLog(); - return accessLog; - } - - private AccessLog findAccessLog(Container container) { - if (container == null) { - return new NoopAccessLog(); - } - - Valve valves[] = container.getPipeline().getValves(); - for (Valve valve : valves) { - if (valve instanceof AccessLog) { - return (AccessLog) valve; - } - } - return null; - } - - private static final class NoopAccessLog implements AccessLog { - - @Override - public void log(Request request, Response response, long time) { - // NOOP - } - - } } diff --git a/java/org/apache/catalina/core/ContainerBase.java b/java/org/apache/catalina/core/ContainerBase.java index 1b148eb18..b23af4ce7 100644 --- a/java/org/apache/catalina/core/ContainerBase.java +++ b/java/org/apache/catalina/core/ContainerBase.java @@ -31,6 +31,7 @@ import javax.management.ObjectName; import javax.naming.directory.DirContext; import javax.servlet.ServletException; +import org.apache.catalina.AccessLog; import org.apache.catalina.CatalinaFactory; import org.apache.catalina.Cluster; import org.apache.catalina.Container; @@ -265,6 +266,13 @@ public abstract class ContainerBase extends LifecycleMBeanBase private volatile boolean threadDone = false; + /** + * The access log to use for requests normally handled by this container + * that have been handled earlier in the processing chain. + */ + protected volatile AccessLog accessLog = null; + private volatile boolean accessLogScanComplete = false; + // ------------------------------------------------------------- Properties @@ -1062,6 +1070,46 @@ public abstract class ContainerBase extends LifecycleMBeanBase super.destroyInternal(); } + + /** + * Check this container for an access log and if none is found, look to the + * parent. If there is no parent and still none is found, use the NoOp + * access log. + */ + public void logAccess(Request request, Response response, long time, + boolean useDefault) { + + boolean logged = false; + + if (getAccessLog() != null) { + getAccessLog().log(request, response, time); + logged = true; + } + + if (getParent() != null) { + // No need to use default logger once request/response has been logged + // once + getParent().logAccess(request, response, time, (useDefault && !logged)); + } + } + + public AccessLog getAccessLog() { + + if (accessLogScanComplete) { + return accessLog; + } + + Valve valves[] = getPipeline().getValves(); + for (Valve valve : valves) { + if (valve instanceof AccessLog) { + accessLog = (AccessLog) valve; + break; + } + } + accessLogScanComplete = true; + return accessLog; + } + // ------------------------------------------------------- Pipeline Methods @@ -1305,4 +1353,11 @@ public abstract class ContainerBase extends LifecycleMBeanBase } + protected static final class NoopAccessLog implements AccessLog { + + @Override + public void log(Request request, Response response, long time) { + // NOOP + } + } } diff --git a/java/org/apache/catalina/core/StandardEngine.java b/java/org/apache/catalina/core/StandardEngine.java index 04b127c9e..f1cd9f0df 100644 --- a/java/org/apache/catalina/core/StandardEngine.java +++ b/java/org/apache/catalina/core/StandardEngine.java @@ -18,12 +18,16 @@ package org.apache.catalina.core; import java.util.Locale; +import org.apache.catalina.AccessLog; import org.apache.catalina.Container; +import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.LifecycleException; import org.apache.catalina.Realm; import org.apache.catalina.Service; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; import org.apache.catalina.realm.JAASRealm; import org.apache.catalina.util.LifecycleBase; import org.apache.catalina.util.ServerInfo; @@ -99,6 +103,11 @@ public class StandardEngine extends ContainerBase implements Engine { */ private String jvmRouteId; + /** + * Default access log to use for request/response pairs where we can't ID + * the intended host and context. + */ + private volatile AccessLog defaultAccessLog; // ------------------------------------------------------------- Properties @@ -280,6 +289,51 @@ public class StandardEngine extends ContainerBase implements Engine { } + /** + * Override the default implementation. If no access log is defined for the + * Engine, look for one in the Engine's default host and then the default + * host's ROOT context. If still none is found, return the default NoOp + * access log. + */ + @Override + /** + * Check this container for an access log and if none is found, look to the + * parent. If there is no parent and still none is found, use the NoOp + * access log. + */ + public void logAccess(Request request, Response response, long time, + boolean useDefault) { + + boolean logged = false; + + if (accessLog != null) { + accessLog.log(request, response, time); + logged = true; + } + + if (!logged && useDefault) { + Host host = null; + if (defaultAccessLog == null) { + // If we reached this point, this Engine can't have an AccessLog + // Look in the defaultHost + host = (Host) findChild(getDefaultHost()); + defaultAccessLog = host.getAccessLog(); + + if (defaultAccessLog == null) { + // Try the ROOT context of default host + Context context = (Context) host.findChild(""); + defaultAccessLog = context.getAccessLog(); + + if (defaultAccessLog == null) { + defaultAccessLog = new NoopAccessLog(); + } + } + } + + defaultAccessLog.log(request, response, time); + } + } + // -------------------- JMX registration -------------------- diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml index 201489637..3bac52bdb 100644 --- a/webapps/docs/config/valve.xml +++ b/webapps/docs/config/valve.xml @@ -66,12 +66,17 @@ Host, or Engine), and will record ALL requests processed by that container.

-

Some requests (e.g. those with mal-formed URLs) may be rejected by Tomcat - before they are passed to a container. In these cases Tomcat will look in - the Engine, then the default Host for the - Engine and finally the ROOT (or default) Context - for the default Host for an AccessLogValve or - other AccessLog implementation. Tomcat will use the first +

Some requests may be handled by Tomcat before they are passed to a + container. These include redirects from /foo to /foo/ and the rejection of + invalid requests. Where Tomcat can identify the Context that + would have handled the request, the request/response will be logged in the + AccessLog(s) associated Context, Host + and Engine. Where Tomcat cannot identify the + Context that would have handled the request, e.g. in cases + where the URL is invalid, Tomcat will look first in the Engine, + then the default Host for the Engine and finally + the ROOT (or default) Context for the default Host + for an AccessLog implementation. Tomcat will use the first AccessLog implementation found to log those requests that are rejected before they are passed to a container.