You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/11/11 15:10:36 UTC

[tomcat] branch 8.5.x updated (7a5163b -> 28c60f1)

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

markt pushed a change to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git.


    from 7a5163b  Polish (aligning with 9.0.x/7.0.x)
     new 0ae3dde  Convert TestExpireFilter to use the built-in getUrl() methods
     new 2522b5a0 Refactor response header handling in unit tests
     new 28c60f1  Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63909

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/catalina/filters/ExpiresFilter.java |  48 +++++++--
 test/javax/servlet/http/TestHttpServlet.java       |   7 +-
 .../apache/catalina/connector/TestResponse.java    |   4 +-
 .../apache/catalina/core/TestAsyncContextImpl.java |  19 ++--
 .../catalina/filters/TestAddCharSetFilter.java     |   4 +-
 .../apache/catalina/filters/TestExpiresFilter.java | 110 ++++++++++++++++++---
 .../apache/catalina/mapper/TestMapperWebapps.java  |  16 +--
 .../servlets/DefaultServletEncodingBaseTest.java   |   6 +-
 .../apache/catalina/startup/TomcatBaseTest.java    |  32 +++++-
 test/org/apache/coyote/TestResponse.java           |  75 +++++++++++++-
 .../apache/coyote/http11/TestHttp11Processor.java  |  21 ++--
 test/org/apache/jasper/compiler/TestCompiler.java  |   6 +-
 test/org/apache/jasper/compiler/TestGenerator.java |   8 +-
 test/org/apache/jasper/compiler/TestParser.java    |  30 ++----
 .../compiler/TestParserNoStrictWhitespace.java     |   9 +-
 test/org/apache/jasper/servlet/TestTldScanner.java |   3 +-
 .../bug6nnnn/bug69303.txt}                         |  12 +--
 webapps/docs/changelog.xml                         |   6 ++
 18 files changed, 296 insertions(+), 120 deletions(-)
 copy test/{org/apache/tomcat/util/net/keystore-info.txt => webapp/bug6nnnn/bug69303.txt} (80%)


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


[tomcat] 02/03: Refactor response header handling in unit tests

Posted by ma...@apache.org.
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

commit 2522b5a01ee6a4cabd6094745e664e72df799568
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Nov 11 11:29:03 2019 +0000

    Refactor response header handling in unit tests
    
    1. Use CaseInsensitiveKeyMap to store received headers
    2. Use the getSingleHeader() utility method
    
    This results in a small reduction in duplicate code.
---
 test/javax/servlet/http/TestHttpServlet.java       |  7 +-
 .../apache/catalina/connector/TestResponse.java    |  4 +-
 .../apache/catalina/core/TestAsyncContextImpl.java | 19 ++----
 .../catalina/filters/TestAddCharSetFilter.java     |  4 +-
 .../apache/catalina/filters/TestExpiresFilter.java | 16 ++---
 .../apache/catalina/mapper/TestMapperWebapps.java  | 16 ++---
 .../servlets/DefaultServletEncodingBaseTest.java   |  6 +-
 .../apache/catalina/startup/TomcatBaseTest.java    | 32 ++++++++-
 test/org/apache/coyote/TestResponse.java           | 75 ++++++++++++++++++++--
 .../apache/coyote/http11/TestHttp11Processor.java  | 21 +++---
 test/org/apache/jasper/compiler/TestCompiler.java  |  6 +-
 test/org/apache/jasper/compiler/TestGenerator.java |  8 +--
 test/org/apache/jasper/compiler/TestParser.java    | 30 +++------
 .../compiler/TestParserNoStrictWhitespace.java     |  9 +--
 test/org/apache/jasper/servlet/TestTldScanner.java |  3 +-
 15 files changed, 152 insertions(+), 104 deletions(-)

