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 b26ad77 BZ 64265. Fix ETag comparison. Always use weak comparison. b26ad77 is described below commit b26ad77f659de34d49dda5a248566a38383cec0e Author: Mark Thomas <ma...@apache.org> AuthorDate: Mon Mar 30 21:40:17 2020 +0100 BZ 64265. Fix ETag comparison. Always use weak comparison. https://bz.apache.org/bugzilla/show_bug.cgi?id=64265 --- .../apache/catalina/servlets/DefaultServlet.java | 12 ++- .../TestDefaultServletIfMatchRequests.java | 108 +++++++++++++++++++++ webapps/docs/changelog.xml | 4 + 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java index 396b91b..1cf343a 100644 --- a/java/org/apache/catalina/servlets/DefaultServlet.java +++ b/java/org/apache/catalina/servlets/DefaultServlet.java @@ -2161,16 +2161,24 @@ public class DefaultServlet extends HttpServlet { throws IOException { String eTag = resource.getETag(); + // Default servlet uses weak matching so we strip any leading "W/" and + // then compare using equals + if (eTag.startsWith("W/")) { + eTag = eTag.substring(2); + } String headerValue = request.getHeader("If-Match"); if (headerValue != null) { if (headerValue.indexOf('*') == -1) { - StringTokenizer commaTokenizer = new StringTokenizer - (headerValue, ","); + 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.trim().equals(eTag)) conditionSatisfied = true; } diff --git a/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java b/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java new file mode 100644 index 0000000..ffd3e92 --- /dev/null +++ b/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java @@ -0,0 +1,108 @@ +/* + * 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.servlets; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; + +import org.apache.catalina.Context; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.buf.ByteChunk; + +@RunWith(Parameterized.class) +public class TestDefaultServletIfMatchRequests extends TomcatBaseTest { + + @Parameterized.Parameters(name = "{index} ifMatchHeader [{0}]") + 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; + + 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) }); + + return parameterSets; + } + + @Parameter(0) + public String ifMatchHeader; + + @Parameter(1) + public int responseCodeExpected; + + + @Test + public void testIfMatch() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp"); + Context ctxt = tomcat.addContext("", appDir.getAbsolutePath()); + + Tomcat.addServlet(ctxt, "default", DefaultServlet.class.getName()); + ctxt.addServletMappingDecoded("/", "default"); + + tomcat.start(); + + // Set up parameters + String path = "http://localhost:"; + getPort() + "/index.html"; + ByteChunk responseBody = new ByteChunk(); + 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); + } + + int rc = getUrl(path, responseBody, requestHeaders, responseHeaders); + + // Check the result + Assert.assertEquals(responseCodeExpected, rc); + } +} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 495bcba..59ed7b4 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -117,6 +117,10 @@ system property, replaced by the <code>dispatcherWrapsSameObject</code> attribute on the Context. (remm) </update> + <fix> + <bug>64265</bug>: Fix ETag comparison performed by the default servlet. + The default servley always uses weak comparison. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org