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 2016/10/19 13:31:36 UTC

svn commit: r1765590 - in /tomcat/trunk: java/org/apache/coyote/http2/ test/org/apache/coyote/http2/ webapps/docs/ webapps/docs/config/

Author: markt
Date: Wed Oct 19 13:31:36 2016
New Revision: 1765590

URL: http://svn.apache.org/viewvc?rev=1765590&view=rev
Log:
Enable configuration of allowed trailer headers

Modified:
    tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java
    tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
    tomcat/trunk/java/org/apache/coyote/http2/Stream.java
    tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java
    tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/config/http2.xml

Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java?rev=1765590&r1=1765589&r2=1765590&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java Wed Oct 19 13:31:36 2016
@@ -17,7 +17,14 @@
 package org.apache.coyote.http2;
 
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.coyote.Adapter;
 import org.apache.coyote.Processor;
@@ -54,6 +61,9 @@ public class Http2Protocol implements Up
     // If a lower initial value is required, set it here but DO NOT change the
     // default defined above.
     private int initialWindowSize = DEFAULT_INITIAL_WINDOW_SIZE;
+    private Set<String> allowedTrailerHeaders =
+            Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
+
 
     @Override
     public String getHttpUpgradeName(boolean isSSLEnabled) {
@@ -93,7 +103,7 @@ public class Http2Protocol implements Up
         result.setMaxConcurrentStreams(getMaxConcurrentStreams());
         result.setMaxConcurrentStreamExecution(getMaxConcurrentStreamExecution());
         result.setInitialWindowSize(getInitialWindowSize());
-
+        result.setAllowedTrailerHeaders(allowedTrailerHeaders);
         return result;
     }
 
@@ -178,4 +188,43 @@ public class Http2Protocol implements Up
     public void setInitialWindowSize(int initialWindowSize) {
         this.initialWindowSize = initialWindowSize;
     }
+
+
+    public void setAllowedTrailerHeaders(String commaSeparatedHeaders) {
+        // Jump through some hoops so we don't end up with an empty set while
+        // doing updates.
+        Set<String> toRemove = new HashSet<>();
+        toRemove.addAll(allowedTrailerHeaders);
+        if (commaSeparatedHeaders != null) {
+            String[] headers = commaSeparatedHeaders.split(",");
+            for (String header : headers) {
+                String trimmedHeader = header.trim().toLowerCase(Locale.ENGLISH);
+                if (toRemove.contains(trimmedHeader)) {
+                    toRemove.remove(trimmedHeader);
+                } else {
+                    allowedTrailerHeaders.add(trimmedHeader);
+                }
+            }
+            allowedTrailerHeaders.removeAll(toRemove);
+        }
+    }
+
+
+    public String getAllowedTrailerHeaders() {
+        // Chances of a size change between these lines are small enough that a
+        // sync is unnecessary.
+        List<String> copy = new ArrayList<>(allowedTrailerHeaders.size());
+        copy.addAll(allowedTrailerHeaders);
+        StringBuilder result = new StringBuilder();
+        boolean first = true;
+        for (String header : copy) {
+            if (first) {
+                first = false;
+            } else {
+                result.append(',');
+            }
+            result.append(header);
+        }
+        return result.toString();
+    }
 }

Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java?rev=1765590&r1=1765589&r2=1765590&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Wed Oct 19 13:31:36 2016
@@ -20,6 +20,7 @@ import java.io.EOFException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -144,6 +145,10 @@ class Http2UpgradeHandler extends Abstra
     private AtomicInteger streamConcurrency = null;
     private Queue<StreamProcessor> queuedProcessors = null;
 
+    // Limits
+    private Set<String> allowedTrailerHeaders = Collections.emptySet();
+
+
     Http2UpgradeHandler(Adapter adapter, Request coyoteRequest) {
         super (STREAM_ID_ZERO);
         this.adapter = adapter;
@@ -1051,6 +1056,11 @@ class Http2UpgradeHandler extends Abstra
     }
 
 
+    boolean isTrailerHeaderAllowed(String headerName) {
+        return allowedTrailerHeaders.contains(headerName);
+    }
+
+
     // ------------------------------------------- Configuration getters/setters
 
     public long getReadTimeout() {
@@ -1098,6 +1108,11 @@ class Http2UpgradeHandler extends Abstra
     }
 
 