diff --git a/test/javax/servlet/http/TestHttpServlet.java b/test/javax/servlet/http/TestHttpServlet.java
index 331a0f6..8c03ee3 100644
--- a/test/javax/servlet/http/TestHttpServlet.java
+++ b/test/javax/servlet/http/TestHttpServlet.java
@@ -31,6 +31,7 @@ import org.apache.catalina.core.StandardContext;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap;
 
 public class TestHttpServlet extends TomcatBaseTest {
 
@@ -92,13 +93,13 @@ public class TestHttpServlet extends TomcatBaseTest {
 
         tomcat.start();
 
-        Map<String,List<String>> resHeaders= new HashMap<>();
+        Map<String,List<String>> resHeaders= new CaseInsensitiveKeyMap<>();
         String path = "http://localhost:" + getPort() + "/outer";
         ByteChunk out = new ByteChunk();
 
         int rc = getUrl(path, out, resHeaders);
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
-        String length = resHeaders.get("Content-Length").get(0);
+        String length = getSingleHeader("Content-Length", resHeaders);
         Assert.assertEquals(Long.parseLong(length), out.getLength());
         out.recycle();
 
@@ -124,7 +125,7 @@ public class TestHttpServlet extends TomcatBaseTest {
 
         tomcat.start();
 
-        Map<String,List<String>> getHeaders = new HashMap<>();
+        Map<String,List<String>> getHeaders = new CaseInsensitiveKeyMap<>();
         String path = "http://localhost:" + getPort() + "/chunking";
         ByteChunk out = new ByteChunk();
 
diff --git a/test/org/apache/catalina/connector/TestResponse.java b/test/org/apache/catalina/connector/TestResponse.java
index 415b4d3..14f78f3 100644
--- a/test/org/apache/catalina/connector/TestResponse.java
+++ b/test/org/apache/catalina/connector/TestResponse.java
@@ -18,7 +18,6 @@ package org.apache.catalina.connector;
 
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -37,6 +36,7 @@ import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.unittest.TesterContext;
 import org.apache.tomcat.unittest.TesterRequest;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap;
 
 /**
  * Test case for {@link Request}.
@@ -56,7 +56,7 @@ public class TestResponse extends TomcatBaseTest {
 
         tomcat.start();
 
-        Map<String,List<String>> headers = new HashMap<>();
+        Map<String,List<String>> headers = new CaseInsensitiveKeyMap<>();
         getUrl("http://localhost:" + getPort() + "/", new ByteChunk(), headers);
 
         // Check for headers without a name
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java
index ccf3228..d305cbd 100644
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
@@ -21,8 +21,6 @@ import java.io.PrintWriter;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
@@ -65,6 +63,7 @@ import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.catalina.valves.TesterAccessLogValve;
 import org.apache.tomcat.unittest.TesterContext;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap;
 import org.apache.tomcat.util.descriptor.web.ErrorPage;
 import org.easymock.EasyMock;
 
@@ -231,14 +230,12 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
 
         // Call the servlet once
         ByteChunk bc = new ByteChunk();
-        Map<String,List<String>> headers = new HashMap<>();
+        Map<String,List<String>> headers = new CaseInsensitiveKeyMap<>();
         getUrl("http://localhost:" + getPort() + "/", bc, headers);
 
         Assert.assertEquals("OK", bc.toString());
-        List<String> contentLength = headers.get("Content-Length");
-        Assert.assertNotNull(contentLength);
-        Assert.assertEquals(1,  contentLength.size());
-        Assert.assertEquals("2", contentLength.get(0));
+        String contentLength = getSingleHeader("Content-Length", headers);
+        Assert.assertEquals("2", contentLength);
 
         // Check the access log
         alv.validateAccessLog(1, 200, 0, REQUEST_TIME);
@@ -1170,15 +1167,13 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         tomcat.start();
 
         // Call the servlet once
-        Map<String,List<String>> headers = new LinkedHashMap<>();
+        Map<String,List<String>> headers = new CaseInsensitiveKeyMap<>();
         ByteChunk bc = new ByteChunk();
         int rc = getUrl("http://localhost:" + getPort() + "/", bc, headers);
         Assert.assertEquals(200, rc);
         Assert.assertEquals("OK", bc.toString());
-        List<String> testHeader = headers.get("A");
-        Assert.assertNotNull(testHeader);
-        Assert.assertEquals(1, testHeader.size());
-        Assert.assertEquals("xyz",testHeader.get(0));
+        String testHeader = getSingleHeader("A", headers);
+        Assert.assertEquals("xyz",testHeader);
 
         // Check the access log
         alv.validateAccessLog(1, 200, Bug50753Servlet.THREAD_SLEEP_TIME,
diff --git a/test/org/apache/catalina/filters/TestAddCharSetFilter.java b/test/org/apache/catalina/filters/TestAddCharSetFilter.java
index 3b8bf0c..2443b1b 100644
--- a/test/org/apache/catalina/filters/TestAddCharSetFilter.java
+++ b/test/org/apache/catalina/filters/TestAddCharSetFilter.java
@@ -120,9 +120,7 @@ public class TestAddCharSetFilter extends TomcatBaseTest {
         Map<String, List<String>> headers = new HashMap<>();
         getUrl("http://localhost:" + getPort() + "/", new ByteChunk(), headers);
 
-        List<String> ctHeaders = headers.get("Content-Type");
-        Assert.assertEquals(1, ctHeaders.size());
-        String ct = ctHeaders.get(0).toLowerCase(Locale.ENGLISH);
+        String ct = getSingleHeader("Content-Type", headers).toLowerCase(Locale.ENGLISH);
         Assert.assertEquals("text/plain;charset=" + expected.toLowerCase(Locale.ENGLISH), ct);
     }
 
diff --git a/test/org/apache/catalina/filters/TestExpiresFilter.java b/test/org/apache/catalina/filters/TestExpiresFilter.java
index d6a2429..4049eb7 100644
--- a/test/org/apache/catalina/filters/TestExpiresFilter.java
+++ b/test/org/apache/catalina/filters/TestExpiresFilter.java
@@ -18,7 +18,6 @@
 package org.apache.catalina.filters;
 
 import java.io.IOException;
-import java.net.HttpURLConnection;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
@@ -368,12 +367,13 @@ public class TestExpiresFilter extends TomcatBaseTest {
 
     protected void validate(HttpServlet servlet, Integer expectedMaxAgeInSeconds)
             throws Exception {
-        validate(servlet, expectedMaxAgeInSeconds, HttpURLConnection.HTTP_OK);
+        validate(servlet, expectedMaxAgeInSeconds, HttpServletResponse.SC_OK);
     }
 
     protected void validate(HttpServlet servlet,
             Integer expectedMaxAgeInSeconds, int expectedResponseStatusCode)
             throws Exception {
+
         // SETUP
 
         Tomcat tomcat = getTomcatInstance();
@@ -429,11 +429,7 @@ public class TestExpiresFilter extends TomcatBaseTest {
 
             Integer actualMaxAgeInSeconds;
 
-            String cacheControlHeader = null;
-            List<String> cacheControlHeaders = responseHeaders.get("Cache-Control");
-            if (cacheControlHeaders != null && cacheControlHeaders.size() == 1) {
-                cacheControlHeader = cacheControlHeaders.get(0);
-            }
+            String cacheControlHeader = getSingleHeader("Cache-Control", responseHeaders);
 
             if (cacheControlHeader == null) {
                 actualMaxAgeInSeconds = null;
@@ -465,11 +461,7 @@ public class TestExpiresFilter extends TomcatBaseTest {
 
             Assert.assertNotNull(actualMaxAgeInSeconds);
 
-            String contentType = null;
-            List<String> contentTypeHeaders = responseHeaders.get("Content-Type");
-            if (contentTypeHeaders != null && contentTypeHeaders.size() == 1) {
-                contentType = contentTypeHeaders.get(0);
-            }
+            String contentType = getSingleHeader("Content-Type", responseHeaders);
 
             int deltaInSeconds = Math.abs(actualMaxAgeInSeconds.intValue() -
                     expectedMaxAgeInSeconds.intValue());
diff --git a/test/org/apache/catalina/mapper/TestMapperWebapps.java b/test/org/apache/catalina/mapper/TestMapperWebapps.java
index 4fc9bd5..fa453dd 100644
--- a/test/org/apache/catalina/mapper/TestMapperWebapps.java
+++ b/test/org/apache/catalina/mapper/TestMapperWebapps.java
@@ -18,8 +18,6 @@ package org.apache.catalina.mapper;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -186,14 +184,11 @@ public class TestMapperWebapps extends TomcatBaseTest{
 
         tomcat.start();
         ByteChunk bc = new ByteChunk();
-        int rc = getUrl("http://localhost:" + getPort() +
-                "/test/welcome-files", bc, new HashMap<String,List<String>>());
+        int rc = getUrl("http://localhost:" + getPort() + "/test/welcome-files", bc, null);
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
         Assert.assertTrue(bc.toString().contains("JSP"));
 
-        rc = getUrl("http://localhost:" + getPort() +
-                "/test/welcome-files/sub", bc,
-                new HashMap<String,List<String>>());
+        rc = getUrl("http://localhost:" + getPort() + "/test/welcome-files/sub", bc, null);
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
         Assert.assertTrue(bc.toString().contains("Servlet"));
     }
@@ -217,14 +212,11 @@ public class TestMapperWebapps extends TomcatBaseTest{
 
         tomcat.start();
         ByteChunk bc = new ByteChunk();
-        int rc = getUrl("http://localhost:" + getPort() +
-                "/test/welcome-files", bc, new HashMap<String,List<String>>());
+        int rc = getUrl("http://localhost:" + getPort() + "/test/welcome-files", bc, null);
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
         Assert.assertTrue(bc.toString().contains("JSP"));
 
-        rc = getUrl("http://localhost:" + getPort() +
-                "/test/welcome-files/sub", bc,
-                new HashMap<String,List<String>>());
+        rc = getUrl("http://localhost:" + getPort() + "/test/welcome-files/sub", bc, null);
         Assert.assertEquals(HttpServletResponse.SC_NOT_FOUND, rc);
     }
 
diff --git a/test/org/apache/catalina/servlets/DefaultServletEncodingBaseTest.java b/test/org/apache/catalina/servlets/DefaultServletEncodingBaseTest.java
index 6640494..7a1b1c9 100644
--- a/test/org/apache/catalina/servlets/DefaultServletEncodingBaseTest.java
+++ b/test/org/apache/catalina/servlets/DefaultServletEncodingBaseTest.java
@@ -200,9 +200,9 @@ public abstract class DefaultServletEncodingBaseTest extends TomcatBaseTest {
         int rc = getUrl(target, res, headers);
 
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
-        List<String> values = headers.get("Content-Type");
-        if (values != null && values.size() == 1) {
-            MediaType mediaType = MediaType.parseMediaType(new StringReader(values.get(0)));
+        String contentType = getSingleHeader("Content-Type", headers);
+        if (contentType != null) {
+            MediaType mediaType = MediaType.parseMediaType(new StringReader(contentType));
             String charset = mediaType.getCharset();
             if (charset == null) {
                 res.setCharset(B2CConverter.getCharset(outputEncoding));
diff --git a/test/org/apache/catalina/startup/TomcatBaseTest.java b/test/org/apache/catalina/startup/TomcatBaseTest.java
index b7c5fb4..ac7c3f5 100644
--- a/test/org/apache/catalina/startup/TomcatBaseTest.java
+++ b/test/org/apache/catalina/startup/TomcatBaseTest.java
@@ -693,8 +693,13 @@ public abstract class TomcatBaseTest extends LoggingBaseTest {
         connection.connect();
         int rc = connection.getResponseCode();
         if (resHead != null) {
-            Map<String, List<String>> head = connection.getHeaderFields();
-            resHead.putAll(head);
+            // Skip the entry with null key that is used for the response line
+            // that some Map implementations may not accept.
+            for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
+                if (entry.getKey() != null) {
+                    resHead.put(entry.getKey(), entry.getValue());
+                }
+            }
         }
         InputStream is;
         if (rc < 400) {
@@ -824,6 +829,29 @@ public abstract class TomcatBaseTest extends LoggingBaseTest {
         }
     }
 
+    protected static String getSingleHeader(String header, Map<String,List<String>> headers) {
+        // Assume headers is never null
+
+        // Assume that either:
+        // a) is correct since HTTP headers are case insensitive but most Map
+        //    implementations are case-sensitive; or
+        // b) CaseInsensitiveKeyMap or similar is used
+        List<String> headerValues = headers.get(header);
+
+        // Looking for a single header. No matches are OK
+        if (headerValues == null) {
+            return null;
+        }
+
+        // Found a single header - return the header value
+        if (headerValues.size() == 1) {
+            return headerValues.get(0);
+        }
+
+        // More than one header value is an error
+        throw new IllegalStateException("Found multiple headers for [" + header + "]");
+    }
+
     private static class TomcatWithFastSessionIDs extends Tomcat {
 
         @Override
diff --git a/test/org/apache/coyote/TestResponse.java b/test/org/apache/coyote/TestResponse.java
index ded1b07..15ecc3a 100644
--- a/test/org/apache/coyote/TestResponse.java
+++ b/test/org/apache/coyote/TestResponse.java
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import org.apache.catalina.Context;
@@ -58,10 +59,9 @@ public class TestResponse extends TomcatBaseTest {
                 responseHeaders);
 
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
-        Assert.assertTrue(responseHeaders.containsKey("Content-Type"));
-        List<String> contentType = responseHeaders.get("Content-Type");
-        Assert.assertEquals(1, contentType.size());
-        Assert.assertEquals("text/plain;charset=uTf-8", contentType.get(0));
+
+        String contentType = getSingleHeader("Content-Type", responseHeaders);
+        Assert.assertEquals("text/plain;charset=uTf-8", contentType);
     }
 
 
@@ -78,4 +78,71 @@ public class TestResponse extends TomcatBaseTest {
             resp.getWriter().print("OK");
         }
     }
+
+
+    @Test
+    public void testContentTypeWithSpace() throws Exception {
+        doTestContentTypeSpacing(true);
+    }
+
+
+    @Ignore // Disabled until Bug 62912 is addressed
+    @Test
+    public void testContentTypeWithoutSpace() throws Exception {
+        doTestContentTypeSpacing(false);
+    }
+
+
+    private void doTestContentTypeSpacing(boolean withSpace) throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        // No file system docBase required
+        Context ctx = tomcat.addContext("", null);
+
+        // Add  servlet
+        Tomcat.addServlet(ctx, "ContentTypeServlet", new ContentTypeServlet());
+        ctx.addServletMappingDecoded("/*", "ContentTypeServlet");
+
+        tomcat.start();
+
+        ByteChunk responseBody = new ByteChunk();
+        Map<String,List<String>> responseHeaders = new HashMap<>();
+        StringBuilder uri = new StringBuilder("http://localhost:");
+        uri.append(getPort());
+        uri.append("/test");
+        if (withSpace) {
+            uri.append("?withSpace=true");
+        }
+        int rc = getUrl(uri.toString(), responseBody, responseHeaders);
+
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+
+        String contentType = getSingleHeader("Content-Type", responseHeaders);
+        StringBuilder expected = new StringBuilder("text/plain;");
+        if (withSpace) {
+            expected.append(" ");
+        }
+        expected.append("v=1;charset=UTF-8");
+        Assert.assertEquals(expected.toString() , contentType);
+    }
+
+
+    private static class ContentTypeServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+
+            if (req.getParameter("withSpace") == null) {
+                resp.setContentType("text/plain;v=1");
+            } else {
+                resp.setContentType("text/plain; v=1");
+            }
+            resp.setCharacterEncoding("UTF-8");
+
+            resp.getWriter().print("OK");
+        }
+    }
 }
diff --git a/test/org/apache/coyote/http11/TestHttp11Processor.java b/test/org/apache/coyote/http11/TestHttp11Processor.java
index 6bd175e..7759df6 100644
--- a/test/org/apache/coyote/http11/TestHttp11Processor.java
+++ b/test/org/apache/coyote/http11/TestHttp11Processor.java
@@ -401,10 +401,9 @@ public class TestHttp11Processor extends TomcatBaseTest {
                 responseHeaders);
 
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
-        Assert.assertTrue(responseHeaders.containsKey("Transfer-Encoding"));
-        List<String> encodings = responseHeaders.get("Transfer-Encoding");
-        Assert.assertEquals(1, encodings.size());
-        Assert.assertEquals("chunked", encodings.get(0));
+
+        String transferEncoding = getSingleHeader("Transfer-Encoding", responseHeaders);
+        Assert.assertEquals("chunked", transferEncoding);
     }
 
     @Test
@@ -430,10 +429,8 @@ public class TestHttp11Processor extends TomcatBaseTest {
 
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
 
-        Assert.assertTrue(responseHeaders.containsKey("Connection"));
-        List<String> connections = responseHeaders.get("Connection");
-        Assert.assertEquals(1, connections.size());
-        Assert.assertEquals("close", connections.get(0));
+        String connection = getSingleHeader("Connection", responseHeaders);
+        Assert.assertEquals("close", connection);
 
         Assert.assertFalse(responseHeaders.containsKey("Transfer-Encoding"));
 
@@ -463,9 +460,7 @@ public class TestHttp11Processor extends TomcatBaseTest {
         tomcat.start();
 
         ByteChunk responseBody = new ByteChunk();
-        Map<String,List<String>> responseHeaders = new HashMap<>();
-        int rc = getUrl("http://localhost:" + getPort() + "/test", responseBody,
-                responseHeaders);
+        int rc = getUrl("http://localhost:" + getPort() + "/test", responseBody, null);
 
         Assert.assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, rc);
         if (responseBody.getLength() > 0) {
@@ -992,8 +987,8 @@ public class TestHttp11Processor extends TomcatBaseTest {
         int rc = getUrl("http://localhost:" + getPort() + "/test", responseBody, responseHeaders);
 
         Assert.assertEquals(HttpServletResponse.SC_RESET_CONTENT, rc);
-        Assert.assertNotNull(responseHeaders.get("Content-Length"));
-        Assert.assertTrue("0".equals(responseHeaders.get("Content-Length").get(0)));
+        String contentLength = getSingleHeader("Content-Length", responseHeaders);
+        Assert.assertEquals("0", contentLength);
         Assert.assertTrue(responseBody.getLength() == 0);
     }
 
diff --git a/test/org/apache/jasper/compiler/TestCompiler.java b/test/org/apache/jasper/compiler/TestCompiler.java
index 200e8f2..e89a4d2 100644
--- a/test/org/apache/jasper/compiler/TestCompiler.java
+++ b/test/org/apache/jasper/compiler/TestCompiler.java
@@ -48,7 +48,8 @@ public class TestCompiler extends TomcatBaseTest {
         assertEcho(result, "OK");
 
         // Check content type
-        Assert.assertTrue(headers.get("Content-Type").get(0).startsWith("text/html"));
+        String contentType = getSingleHeader("Content-Type", headers);
+        Assert.assertTrue(contentType.startsWith("text/html"));
     }
 
     @Test
@@ -66,7 +67,8 @@ public class TestCompiler extends TomcatBaseTest {
         assertEcho(result, "OK");
 
         // Check content type
-        Assert.assertTrue(headers.get("Content-Type").get(0).startsWith("text/plain"));
+        String contentType = getSingleHeader("Content-Type", headers);
+        Assert.assertTrue(contentType.startsWith("text/plain"));
     }
 
     @Test
diff --git a/test/org/apache/jasper/compiler/TestGenerator.java b/test/org/apache/jasper/compiler/TestGenerator.java
index 78c4feb..ca6f568 100644
--- a/test/org/apache/jasper/compiler/TestGenerator.java
+++ b/test/org/apache/jasper/compiler/TestGenerator.java
@@ -19,9 +19,6 @@ package org.apache.jasper.compiler;
 
 import java.io.IOException;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.jsp.JspException;
@@ -183,10 +180,7 @@ public class TestGenerator extends TomcatBaseTest {
         getTomcatInstanceTestWebapp(false, true);
 
         ByteChunk res = new ByteChunk();
-        Map<String,List<String>> headers = new HashMap<>();
-
-        getUrl("http://localhost:" + getPort() + "/test/bug49nnn/bug49799.jsp",
-                res, headers);
+        getUrl("http://localhost:" + getPort() + "/test/bug49nnn/bug49799.jsp", res, null);
 
         // Check request completed
         String result = res.toString();
diff --git a/test/org/apache/jasper/compiler/TestParser.java b/test/org/apache/jasper/compiler/TestParser.java
index 0a79a16..c9035be 100644
--- a/test/org/apache/jasper/compiler/TestParser.java
+++ b/test/org/apache/jasper/compiler/TestParser.java
@@ -16,9 +16,6 @@
  */
 package org.apache.jasper.compiler;
 
-import java.util.HashMap;
-import java.util.List;
-
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -100,8 +97,7 @@ public class TestParser extends TomcatBaseTest {
         getTomcatInstanceTestWebapp(false, true);
 
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297NoSpace.jsp", new ByteChunk(),
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297NoSpace.jsp", new ByteChunk(), null);
 
         Assert.assertEquals(500, sc);
     }
@@ -111,8 +107,7 @@ public class TestParser extends TomcatBaseTest {
         getTomcatInstanceTestWebapp(false, true);
 
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297DuplicateAttr.jsp", new ByteChunk(),
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297DuplicateAttr.jsp", new ByteChunk(), null);
 
         Assert.assertEquals(500, sc);
     }
@@ -123,8 +118,7 @@ public class TestParser extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297MultipleImport1.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297MultipleImport1.jsp", res, null);
 
         Assert.assertEquals(200, sc);
         assertEcho(res.toString(), "OK");
@@ -136,8 +130,7 @@ public class TestParser extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297MultipleImport2.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297MultipleImport2.jsp", res, null);
 
         Assert.assertEquals(200, sc);
         assertEcho(res.toString(), "OK");
@@ -149,8 +142,7 @@ public class TestParser extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297MultiplePageEncoding1.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297MultiplePageEncoding1.jsp", res, null);
 
         Assert.assertEquals(500, sc);
     }
@@ -161,8 +153,7 @@ public class TestParser extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297MultiplePageEncoding2.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297MultiplePageEncoding2.jsp", res, null);
 
         Assert.assertEquals(500, sc);
     }
@@ -173,8 +164,7 @@ public class TestParser extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297MultiplePageEncoding3.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297MultiplePageEncoding3.jsp", res, null);
 
         Assert.assertEquals(500, sc);
     }
