This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 8.5.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/8.5.x by this push: new 3b17b66 Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=51497 3b17b66 is described below commit 3b17b66656c6dcae8844bd2ff18f130e0283db2b Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Jul 30 22:37:56 2019 +0100 Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=51497 Add an option to use canonical IPv6 representation in the access logs. --- .../catalina/security/SecurityClassLoad.java | 6 -- .../catalina/valves/AbstractAccessLogValve.java | 80 ++++++++++++++++------ .../catalina/valves/ExtendedAccessLogValve.java | 2 +- webapps/docs/changelog.xml | 5 ++ webapps/docs/config/valve.xml | 10 +++ 5 files changed, 76 insertions(+), 27 deletions(-) diff --git a/java/org/apache/catalina/security/SecurityClassLoad.java b/java/org/apache/catalina/security/SecurityClassLoad.java index 1bb6ecd..b6e2be7 100644 --- a/java/org/apache/catalina/security/SecurityClassLoad.java +++ b/java/org/apache/catalina/security/SecurityClassLoad.java @@ -43,7 +43,6 @@ public final class SecurityClassLoad { loadServletsPackage(loader); loadSessionPackage(loader); loadUtilPackage(loader); - loadValvesPackage(loader); loadJavaxPackage(loader); loadConnectorPackage(loader); loadTomcatPackage(loader); @@ -109,11 +108,6 @@ public final class SecurityClassLoad { } - private static final void loadValvesPackage(ClassLoader loader) throws Exception { - final String basePackage = "org.apache.catalina.valves."; - loadAnonymousInnerClasses(loader, basePackage + "AbstractAccessLogValve"); - } - private static final void loadCoyotePackage(ClassLoader loader) throws Exception { final String basePackage = "org.apache.coyote."; loader.loadClass(basePackage + "http11.Constants"); diff --git a/java/org/apache/catalina/valves/AbstractAccessLogValve.java b/java/org/apache/catalina/valves/AbstractAccessLogValve.java index 950dbad..9f700e3 100644 --- a/java/org/apache/catalina/valves/AbstractAccessLogValve.java +++ b/java/org/apache/catalina/valves/AbstractAccessLogValve.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicBoolean; @@ -51,6 +52,7 @@ import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.collections.SynchronizedStack; +import org.apache.tomcat.util.net.IPv6Utils; /** @@ -173,6 +175,11 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access */ protected boolean enabled = true; + /** + * Use IPv6 canonical representation format as defined by RFC 5952. + */ + private boolean ipv6Canonical = false; + /** * The pattern used to format our access log lines. */ @@ -344,7 +351,7 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access private final Locale cacheDefaultLocale; private final DateFormatCache parent; protected final Cache cLFCache; - private final HashMap<String, Cache> formatCache = new HashMap<>(); + private final Map<String, Cache> formatCache = new HashMap<>(); protected DateFormatCache(int size, Locale loc, DateFormatCache parent) { cacheSize = size; @@ -489,6 +496,16 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access } + public boolean getIpv6Canonical() { + return ipv6Canonical; + } + + + public void setIpv6Canonical(boolean ipv6Canonical) { + this.ipv6Canonical = ipv6Canonical; + } + + /** * {@inheritDoc} * Default is <code>false</code>. @@ -498,6 +515,7 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access this.requestAttributesEnabled = requestAttributesEnabled; } + /** * {@inheritDoc} */ @@ -803,9 +821,9 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access */ protected static class LocalAddrElement implements AccessLogElement { - private static final String LOCAL_ADDR_VALUE; + private final String localAddrValue; - static { + public LocalAddrElement(boolean ipv6Canonical) { String init; try { init = InetAddress.getLocalHost().getHostAddress(); @@ -813,13 +831,18 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access ExceptionUtils.handleThrowable(e); init = "127.0.0.1"; } - LOCAL_ADDR_VALUE = init; + + if (ipv6Canonical) { + localAddrValue = IPv6Utils.canonize(init); + } else { + localAddrValue = init; + } } @Override public void addElement(CharArrayWriter buf, Date date, Request request, Response response, long time) { - buf.append(LOCAL_ADDR_VALUE); + buf.append(localAddrValue); } } @@ -830,16 +853,22 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access @Override public void addElement(CharArrayWriter buf, Date date, Request request, Response response, long time) { + String value = null; if (requestAttributesEnabled) { Object addr = request.getAttribute(REMOTE_ADDR_ATTRIBUTE); if (addr == null) { - buf.append(request.getRemoteAddr()); + value = request.getRemoteAddr(); } else { - buf.append(addr.toString()); + value = addr.toString(); } } else { - buf.append(request.getRemoteAddr()); + value = request.getRemoteAddr(); } + + if (ipv6Canonical) { + value = IPv6Utils.canonize(value); + } + buf.append(value); } } @@ -863,6 +892,10 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access if (value == null || value.length() == 0) { value = "-"; } + + if (ipv6Canonical) { + value = IPv6Utils.canonize(value); + } buf.append(value); } } @@ -1046,17 +1079,22 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access if (usesBegin) { timestamp -= time; } - switch (type) { - case CLF: + /* Implementation note: This is deliberately not implemented using + * switch. If a switch is used the compiler (at least the Oracle + * one) will use a synthetic class to implement the switch. The + * problem is that this class needs to be pre-loaded when using a + * SecurityManager and the name of that class will depend on any + * anonymous inner classes and any other synthetic classes. As such + * the name is not constant and keeping the pre-loading up to date + * as the name changes is error prone. + */ + if (type == FormatType.CLF) { buf.append(localDateCache.get().getFormat(timestamp)); - break; - case SEC: + } else if (type == FormatType.SEC) { buf.append(Long.toString(timestamp / 1000)); - break; - case MSEC: + } else if (type == FormatType.MSEC) { buf.append(Long.toString(timestamp)); - break; - case MSEC_FRAC: + } else if (type == FormatType.MSEC_FRAC) { frac = timestamp % 1000; if (frac < 100) { if (frac < 10) { @@ -1067,8 +1105,8 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access } } buf.append(Long.toString(frac)); - break; - case SDF: + } else { + // FormatType.SDF String temp = localDateCache.get().getFormat(format, locale, timestamp); if (usesMsecs) { frac = timestamp % 1000; @@ -1086,7 +1124,6 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access temp = temp.replace(msecPattern, Long.toString(frac)); } buf.append(temp); - break; } } } @@ -1371,6 +1408,9 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access value = "-"; } + if (ipv6Canonical) { + value = IPv6Utils.canonize(value); + } buf.append(value); } } @@ -1668,7 +1708,7 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access case 'a': return new RemoteAddrElement(); case 'A': - return new LocalAddrElement(); + return new LocalAddrElement(ipv6Canonical); case 'b': return new ByteSentElement(true); case 'B': diff --git a/java/org/apache/catalina/valves/ExtendedAccessLogValve.java b/java/org/apache/catalina/valves/ExtendedAccessLogValve.java index c3b7008..43f5fa7 100644 --- a/java/org/apache/catalina/valves/ExtendedAccessLogValve.java +++ b/java/org/apache/catalina/valves/ExtendedAccessLogValve.java @@ -604,7 +604,7 @@ public class ExtendedAccessLogValve extends AccessLogValve { } else if ("s".equals(token)) { String nextToken = tokenizer.getToken(); if ("ip".equals(nextToken)) { - return new LocalAddrElement(); + return new LocalAddrElement(getIpv6Canonical()); } else if ("dns".equals(nextToken)) { return new AccessLogElement() { @Override diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 23e137d..12a9077 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -48,6 +48,11 @@ <subsection name="Catalina"> <changelog> <add> + <bug>51497</bug>: Add an option, <code>ipv6Canonical</code>, to the + <code>AccessLogValve</code> that causes IPv6 addresses to be output in + canonical form defined by RFC 5952. (ognjen/markt) + </add> + <add> <bug>57665</bug>: Add support for the <code>X-Forwarded-Host</code> header to the <code>RemoteIpFilter</code> and <code>RemotepValve</code>. (markt) diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml index 048c77f..b8bbc42 100644 --- a/webapps/docs/config/valve.xml +++ b/webapps/docs/config/valve.xml @@ -181,6 +181,16 @@ </p> </attribute> + <attribute name="ipv6Canonical" required="false"> + <p>Flag to determine if IPv6 addresses should be represented in canonical + representation format as defined by RFC 5952. If set to <code>true</code>, + then IPv6 addresses will be written in canonical format (e.g. + <code>2001:db8::1:0:0:1</code>, <code>::1</code>), otherwise it will be + represented in full form (e.g. <code>2001:db8:0:0:1:0:0:1</code>, + <code>0:0:0:0:0:0:0:1</code>). Default value: <code>false</code> + </p> + </attribute> + <attribute name="locale" required="false"> <p>The locale used to format timestamps in the access log lines. Any timestamps configured using an --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org