+    public void setAllowedTrailerHeaders(Set<String> allowedTrailerHeaders) {
+        this.allowedTrailerHeaders = allowedTrailerHeaders;
+    }
+
+
     // ----------------------------------------------- Http2Parser.Input methods
 
     @Override

Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1765590&r1=1765589&r2=1765590&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Wed Oct 19 13:31:36 2016
@@ -268,6 +268,9 @@ class Stream extends AbstractStream impl
             break;
         }
         default: {
+            if (headerState == HEADER_STATE_TRAILER && !handler.isTrailerHeaderAllowed(name)) {
+                break;
+            }
             if ("expect".equals(name) && "100-continue".equals(value)) {
                 coyoteRequest.setExpectation(true);
             }

Modified: tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java?rev=1765590&r1=1765589&r2=1765590&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java Wed Oct 19 13:31:36 2016
@@ -69,7 +69,8 @@ public abstract class Http2TestBase exte
         EMPTY_HTTP2_SETTINGS_HEADER = "HTTP2-Settings: " + Base64.encodeBase64String(empty) + "\r\n";
     }
 
-    private static final String TRAILER_HEADER_NAME = "X-TrailerTest";
+    protected static final String TRAILER_HEADER_NAME = "X-TrailerTest";
+    protected static final String TRAILER_HEADER_VALUE = "test";
 
     private Socket s;
     protected HpackEncoder hpackEncoder;
@@ -354,7 +355,7 @@ public abstract class Http2TestBase exte
         // Trailers
         if (trailersPayload != null) {
             MimeHeaders trailerHeaders = new MimeHeaders();
-            trailerHeaders.addValue(TRAILER_HEADER_NAME).setString("xxxx");
+            trailerHeaders.addValue(TRAILER_HEADER_NAME).setString(TRAILER_HEADER_VALUE);
             hpackEncoder.encode(trailerHeaders, trailersPayload);
 
             trailersPayload.flip();

Modified: tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java?rev=1765590&r1=1765589&r2=1765590&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_8_1.java Wed Oct 19 13:31:36 2016
@@ -34,7 +34,23 @@ public class TestHttp2Section_8_1 extend
 
     @Test
     public void testPostWithTrailerHeaders() throws Exception {
+        doTestPostWithTrailerHeaders(true);
+    }
+
+
+    @Test
+    public void testPostWithTrailerHeadersBlocked() throws Exception {
+        doTestPostWithTrailerHeaders(false);
+    }
+
+
+    private void doTestPostWithTrailerHeaders(boolean allowTrailerHeader) throws Exception{
         http2Connect();
+        if (allowTrailerHeader) {
+            Http2Protocol http2Protocol =
+                    (Http2Protocol) getTomcatInstance().getConnector().findUpgradeProtocols()[0];
+            http2Protocol.setAllowedTrailerHeaders(TRAILER_HEADER_NAME);
+        }
 
         byte[] headersFrameHeader = new byte[9];
         ByteBuffer headersPayload = ByteBuffer.allocate(128);
@@ -58,13 +74,22 @@ public class TestHttp2Section_8_1 extend
         parser.readFrame(true);
         parser.readFrame(true);
 
+        String len;
+        if (allowTrailerHeader) {
+            len = Integer.toString(256 + TRAILER_HEADER_VALUE.length());
+        } else {
+            len = "256";
+        }
+
         Assert.assertEquals("0-WindowSize-[256]\n" +
                 "3-WindowSize-[256]\n" +
                 "3-HeadersStart\n" +
                 "3-Header-[:status]-[200]\n" +
                 "3-Header-[date]-["+ DEFAULT_DATE + "]\n" +
                 "3-HeadersEnd\n" +
-                "3-Body-260\n" +
+                "3-Body-" +
+                len +
+                "\n" +
                 "3-EndOfStream\n",
                 output.getTrace());
     }

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1765590&r1=1765589&r2=1765590&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Oct 19 13:31:36 2016
@@ -115,6 +115,9 @@
         Add addition checks around the handling of HTTP/2 pseudo headers.
         (markt)
       </add>
+      <add>
+        Add support for trailer headers to the HTTP/2 implementation. (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Jasper">

Modified: tomcat/trunk/webapps/docs/config/http2.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http2.xml?rev=1765590&r1=1765589&r2=1765590&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/http2.xml (original)
+++ tomcat/trunk/webapps/docs/config/http2.xml Wed Oct 19 13:31:36 2016
@@ -71,6 +71,12 @@
 
   <attributes>
 
+    <attribute name="allowedTrailerHeaders" required="false">
+      <p>By default Tomcat will ignore all trailer headers when processing
+      HTTP/2 connections. For a header to be processed, it must be added to this
+      comma-separated list of header names.</p>
+    </attribute>
+
     <attribute name="initialWindowSize" required="false">
       <p>Controls the initial size of the flow control window for streams that
       Tomcat advertises to clients. If not specified, the default value of



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