This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new bef507e  Improve entity tag handling
bef507e is described below

commit bef507e1b7ac2eb0ff012d0d40035e218a5839cc
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Aug 11 15:27:45 2020 +0100

    Improve entity tag handling
---
 conf/web.xml                                       |   8 ++
 .../apache/catalina/servlets/DefaultServlet.java   | 116 +++++++++--------
 .../apache/tomcat/util/http/parser/EntityTag.java  |  82 ++++++++++++
 .../TestDefaultServletIfMatchRequests.java         | 143 +++++++++++++++++----
 webapps/docs/changelog.xml                         |   7 +
 webapps/docs/default-servlet.xml                   |   8 +-
 6 files changed, 284 insertions(+), 80 deletions(-)

diff --git a/conf/web.xml b/conf/web.xml
index a685947..b5e0b30 100644
--- a/conf/web.xml
+++ b/conf/web.xml
@@ -114,6 +114,14 @@
   <!--                       with a Range header as a partial PUT? Note     -->
   <!--                       that RFC 7233 clarified that Range headers are -->
   <!--                       only valid for GET requests. [true]            -->
+  <!--                                                                      -->
+  <!--   useWeakComparisonWithIfMatch                                       -->
+  <!--                       When comparing entity tags for If-Match        -->
+  <!--                       headers should a weak comparison be used       -->
+  <!--                       rather than the strong comparison required by  -->
+  <!--                       RFC 7232? A weak comparison is used by default -->
+  <!--                       since the default resources implementation     -->
+  <!--                       generates weak entity tags. [true]             -->
 
     <servlet>
         <servlet-name>default</servlet-name>
diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java 
b/java/org/apache/catalina/servlets/DefaultServlet.java
index 466f1df..513353f 100644
--- a/java/org/apache/catalina/servlets/DefaultServlet.java
+++ b/java/org/apache/catalina/servlets/DefaultServlet.java
@@ -43,7 +43,7 @@ import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.Locale;
-import java.util.StringTokenizer;
+import java.util.Set;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -81,6 +81,7 @@ import org.apache.catalina.webresources.CachedResource;
 import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.http.ResponseUtil;
 import org.apache.tomcat.util.http.parser.ContentRange;