@@ -185,8 +175,7 @@ public class TestParser extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297MultiplePageEncoding4.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297MultiplePageEncoding4.jsp", res, null);
 
         Assert.assertEquals(500, sc);
     }
@@ -197,8 +186,7 @@ public class TestParser extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297Tag.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297Tag.jsp", res, null);
 
         Assert.assertEquals(200, sc);
         assertEcho(res.toString(), "OK");
diff --git a/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java b/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java
index a467239..19f9633 100644
--- a/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java
+++ b/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java
@@ -17,9 +17,6 @@
 
 package org.apache.jasper.compiler;
 
-import java.util.HashMap;
-import java.util.List;
-
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -110,8 +107,7 @@ public class TestParserNoStrictWhitespace extends TomcatBaseTest {
 
         ByteChunk res = new ByteChunk();
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297NoSpace.jsp", res,
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297NoSpace.jsp", res, null);
 
 
         Assert.assertEquals(200, sc);
@@ -123,8 +119,7 @@ public class TestParserNoStrictWhitespace extends TomcatBaseTest {
         getTomcatInstanceTestWebapp(false, true);
 
         int sc = getUrl("http://localhost:" + getPort() +
-                "/test/bug49nnn/bug49297DuplicateAttr.jsp", new ByteChunk(),
-                new HashMap<String,List<String>>());
+                "/test/bug49nnn/bug49297DuplicateAttr.jsp", new ByteChunk(), null);
 
         Assert.assertEquals(500, sc);
     }
