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.