+import org.apache.tomcat.util.http.parser.EntityTag;
 import org.apache.tomcat.util.http.parser.Ranges;
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.util.security.Escape;
@@ -279,6 +280,8 @@ public class DefaultServlet extends HttpServlet {
      */
     private boolean allowPartialPut = true;
 
+    protected boolean useWeakComparisonWithIfMatch = true;
+
 
     // --------------------------------------------------------- Public Methods
 
@@ -297,27 +300,31 @@ public class DefaultServlet extends HttpServlet {
     @Override
     public void init() throws ServletException {
 
-        if (getServletConfig().getInitParameter("debug") != null)
+        if (getServletConfig().getInitParameter("debug") != null) {
             debug = 
Integer.parseInt(getServletConfig().getInitParameter("debug"));
+        }
 
-        if (getServletConfig().getInitParameter("input") != null)
+        if (getServletConfig().getInitParameter("input") != null) {
             input = 
Integer.parseInt(getServletConfig().getInitParameter("input"));
+        }
 
-        if (getServletConfig().getInitParameter("output") != null)
+        if (getServletConfig().getInitParameter("output") != null) {
             output = 
Integer.parseInt(getServletConfig().getInitParameter("output"));
+        }
 
         listings = 
Boolean.parseBoolean(getServletConfig().getInitParameter("listings"));
 
-        if (getServletConfig().getInitParameter("readonly") != null)
+        if (getServletConfig().getInitParameter("readonly") != null) {
             readOnly = 
Boolean.parseBoolean(getServletConfig().getInitParameter("readonly"));
+        }
 
         compressionFormats = parseCompressionFormats(
                 getServletConfig().getInitParameter("precompressed"),
                 getServletConfig().getInitParameter("gzip"));
 
-        if (getServletConfig().getInitParameter("sendfileSize") != null)
-            sendfileSize =
-                
Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024;
+        if (getServletConfig().getInitParameter("sendfileSize") != null) {
+            sendfileSize = 
Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024;
+        }
 
         fileEncoding = getServletConfig().getInitParameter("fileEncoding");
         if (fileEncoding == null) {
@@ -331,23 +338,31 @@ public class DefaultServlet extends HttpServlet {
             }
         }
 
-        if (getServletConfig().getInitParameter("useBomIfPresent") != null)
-            useBomIfPresent = Boolean.parseBoolean(
-                    getServletConfig().getInitParameter("useBomIfPresent"));
+        if (getServletConfig().getInitParameter("useBomIfPresent") != null) {
+            useBomIfPresent = 
Boolean.parseBoolean(getServletConfig().getInitParameter("useBomIfPresent"));
+        }
 
         globalXsltFile = getServletConfig().getInitParameter("globalXsltFile");
         contextXsltFile = 
getServletConfig().getInitParameter("contextXsltFile");
         localXsltFile = getServletConfig().getInitParameter("localXsltFile");
         readmeFile = getServletConfig().getInitParameter("readmeFile");
 
-        if (getServletConfig().getInitParameter("useAcceptRanges") != null)
+        if (getServletConfig().getInitParameter("useAcceptRanges") != null) {
             useAcceptRanges = 
Boolean.parseBoolean(getServletConfig().getInitParameter("useAcceptRanges"));
+        }
+
+        if 
(getServletConfig().getInitParameter("useWeakComparisonWithIfMatch") != null) {
+            useWeakComparisonWithIfMatch = Boolean.parseBoolean(
+                    
getServletConfig().getInitParameter("useWeakComparisonWithIfMatch"));
+        }
 
         // Sanity check on the specified buffer sizes
-        if (input < 256)
+        if (input < 256) {
             input = 256;
-        if (output < 256)
+        }
+        if (output < 256) {
             output = 256;
+        }
 
         if (debug > 0) {
             log("DefaultServlet.init:  input buffer size=" + input +
@@ -355,8 +370,7 @@ public class DefaultServlet extends HttpServlet {
         }
 
         // Load the web resources
-        resources = (WebResourceRoot) getServletContext().getAttribute(
-                Globals.RESOURCES_ATTR);
+        resources = (WebResourceRoot) 
getServletContext().getAttribute(Globals.RESOURCES_ATTR);
 
         if (resources == null) {
             throw new 
UnavailableException(sm.getString("defaultServlet.noResources"));
@@ -2168,30 +2182,22 @@ public class DefaultServlet extends HttpServlet {
             eTag = eTag.substring(2);
         }
         String headerValue = request.getHeader("If-Match");
-        if (headerValue != null) {
-            if (headerValue.indexOf('*') == -1) {
+        if (headerValue != null && !headerValue.equals("*")) {
 
-                StringTokenizer commaTokenizer = new 
StringTokenizer(headerValue, ",");
-                boolean conditionSatisfied = false;
-
-                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
-                    String currentToken = commaTokenizer.nextToken();
-                    currentToken = currentToken.trim();
-                    if (currentToken.startsWith("W/")) {
-                        currentToken = currentToken.substring(2);
-                    }
-                    if (currentToken.equals(eTag))
-                        conditionSatisfied = true;
-                }
-
-                // If none of the given ETags match, 412 Precondition failed is
-                // sent back
-                if (!conditionSatisfied) {
-                    response.sendError
-                        (HttpServletResponse.SC_PRECONDITION_FAILED);
-                    return false;
+            Set<String> eTags = EntityTag.parseEntityTag(new 
StringReader(headerValue), useWeakComparisonWithIfMatch);
+            if (eTags == null) {
+                if (debug > 10) {
+                    log("DefaultServlet.checkIfMatch:  Invalid header value [" 
+ headerValue + "]");
                 }
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                return false;
+            }
 
+            // If none of the given ETags match, 412 Precondition failed is
+            // sent back
+            if (!eTags.contains(eTag)) {
+                response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
+                return false;
             }
         }
         return true;
@@ -2250,46 +2256,48 @@ public class DefaultServlet extends HttpServlet {
             throws IOException {
 
         String eTag = generateETag(resource);
+        // If-None-Match uses weak comparison so strip the weak indicator if
+        // present
+        if (eTag.startsWith("W/")) {
+            eTag = eTag.substring(2);
+        }
         String headerValue = request.getHeader("If-None-Match");
         if (headerValue != null) {
 
             boolean conditionSatisfied = false;
 
             if (!headerValue.equals("*")) {
-
-                StringTokenizer commaTokenizer =
-                    new StringTokenizer(headerValue, ",");
-
-                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
-                    String currentToken = commaTokenizer.nextToken();
-                    if (currentToken.trim().equals(eTag))
-                        conditionSatisfied = true;
+                Set<String> eTags = EntityTag.parseEntityTag(new 
StringReader(headerValue), true);
+                if (eTags == null) {
+                    if (debug > 10) {
+                        log("DefaultServlet.checkIfNoneMatch:  Invalid header 
value [" + headerValue + "]");
+                    }
+                    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                    return false;
                 }
-
+                conditionSatisfied = eTags.contains(eTag);
             } else {
                 conditionSatisfied = true;
             }
 
             if (conditionSatisfied) {
-
                 // For GET and HEAD, we should respond with
                 // 304 Not Modified.
                 // For every other method, 412 Precondition Failed is sent
                 // back.
-                if ( ("GET".equals(request.getMethod()))
-                     || ("HEAD".equals(request.getMethod())) ) {
+                if ("GET".equals(request.getMethod()) || 
"HEAD".equals(request.getMethod())) {
                     response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                     response.setHeader("ETag", eTag);
-
-                    return false;
+                } else {
+                    
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
                 }
-                response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
                 return false;
             }
         }
         return true;
     }
 
+
     /**
      * Check if the if-unmodified-since condition is satisfied.
      *
@@ -2325,7 +2333,9 @@ public class DefaultServlet extends HttpServlet {
     /**
      * Provides the entity tag (the ETag header) for the given resource.
      * Intended to be over-ridden by custom DefaultServlet implementations that
-     * wish to use an alternative format for the entity tag.
+     * wish to use an alternative format for the entity tag. Such custom
+     * implementations that generate strong entity tags may also want to change
+     * the default value of {@link #useWeakComparisonWithIfMatch}.
      *
      * @param resource  The resource for which an entity tag is required.
      *
diff --git a/java/org/apache/tomcat/util/http/parser/EntityTag.java 
b/java/org/apache/tomcat/util/http/parser/EntityTag.java
new file mode 100644
index 0000000..abab6b7
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/parser/EntityTag.java
@@ -0,0 +1,82 @@
+/*
+ * 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.tomcat.util.http.parser;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashSet;
+import java.util.Set;
+
+public class EntityTag {
+
+    /**
+     *
+     * @param input
+     * @param includeWeak
+     *
+     * @return The set of parsed entity tags or {@code null} if the header is
+     *         invalid
+     *
+     * @throws IOException
+     */
+    public static Set<String> parseEntityTag(StringReader input, boolean 
includeWeak) throws IOException {
+
+        HashSet<String> result = new HashSet<>();
+
+        while (true) {
+            boolean strong = false;
+            HttpParser.skipLws(input);
+
+            switch (HttpParser.skipConstant(input, "W/")) {
+                case EOF:
+                    // Empty values are invalid
+                    return null;
+                case NOT_FOUND:
+                    strong = true;
+                    break;
+                case FOUND:
+                    strong = false;
+                    break;
+            }
+
+            // Note: RFC 2616 allowed quoted string
+            //       RFC 7232 does not allow " in the entity-tag
+            String value = HttpParser.readQuotedString(input, true);
+            if (value == null) {
+                // Not a quoted string so the header is invalid
+                return null;
+            }
+
+            if (strong || includeWeak) {
+                result.add(value);
+            }
+
+            HttpParser.skipLws(input);
+
+            switch (HttpParser.skipConstant(input, ",")) {
+                case EOF:
+                    return result;
+                case NOT_FOUND:
+                    // Not EOF and not "," so must be invalid
+                    return null;
+                case FOUND:
+                    // Parse next entry
+                    break;
+            }
+        }
+    }
+}
diff --git 
a/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java 
b/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java
index ffd3e92..102fc0f 100644
--- a/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java
+++ b/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java
@@ -19,6 +19,7 @@ package org.apache.catalina.servlets;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -30,6 +31,7 @@ import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameter;
 
 import org.apache.catalina.Context;
+import org.apache.catalina.WebResource;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.util.buf.ByteChunk;
@@ -37,52 +39,126 @@ import org.apache.tomcat.util.buf.ByteChunk;
 @RunWith(Parameterized.class)
 public class TestDefaultServletIfMatchRequests extends TomcatBaseTest {
 
-    @Parameterized.Parameters(name = "{index} ifMatchHeader [{0}]")
+    private static final Integer RC_200 = Integer.valueOf(200);
+    private static final Integer RC_304 = Integer.valueOf(304);
+    private static final Integer RC_400 = Integer.valueOf(400);
+    private static final Integer RC_412 = Integer.valueOf(412);
+
+    private static final String[] CONCAT = new String[] { ",", " ,", ", ", " , 
" };
+
+    @Parameterized.Parameters(name = "{index} resource-strong [{0}], 
matchHeader [{1}]")
     public static Collection<Object[]> parameters() {
 
         // Get the length of the file used for this test
         // It varies by platform due to line-endings
         File index = new File("test/webapp/index.html");
-        String strongETag =  "\"" + index.length() + "-" + 
index.lastModified() + "\"";
-        String weakETag = "W/" + strongETag;
+        String resourceETagStrong =  "\"" + index.length() + "-" + 
index.lastModified() + "\"";
+        String resourceETagWeak = "W/" + resourceETagStrong;
+
+        String otherETagStrong = "\"123456789\"";
+        String otherETagWeak = "\"123456789\"";
 
         List<Object[]> parameterSets = new ArrayList<>();
 
-        parameterSets.add(new Object[] { null, Integer.valueOf(200) });
-        parameterSets.add(new Object[] { "*", Integer.valueOf(200) });
-        parameterSets.add(new Object[] { weakETag, Integer.valueOf(200) });
-        parameterSets.add(new Object[] { strongETag, Integer.valueOf(200) });
-        parameterSets.add(new Object[] { weakETag + ",123456789", 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { strongETag + ",123456789", 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { weakETag + " ,123456789", 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { strongETag + " ,123456789", 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { "123456789," + weakETag, 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { "123456789," + strongETag, 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { "123456789, " + weakETag, 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { "123456789, " + strongETag, 
Integer.valueOf(200) });
-        parameterSets.add(new Object[] { "123456789", Integer.valueOf(412) });
-        parameterSets.add(new Object[] { "W/123456789", Integer.valueOf(412) 
});
-        parameterSets.add(new Object[] { "W/", Integer.valueOf(412) });
+        for (Boolean resourceWithStrongETag : booleans) {
+            // No match header
+            parameterSets.add(new Object[] { resourceWithStrongETag, null, 
RC_200, RC_200 });
+
+            // match header is invalid
+            parameterSets.add(new Object[] { resourceWithStrongETag, "", 
RC_400, RC_400 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, "W", 
RC_400, RC_400 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, "W/", 
RC_400, RC_400 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, "w/" + 
resourceETagStrong, RC_400, RC_400 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagStrong + " x", RC_400, RC_400 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagStrong + "x", RC_400, RC_400 });
+            for (String concat : CONCAT) {
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
concat + resourceETagStrong, RC_400, RC_400 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
concat + resourceETagWeak, RC_400, RC_400 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagStrong + concat, RC_400, RC_400 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagWeak + concat, RC_400, RC_400 });
+            }
+
+            // match header always matches resource (leading and trailing 
space should be ignored)
+            parameterSets.add(new Object[] { resourceWithStrongETag, "*", 
RC_200, RC_304 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, " *", 
RC_200, RC_304 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, "* ", 
RC_200, RC_304 });
+
+            // match header never matches resource
+            parameterSets.add(new Object[] { resourceWithStrongETag, 
otherETagStrong, RC_412, RC_200 });
+            parameterSets.add(new Object[] { resourceWithStrongETag, 
otherETagWeak, RC_412, RC_200 });
+
+            // match header includes weak tag
+            // Results depend on whether strong or weak comparison is used
+            Integer rcWeak;
+            if (resourceWithStrongETag.booleanValue()) {
+                rcWeak = RC_412;
+            } else {
+                rcWeak = RC_200;
+            }
+            parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagWeak, rcWeak, RC_304 });
+            for (String concat : CONCAT) {
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagWeak + concat + otherETagWeak,
+                        rcWeak, RC_304 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagWeak + concat + otherETagStrong,
+                        rcWeak, RC_304 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
otherETagWeak + concat + resourceETagWeak,
+                        rcWeak, RC_304 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
otherETagStrong + concat + resourceETagWeak,
+                        rcWeak, RC_304 });
+            }
+
+            // match header includes strong tag
+            parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagStrong, RC_200, RC_304 });
+            for (String concat : CONCAT) {
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagStrong + concat + otherETagWeak,
+                        RC_200, RC_304 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
resourceETagStrong + concat + otherETagStrong,
+                        RC_200, RC_304 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
otherETagWeak + concat + resourceETagStrong,
+                        RC_200, RC_304 });
+                parameterSets.add(new Object[] { resourceWithStrongETag, 
otherETagStrong + concat + resourceETagStrong,
+                        RC_200, RC_304 });
+            }
+        }
 
         return parameterSets;
     }
 
     @Parameter(0)
-    public String ifMatchHeader;
+    public boolean resourceHasStrongETag;
 
     @Parameter(1)
-    public int responseCodeExpected;
+    public String matchHeader;
+
+    @Parameter(2)
+    public int ifMatchResponseCode;
 
+    @Parameter(3)
+    public int ifNoneMatchResponseCode;
 
     @Test
     public void testIfMatch() throws Exception {
+        doMatchTest("If-Match", ifMatchResponseCode);
+    }
+
+
+    @Test
+    public void testIfNoneMatch() throws Exception {
+        doMatchTest("If-None-Match", ifNoneMatchResponseCode);
+    }
 
+
+    private void doMatchTest(String headerName, int responseCodeExpected) 
throws Exception {
         Tomcat tomcat = getTomcatInstance();
 
         File appDir = new File("test/webapp");
         Context ctxt = tomcat.addContext("", appDir.getAbsolutePath());
 
-        Tomcat.addServlet(ctxt, "default", DefaultServlet.class.getName());
+        if (resourceHasStrongETag) {
+            Tomcat.addServlet(ctxt, "default", 
DefaultWithStrongETag.class.getName());
+        } else {
+            Tomcat.addServlet(ctxt, "default", DefaultServlet.class.getName());
+        }
         ctxt.addServletMappingDecoded("/", "default");
 
         tomcat.start();
@@ -93,11 +169,9 @@ public class TestDefaultServletIfMatchRequests extends 
TomcatBaseTest {
         Map<String,List<String>> responseHeaders = new HashMap<>();
 
         Map<String,List<String>> requestHeaders = null;
-        if (ifMatchHeader != null) {
-            requestHeaders = new HashMap<>();
-            List<String> values = new ArrayList<>(1);
-            values.add(ifMatchHeader);
-            requestHeaders.put("If-Match", values);
+        if (matchHeader != null) {
+            List<String> values = Collections.singletonList(matchHeader);
+            requestHeaders = Collections.singletonMap(headerName, values);
         }
 
         int rc = getUrl(path, responseBody, requestHeaders, responseHeaders);
@@ -105,4 +179,21 @@ public class TestDefaultServletIfMatchRequests extends 
TomcatBaseTest {
         // Check the result
         Assert.assertEquals(responseCodeExpected, rc);
     }
+
+
+    public static class DefaultWithStrongETag extends DefaultServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        public DefaultWithStrongETag() {
+            useWeakComparisonWithIfMatch = false;
+        }
+
+        @Override
+        protected String generateETag(WebResource resource) {
+            String weakETag = super.generateETag(resource);
+            // Make it a strong ETag
+            return weakETag.substring(2);
+        }
+    }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index f3bef3f..53adb16 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -74,6 +74,13 @@
         overridden (<code>generateETag()</code>) should a custom entity tag
         format be required. (markt)
       </add>
+      <fix>
+        Improve the validation of entity tags provided with conditional
+        requests. Requests with headers that contain invalid entity tags will 
be
+        rejected with a 400 response code. Improve the matching algorithm used
+        to compare entity tags in conditional requests with the entity tag for
+        the requested resource. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">
diff --git a/webapps/docs/default-servlet.xml b/webapps/docs/default-servlet.xml
index b6d1e62..b382895 100644
--- a/webapps/docs/default-servlet.xml
+++ b/webapps/docs/default-servlet.xml
@@ -92,7 +92,7 @@ Tomcat.</p>
   <property name="debug">
         Debugging level. It is not very useful unless you are a tomcat
         developer. As
-        of this writing, useful values are 0, 1, 11, 1000. [0]
+        of this writing, useful values are 0, 1, 11. [0]
   </property>
   <property name="listings">
         If no welcome file is present, can a directory listing be
@@ -206,6 +206,12 @@ Tomcat.</p>
         partial PUT? Note that RFC 7233 clarified that Range headers are only
         valid for GET requests. [true]
   </property>
+  <property name="useWeakComparisonWithIfMatch">
+        When comparing entity tags for If-Match headers should a weak 
comparison
+        be used rather than the strong comparison required by RFC 7232? A weak
+        comparison is used by default since the default resources 
implementation
+        generates weak entity tags. [true]
+  </property>
 </properties>
 </section>
 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to