diff --git a/test/org/apache/jasper/servlet/TestTldScanner.java b/test/org/apache/jasper/servlet/TestTldScanner.java
index 34b8c6c..4bae692 100644
--- a/test/org/apache/jasper/servlet/TestTldScanner.java
+++ b/test/org/apache/jasper/servlet/TestTldScanner.java
@@ -84,7 +84,8 @@ public class TestTldScanner extends TomcatBaseTest {
 
 
         // Check content type
-        Assert.assertTrue(headers.get("Content-Type").get(0).startsWith("text/html"));
+        String contentType = getSingleHeader("Content-Type", headers);
+        Assert.assertTrue(contentType.startsWith("text/html"));
     }
 
 


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


[tomcat] 01/03: Convert TestExpireFilter to use the built-in getUrl() methods

Posted by ma...@apache.org.
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

commit 0ae3ddeefe30047a88aabbcdf129947913a4153b
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Nov 11 10:29:01 2019 +0000

    Convert TestExpireFilter to use the built-in getUrl() methods
    
    This is to support future changes to the tests for related to bug 63909
---
 .../apache/catalina/filters/TestExpiresFilter.java | 30 +++++++++++++++-------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/test/org/apache/catalina/filters/TestExpiresFilter.java b/test/org/apache/catalina/filters/TestExpiresFilter.java
