Author: markt Date: Fri Jul 6 15:26:30 2018 New Revision: 1835261 URL: http://svn.apache.org/viewvc?rev=1835261&view=rev Log: Add a utility method (and associated test cases) that adds updates / creates a Vary header with a given field name. Multiple headers will be collapsed and invalid values removed.
Added: tomcat/trunk/java/org/apache/tomcat/util/http/ResponseUtil.java (with props) tomcat/trunk/test/org/apache/tomcat/util/http/TestResponseUtil.java (with props) Added: tomcat/trunk/java/org/apache/tomcat/util/http/ResponseUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/ResponseUtil.java?rev=1835261&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/ResponseUtil.java (added) +++ tomcat/trunk/java/org/apache/tomcat/util/http/ResponseUtil.java Fri Jul 6 15:26:30 2018 @@ -0,0 +1,93 @@ +/* + * 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; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.tomcat.util.http.parser.Vary; + +public class ResponseUtil { + + private static final String VARY_HEADER = "vary"; + private static final String VARY_ALL = "*"; + + private ResponseUtil() { + // Utility class. Hide default constructor. + } + + + public static void addVaryFieldName(HttpServletResponse response, String name) { + Collection<String> varyHeaders = response.getHeaders(VARY_HEADER); + + // Short-cut if only * has been set + if (varyHeaders.size() == 1 && varyHeaders.iterator().next().trim().equals(VARY_ALL)) { + // No need to add an additional field + return; + } + + // Short-cut if no headers have been set + if (varyHeaders.size() == 0) { + response.addHeader(VARY_HEADER, name); + return; + } + + // Short-cut if "*" is added + if (VARY_ALL.equals(name.trim())) { + response.setHeader(VARY_HEADER, VARY_ALL); + return; + } + + // May be dealing with an application set header, or multiple headers. + // Header names overlap so can't use String.contains(). Have to parse + // the existing values, check if the new value is already present and + // then add it if not. The good news is field names are tokens which + // makes parsing simpler. + Set<String> fieldNames = new HashSet<>(); + + for (String varyHeader : varyHeaders) { + StringReader input = new StringReader(varyHeader); + try { + Vary.parseVary(input, fieldNames); + } catch (IOException ioe) { + // Should never happen + } + } + + if (fieldNames.contains(VARY_ALL)) { + // '*' has been added without removing other values. Optimise. + response.setHeader(VARY_HEADER, VARY_ALL); + return; + } + + // Build single header to replace current multiple headers + // Replace existing header(s) to ensure any invalid values are removed + fieldNames.add(name); + StringBuilder varyHeader = new StringBuilder(); + varyHeader.append(name); + for (String fieldName : fieldNames) { + varyHeader.append(','); + varyHeader.append(fieldName); + } + response.setHeader(VARY_HEADER, varyHeader.toString()); + } +} Propchange: tomcat/trunk/java/org/apache/tomcat/util/http/ResponseUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/trunk/test/org/apache/tomcat/util/http/TestResponseUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestResponseUtil.java?rev=1835261&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/http/TestResponseUtil.java (added) +++ tomcat/trunk/test/org/apache/tomcat/util/http/TestResponseUtil.java Fri Jul 6 15:26:30 2018 @@ -0,0 +1,182 @@ +/* + * 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; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.tomcat.unittest.TesterResponse; + +public class TestResponseUtil { + + @Test + public void testAddValidWithAll() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "host"); + Set<String> expected = new HashSet<>(); + expected.add("*"); + doTestAddVaryFieldName(response, "*", expected); + } + + + @Test + public void testAddAllWithAll() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "*"); + Set<String> expected = new HashSet<>(); + expected.add("*"); + doTestAddVaryFieldName(response, "*", expected); + } + + + @Test + public void testAddAllWithNone() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + Set<String> expected = new HashSet<>(); + expected.add("*"); + doTestAddVaryFieldName(response, "*", expected); + } + + + @Test + public void testAddValidWithValidSingleHeader() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "foo, bar"); + Set<String> expected = new HashSet<>(); + expected.add("bar"); + expected.add("foo"); + expected.add("too"); + doTestAddVaryFieldName(response, "too", expected); + } + + + @Test + public void testAddValidWithValidSingleHeaderIncludingAll() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "foo, *"); + Set<String> expected = new HashSet<>(); + expected.add("*"); + doTestAddVaryFieldName(response, "too", expected); + } + + + @Test + public void testAddValidWithValidSingleHeaderAlreadyPresent() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "foo, bar"); + Set<String> expected = new HashSet<>(); + expected.add("bar"); + expected.add("foo"); + doTestAddVaryFieldName(response, "foo", expected); + } + + + @Test + public void testAddValidWithValidHeaders() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "foo"); + response.addHeader("vary", "bar"); + Set<String> expected = new HashSet<>(); + expected.add("bar"); + expected.add("foo"); + expected.add("too"); + doTestAddVaryFieldName(response, "too", expected); + } + + + @Test + public void testAddValidWithValidHeadersIncludingAll() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "foo"); + response.addHeader("vary", "*"); + Set<String> expected = new HashSet<>(); + expected.add("*"); + doTestAddVaryFieldName(response, "too", expected); + } + + + @Test + public void testAddValidWithValidHeadersAlreadyPresent() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "foo"); + response.addHeader("vary", "bar"); + Set<String> expected = new HashSet<>(); + expected.add("bar"); + expected.add("foo"); + doTestAddVaryFieldName(response, "foo", expected); + } + + + @Test + public void testAddValidWithPartiallyValidSingleHeader() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "{{{, bar"); + Set<String> expected = new HashSet<>(); + expected.add("bar"); + expected.add("too"); + doTestAddVaryFieldName(response, "too", expected); + } + + + @Test + public void testAddValidWithPartiallyValidSingleHeaderIncludingAll() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "{{{, *"); + Set<String> expected = new HashSet<>(); + expected.add("*"); + doTestAddVaryFieldName(response, "too", expected); + } + + + @Test + public void testAddValidWithPartiallyValidSingleHeaderAlreadyPresent() { + TesterResponse response = new TesterResponse(); + response.getCoyoteResponse(); + response.addHeader("vary", "{{{, bar"); + Set<String> expected = new HashSet<>(); + expected.add("bar"); + doTestAddVaryFieldName(response, "bar", expected); + } + + + private void doTestAddVaryFieldName(TesterResponse response, String fieldName, + Set<String> expected) { + ResponseUtil.addVaryFieldName(response, fieldName); + // There will now only be one Vary header + String resultHeader = response.getHeader("vary"); + Set<String> result = new HashSet<>(); + // Deliberately do not use Vary.parseVary as it will skip invalid values. + for (String value : resultHeader.split(",")) { + result.add(value.trim()); + } + Assert.assertEquals(expected, result); + } +} Propchange: tomcat/trunk/test/org/apache/tomcat/util/http/TestResponseUtil.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org