index b37ca43..d6a2429 100644
--- a/test/org/apache/catalina/filters/TestExpiresFilter.java
+++ b/test/org/apache/catalina/filters/TestExpiresFilter.java
@@ -19,9 +19,10 @@ package org.apache.catalina.filters;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
-import java.net.URL;
 import java.util.Calendar;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.StringTokenizer;
 import java.util.TimeZone;
@@ -41,6 +42,7 @@ import org.apache.catalina.filters.ExpiresFilter.ExpiresConfiguration;
 import org.apache.catalina.filters.ExpiresFilter.StartingPoint;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.descriptor.web.FilterDef;
 import org.apache.tomcat.util.descriptor.web.FilterMap;
 
@@ -408,16 +410,15 @@ public class TestExpiresFilter extends TomcatBaseTest {
             long timeBeforeInMillis = System.currentTimeMillis();
 
             // TEST
-            HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(
-                    "http://localhost:" + tomcat.getConnector().getLocalPort() +
-                            "/test").openConnection();
+            ByteChunk bc = new ByteChunk();
+            Map<String,List<String>> responseHeaders = new HashMap<>();
+            int rc = getUrl("http://localhost:" + getPort() + "/test", bc, responseHeaders);
 
             // VALIDATE
-            Assert.assertEquals(expectedResponseStatusCode,
-                    httpURLConnection.getResponseCode());
+            Assert.assertEquals(expectedResponseStatusCode, rc);
 
             StringBuilder msg = new StringBuilder();
-            for (Entry<String, List<String>> field : httpURLConnection.getHeaderFields().entrySet()) {
+            for (Entry<String, List<String>> field : responseHeaders.entrySet()) {
                 for (String value : field.getValue()) {
                     msg.append((field.getKey() == null ? "" : field.getKey() +
                             ": ") +
@@ -428,7 +429,12 @@ public class TestExpiresFilter extends TomcatBaseTest {
 
             Integer actualMaxAgeInSeconds;
 
-            String cacheControlHeader = httpURLConnection.getHeaderField("Cache-Control");
+            String cacheControlHeader = null;
+            List<String> cacheControlHeaders = responseHeaders.get("Cache-Control");
+            if (cacheControlHeaders != null && cacheControlHeaders.size() == 1) {
+                cacheControlHeader = cacheControlHeaders.get(0);
+            }
+
             if (cacheControlHeader == null) {
                 actualMaxAgeInSeconds = null;
             } else {
@@ -459,13 +465,19 @@ public class TestExpiresFilter extends TomcatBaseTest {
 
             Assert.assertNotNull(actualMaxAgeInSeconds);
 
+            String contentType = null;
+            List<String> contentTypeHeaders = responseHeaders.get("Content-Type");
+            if (contentTypeHeaders != null && contentTypeHeaders.size() == 1) {
+                contentType = contentTypeHeaders.get(0);
+            }
+
             int deltaInSeconds = Math.abs(actualMaxAgeInSeconds.intValue() -
                     expectedMaxAgeInSeconds.intValue());
             Assert.assertTrue("actualMaxAgeInSeconds: " +
                     actualMaxAgeInSeconds + ", expectedMaxAgeInSeconds: " +
                     expectedMaxAgeInSeconds + ", request time: " +
                     timeBeforeInMillis + " for content type " +
-                    httpURLConnection.getContentType(), deltaInSeconds < 3);
+                    contentType, deltaInSeconds < 3);
 
         } finally {
             tomcat.stop();


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


[tomcat] 03/03: Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63909

Posted by ma...@apache.org.
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

commit 28c60f19a3660329e06a6455753584c6c8450eb8
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Nov 11 14:41:12 2019 +0000

    Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63909
    
    When the ExpiresFilter is used without a default and the response is
    served by the Default Servlet, ensure that the filter processes the
    response if the Default Servlet sets a 304 (Not Found) status code.
---
 .../org/apache/catalina/filters/ExpiresFilter.java | 48 +++++++++++--
 .../apache/catalina/filters/TestExpiresFilter.java | 84 ++++++++++++++++++++++
 test/webapp/bug6nnnn/bug69303.txt                  | 18 +++++
 webapps/docs/changelog.xml                         |  6 ++
 4 files changed, 150 insertions(+), 6 deletions(-)

diff --git a/java/org/apache/catalina/filters/ExpiresFilter.java b/java/org/apache/catalina/filters/ExpiresFilter.java
index f746cc2..85d5fce 100644
--- a/java/org/apache/catalina/filters/ExpiresFilter.java
+++ b/java/org/apache/catalina/filters/ExpiresFilter.java
@@ -40,6 +40,7 @@ import javax.servlet.WriteListener;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;
+import javax.servlet.http.MappingMatch;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -379,7 +380,7 @@ import org.apache.juli.logging.LogFactory;
  * {@link #isEligibleToExpirationHeaderGeneration(HttpServletRequest, XHttpServletResponse)}
  * </li>
  * <li>
- * {@link #getExpirationDate(XHttpServletResponse)}</li>
+ * {@link #getExpirationDate(HttpServletRequest, XHttpServletResponse)}</li>
  * </ul>
  * <h2>Troubleshooting</h2>
  * <p>
@@ -1247,22 +1248,57 @@ public class ExpiresFilter extends FilterBase {
         return excludedResponseStatusCodes;
     }
 
+
     /**
-     * <p>
      * Returns the expiration date of the given {@link XHttpServletResponse} or
      * {@code null} if no expiration date has been configured for the
      * declared content type.
-     * </p>
      * <p>
      * {@code protected} for extension.
-     * </p>
      *
-     * @param response The Servlet response
+     * @param response The wrapped HTTP response
+     *
      * @return the expiration date
      * @see HttpServletResponse#getContentType()
+     *
+     * @deprecated  Will be removed in Tomcat 10.
+     *              Use {@link #getExpirationDate(HttpServletRequest, XHttpServletResponse)}
      */
+    @Deprecated
     protected Date getExpirationDate(XHttpServletResponse response) {
+        return getExpirationDate((HttpServletRequest) null, response);
+    }
+
+
+    /**
+     * Returns the expiration date of the given {@link XHttpServletResponse} or
+     * {@code null} if no expiration date has been configured for the
+     * declared content type.
+     * <p>
+     * {@code protected} for extension.
+     *
+     * @param request  The HTTP request
+     * @param response The wrapped HTTP response
+     *
+     * @return the expiration date
+     * @see HttpServletResponse#getContentType()
+     */
+    protected Date getExpirationDate(HttpServletRequest request, XHttpServletResponse response) {
         String contentType = response.getContentType();
+        if (contentType == null && request != null &&
+                request.getHttpServletMapping().getMappingMatch() == MappingMatch.DEFAULT &&
+                response.getStatus() == HttpServletResponse.SC_NOT_MODIFIED) {
+            // Default servlet normally sets the content type but does not for
+            // 304 responses. Look it up.
+            String servletPath = request.getServletPath();
+            if (servletPath != null) {
+                int lastSlash = servletPath.lastIndexOf('/');
+                if (lastSlash > -1) {
+                    String fileName = servletPath.substring(lastSlash + 1);
+                    contentType = request.getServletContext().getMimeType(fileName);
+                }
+            }
+        }
         if (contentType != null) {
             contentType = contentType.toLowerCase(Locale.ENGLISH);
         }
@@ -1485,7 +1521,7 @@ public class ExpiresFilter extends FilterBase {
             return;
         }
 
-        Date expirationDate = getExpirationDate(response);
+        Date expirationDate = getExpirationDate(request, response);
         if (expirationDate == null) {
             if (log.isDebugEnabled()) {
                 log.debug(sm.getString("expiresFilter.noExpirationConfigured",
diff --git a/test/org/apache/catalina/filters/TestExpiresFilter.java b/test/org/apache/catalina/filters/TestExpiresFilter.java
index 4049eb7..1a7a5a3 100644
--- a/test/org/apache/catalina/filters/TestExpiresFilter.java
+++ b/test/org/apache/catalina/filters/TestExpiresFilter.java
@@ -18,6 +18,7 @@
 package org.apache.catalina.filters;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
@@ -42,8 +43,10 @@ import org.apache.catalina.filters.ExpiresFilter.StartingPoint;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap;
 import org.apache.tomcat.util.descriptor.web.FilterDef;
 import org.apache.tomcat.util.descriptor.web.FilterMap;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
 
 public class TestExpiresFilter extends TomcatBaseTest {
     public static final String TEMP_DIR = System.getProperty("java.io.tmpdir");
@@ -484,4 +487,85 @@ public class TestExpiresFilter extends TomcatBaseTest {
 
         Assert.assertEquals(expected, actual);
     }
+
+
+    /*
+     * Tests Expires filter with:
+     * - per content type expires
+     * - no default
+     * - Default servlet returning 304s (without content-type)
+     */
+    @Test
+    public void testBug63909() throws Exception {
+
+        Tomcat tomcat = getTomcatInstanceTestWebapp(false, false);
+        Context ctxt = (Context) tomcat.getHost().findChild("/test");
+
+        FilterDef filterDef = new FilterDef();
+        filterDef.addInitParameter("ExpiresByType text/xml;charset=utf-8", "access plus 3 minutes");
+        filterDef.addInitParameter("ExpiresByType text/xml", "access plus 5 minutes");
+        filterDef.addInitParameter("ExpiresByType text", "access plus 7 minutes");
+        filterDef.addInitParameter("ExpiresExcludedResponseStatusCodes", "");
+
+        filterDef.setFilterClass(ExpiresFilter.class.getName());
+        filterDef.setFilterName(ExpiresFilter.class.getName());
+
+        ctxt.addFilterDef(filterDef);
+
+        FilterMap filterMap = new FilterMap();
+        filterMap.setFilterName(ExpiresFilter.class.getName());
+        filterMap.addURLPatternDecoded("*");
+        ctxt.addFilterMap(filterMap);
+
+        tomcat.start();
+
+        ByteChunk bc = new ByteChunk();
+        Map<String,List<String>> requestHeaders = new CaseInsensitiveKeyMap<>();
+        List<String> ifModifiedSinceValues = new ArrayList<>();
+        ifModifiedSinceValues.add(FastHttpDateFormat.getCurrentDate());
+        requestHeaders.put("If-Modified-Since", ifModifiedSinceValues);
+        Map<String,List<String>> responseHeaders = new CaseInsensitiveKeyMap<>();
+
+        int rc = getUrl("http://localhost:" + getPort() + "/test/bug6nnnn/bug69303.txt", bc, requestHeaders, responseHeaders);
+
+        Assert.assertEquals(HttpServletResponse.SC_NOT_MODIFIED, rc);
+
+        StringBuilder msg = new StringBuilder();
+        for (Entry<String, List<String>> field : responseHeaders.entrySet()) {
+            for (String value : field.getValue()) {
+                msg.append((field.getKey() == null ? "" : field.getKey() +
+                        ": ") +
+                        value + "\n");
+            }
+        }
+        System.out.println(msg);
+
+        Integer actualMaxAgeInSeconds;
+
+        String cacheControlHeader = getSingleHeader("Cache-Control", responseHeaders);
+
+        if (cacheControlHeader == null) {
+            actualMaxAgeInSeconds = null;
+        } else {
+            actualMaxAgeInSeconds = null;
+            StringTokenizer cacheControlTokenizer = new StringTokenizer(
+                    cacheControlHeader, ",");
+            while (cacheControlTokenizer.hasMoreTokens() &&
+                    actualMaxAgeInSeconds == null) {
+                String cacheDirective = cacheControlTokenizer.nextToken();
+                StringTokenizer cacheDirectiveTokenizer = new StringTokenizer(
+                        cacheDirective, "=");
+                if (cacheDirectiveTokenizer.countTokens() == 2) {
+                    String key = cacheDirectiveTokenizer.nextToken().trim();
+                    String value = cacheDirectiveTokenizer.nextToken().trim();
+                    if (key.equalsIgnoreCase("max-age")) {
+                        actualMaxAgeInSeconds = Integer.valueOf(value);
+                    }
+                }
+            }
+        }
+
+        Assert.assertNotNull(actualMaxAgeInSeconds);
+        Assert.assertTrue(Math.abs(actualMaxAgeInSeconds.intValue() - 420) < 3);
+    }
 }
diff --git a/test/webapp/bug6nnnn/bug69303.txt b/test/webapp/bug6nnnn/bug69303.txt
new file mode 100644
index 0000000..972f9d4
--- /dev/null
+++ b/test/webapp/bug6nnnn/bug69303.txt
@@ -0,0 +1,18 @@
+================================================================================
+  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.
+================================================================================
+
+The content is not important.
\ No newline at end of file
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 970270b..c4bb27d 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -74,6 +74,12 @@
       <update>
         <bug>63905</bug> Clean up Tomcat CSS. (michaelo)
       </update>
+      <fix>
+        <bug>63909</bug>: When the <code>ExpiresFilter</code> is used without a
+        default and the response is served by the Default Servlet, ensure that
+        the filter processes the response if the Default Servlet sets a 304 (Not
+        Found) status code. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">


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