You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2016/05/02 16:46:30 UTC

svn commit: r1741984 - in /tomcat/trunk: java/org/apache/coyote/ java/org/apache/coyote/ajp/ java/org/apache/coyote/http11/ java/org/apache/coyote/http11/upgrade/ java/org/apache/coyote/http2/ webapps/docs/

Author: remm
Date: Mon May  2 14:46:29 2016
New Revision: 1741984

URL: http://svn.apache.org/viewvc?rev=1741984&view=rev
Log:
59421: Allow direct (plain text most likely) connection to HTTP/2. The performance cost of the preface matching at this stage should be minimal.
Probably not polished enough, so no 8.5 port for now.

Modified:
    tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
    tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java
    tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java
    tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorBase.java
    tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorExternal.java
    tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorInternal.java
    tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java Mon May  2 14:46:29 2016
@@ -424,6 +424,16 @@ public abstract class AbstractProtocol<S
 
 
     /**
+     * Find a suitable handler for the protocol upgraded name specified. This
+     * is used for direct connection protocol selection.
+     * @param name The name of the requested negotiated protocol.
+     * @return The instance where {@link UpgradeProtocol#getAlpnName()} matches
+     *         the requested protocol
+     */
+    protected abstract UpgradeProtocol getUpgradeProtocol(String name);
+
+
+    /**
      * Create and configure a new Processor instance for the current protocol
      * implementation.
      *
@@ -433,7 +443,7 @@ public abstract class AbstractProtocol<S
 
 
     protected abstract Processor createUpgradeProcessor(
-            SocketWrapperBase<?> socket, ByteBuffer leftoverInput,
+            SocketWrapperBase<?> socket,
             UpgradeToken upgradeToken);
 
 
@@ -780,32 +790,44 @@ public abstract class AbstractProtocol<S
                     if (state == SocketState.UPGRADING) {
                         // Get the HTTP upgrade handler
                         UpgradeToken upgradeToken = processor.getUpgradeToken();
-                        HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler();
                         // Retrieve leftover input
-                        ByteBuffer leftoverInput = processor.getLeftoverInput();
-                        // Release the Http11 processor to be re-used
-                        release(processor);
-                        // Create the upgrade processor
-                        processor = getProtocol().createUpgradeProcessor(
-                                wrapper, leftoverInput, upgradeToken);
-                        // Mark the connection as upgraded
-                        wrapper.setUpgraded(true);
-                        // Associate with the processor with the connection
-                        connections.put(socket, processor);
-                        // Initialise the upgrade handler (which may trigger
-                        // some IO using the new protocol which is why the lines
-                        // above are necessary)
-                        // This cast should be safe. If it fails the error
-                        // handling for the surrounding try/catch will deal with
-                        // it.
-                        if (upgradeToken.getInstanceManager() == null) {
-                            httpUpgradeHandler.init((WebConnection) processor);
+                        ByteBuffer leftOverInput = processor.getLeftoverInput();
+                        if (upgradeToken == null) {
+                            // Assume direct HTTP/2 connection
+                            UpgradeProtocol upgradeProtocol = getProtocol().getUpgradeProtocol("h2c");
+                            if (upgradeProtocol != null) {
+                                processor = upgradeProtocol.getProcessor(
+                                        wrapper, getProtocol().getAdapter());
+                                wrapper.unRead(leftOverInput);
+                                // Associate with the processor with the connection
+                                connections.put(socket, processor);
+                            }
                         } else {
-                            ClassLoader oldCL = upgradeToken.getContextBind().bind(false, null);
-                            try {
+                            HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler();
+                            // Release the Http11 processor to be re-used
+                            release(processor);
+                            // Create the upgrade processor
+                            processor = getProtocol().createUpgradeProcessor(wrapper, upgradeToken);
+                            wrapper.unRead(leftOverInput);
+                            // Mark the connection as upgraded
+                            wrapper.setUpgraded(true);
+                            // Associate with the processor with the connection
+                            connections.put(socket, processor);
+                            // Initialise the upgrade handler (which may trigger
+                            // some IO using the new protocol which is why the lines
+                            // above are necessary)
+                            // This cast should be safe. If it fails the error
+                            // handling for the surrounding try/catch will deal with
+                            // it.
+                            if (upgradeToken.getInstanceManager() == null) {
                                 httpUpgradeHandler.init((WebConnection) processor);
-                            } finally {
-                                upgradeToken.getContextBind().unbind(false, oldCL);
+                            } else {
+                                ClassLoader oldCL = upgradeToken.getContextBind().bind(false, null);
+                                try {
+                                    httpUpgradeHandler.init((WebConnection) processor);
+                                } finally {
+                                    upgradeToken.getContextBind().unbind(false, oldCL);
+                                }
                             }
                         }
                     }

Modified: tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProtocol.java Mon May  2 14:46:29 2016
@@ -16,8 +16,6 @@
  */
 package org.apache.coyote.ajp;
 
-import java.nio.ByteBuffer;
-
 import org.apache.coyote.AbstractProtocol;
 import org.apache.coyote.Processor;
 import org.apache.coyote.UpgradeProtocol;
@@ -82,6 +80,16 @@ public abstract class AbstractAjpProtoco
     }
 
 
+    /**
+     * {@inheritDoc}
+     *
+     * AJP does not support protocol upgrade so this always returns null.
+     */
+    @Override
+    protected UpgradeProtocol getUpgradeProtocol(String name) {
+        return null;
+    }
+
     // ------------------------------------------------- AJP specific properties
     // ------------------------------------------ managed in the ProtocolHandler
 
@@ -190,7 +198,7 @@ public abstract class AbstractAjpProtoco
 
     @Override
     protected Processor createUpgradeProcessor(SocketWrapperBase<?> socket,
-            ByteBuffer leftoverInput, UpgradeToken upgradeToken) {
+            UpgradeToken upgradeToken) {
         throw new IllegalStateException(sm.getString("ajpprotocol.noUpgradeHandler",
                 upgradeToken.getHttpUpgradeHandler().getClass().getName()));
     }

Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Protocol.java Mon May  2 14:46:29 2016
@@ -16,7 +16,6 @@
  */
 package org.apache.coyote.http11;
 
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -351,6 +350,10 @@ public abstract class AbstractHttp11Prot
     public UpgradeProtocol getNegotiatedProtocol(String negotiatedName) {
         return negotiatedProtocols.get(negotiatedName);
     }
+    @Override
+    public UpgradeProtocol getUpgradeProtocol(String upgradedName) {
+        return httpUpgradeProtocols.get(upgradedName);
+    }
 
 
     // ------------------------------------------------ HTTP specific properties
@@ -643,13 +646,13 @@ public abstract class AbstractHttp11Prot
 
     @Override
     protected Processor createUpgradeProcessor(
-            SocketWrapperBase<?> socket, ByteBuffer leftoverInput,
+            SocketWrapperBase<?> socket,
             UpgradeToken upgradeToken) {
         HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler();
         if (httpUpgradeHandler instanceof InternalHttpUpgradeHandler) {
-            return new UpgradeProcessorInternal(socket, leftoverInput, upgradeToken);
+            return new UpgradeProcessorInternal(socket, upgradeToken);
         } else {
-            return new UpgradeProcessorExternal(socket, leftoverInput, upgradeToken);
+            return new UpgradeProcessorExternal(socket, upgradeToken);
         }
     }
 }

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java Mon May  2 14:46:29 2016
@@ -97,6 +97,9 @@ public class Http11InputBuffer implement
     }
 
 
+    private static final byte[] CLIENT_PREFACE_START =
+            "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1);
+
     /**
      * Associated Coyote request.
      */
@@ -407,6 +410,25 @@ public class Http11InputBuffer implement
                     // Switch to the socket timeout.
                     wrapper.setReadTimeout(wrapper.getEndpoint().getSoTimeout());
                 }
+                if (!keptAlive) {
+                    for (int i = 0; i < CLIENT_PREFACE_START.length; i++) {
+                        if (i == lastValid) {
+                            // Need more data to know if this is HTTP/2
+                            if (!fill(false)) {
+                                // A read is pending, so no longer in initial state
+                                parsingRequestLinePhase = 1;
+                                return false;
+                            }
+                        }
+                        if (CLIENT_PREFACE_START[i] != buf[i]) {
+                            break;
+                        } else if (i == CLIENT_PREFACE_START.length - 1) {
+                            // HTTP/2 preface matched
+                            parsingRequestLinePhase = -1;
+                            return false;
+                        }
+                    }
+                }
                 // Set the start time once we start reading data (even if it is
                 // just skipping blank lines)
                 if (request.getStartTime() < 0) {

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java Mon May  2 14:46:29 2016
@@ -984,7 +984,9 @@ public class Http11Processor extends Abs
             // Parsing the request header
             try {
                 if (!inputBuffer.parseRequestLine(keptAlive)) {
-                    if (handleIncompleteRequestLineRead()) {
+                    if (inputBuffer.getParsingRequestLinePhase() == -1) {
+                        return SocketState.UPGRADING;
+                    } else if (handleIncompleteRequestLineRead()) {
                         break;
                     }
                 }

Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorBase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorBase.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorBase.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorBase.java Mon May  2 14:46:29 2016
@@ -33,10 +33,9 @@ public abstract class UpgradeProcessorBa
 
     private final UpgradeToken upgradeToken;
 
-    public UpgradeProcessorBase(SocketWrapperBase<?> wrapper, ByteBuffer leftOverInput,
+    public UpgradeProcessorBase(SocketWrapperBase<?> wrapper,
             UpgradeToken upgradeToken) {
         this.upgradeToken = upgradeToken;
-        wrapper.unRead(leftOverInput);
     }
 
 

Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorExternal.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorExternal.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorExternal.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorExternal.java Mon May  2 14:46:29 2016
@@ -17,7 +17,6 @@
 package org.apache.coyote.http11.upgrade;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 
 import javax.servlet.ServletInputStream;
 import javax.servlet.ServletOutputStream;
@@ -40,13 +39,12 @@ public class UpgradeProcessorExternal ex
     private final UpgradeServletOutputStream upgradeServletOutputStream;
 
 
-    public UpgradeProcessorExternal(SocketWrapperBase<?> wrapper, ByteBuffer leftOverInput,
+    public UpgradeProcessorExternal(SocketWrapperBase<?> wrapper,
             UpgradeToken upgradeToken) {
-        super(wrapper, leftOverInput, upgradeToken);
+        super(wrapper, upgradeToken);
         this.upgradeServletInputStream = new UpgradeServletInputStream(this, wrapper);
         this.upgradeServletOutputStream = new UpgradeServletOutputStream(this, wrapper);
 
-        wrapper.unRead(leftOverInput);
         /*
          * Leave timeouts in the hands of the upgraded protocol.
          */

Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorInternal.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorInternal.java?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorInternal.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessorInternal.java Mon May  2 14:46:29 2016
@@ -17,7 +17,6 @@
 package org.apache.coyote.http11.upgrade;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 
 import javax.servlet.ServletInputStream;
 import javax.servlet.ServletOutputStream;
@@ -36,9 +35,9 @@ public class UpgradeProcessorInternal ex
 
     private final InternalHttpUpgradeHandler internalHttpUpgradeHandler;
 
-    public UpgradeProcessorInternal(SocketWrapperBase<?> wrapper, ByteBuffer leftOverInput,
+    public UpgradeProcessorInternal(SocketWrapperBase<?> wrapper,
             UpgradeToken upgradeToken) {
-        super(wrapper, leftOverInput, upgradeToken);
+        super(wrapper, upgradeToken);
         this.internalHttpUpgradeHandler = (InternalHttpUpgradeHandler) upgradeToken.getHttpUpgradeHandler();
         /*
          * Leave timeouts in the hands of the upgraded protocol.

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=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java Mon May  2 14:46:29 2016
@@ -72,7 +72,7 @@ public class Http2Protocol implements Up
 
     @Override
     public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter) {
-        UpgradeProcessorInternal processor = new UpgradeProcessorInternal(socketWrapper, null,
+        UpgradeProcessorInternal processor = new UpgradeProcessorInternal(socketWrapper,
                 new UpgradeToken(getInternalUpgradeHandler(adapter, null), null, null));
         return processor;
     }

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1741984&r1=1741983&r2=1741984&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Mon May  2 14:46:29 2016
@@ -219,6 +219,9 @@
         known issue in OpenSSL</a> that does not permit the TLS handshake to be
         failed if the ALPN negotiation fails. (markt)
       </fix>
+      <update>
+        <bug>59421</bug>: Add direct HTTP/2 connection support. (remm)
+      </update>
     </changelog>
   </subsection>
   <subsection name="WebSocket">



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


Re: svn commit: r1741984 - in /tomcat/trunk: java/org/apache/coyote/ java/org/apache/coyote/ajp/ java/org/apache/coyote/http11/ java/org/apache/coyote/http11/upgrade/ java/org/apache/coyote/http2/ webapps/docs/

Posted by jean-frederic clere <jf...@gmail.com>.
Cool now the following h2 proxy configuration of httpd (trunk) works:
+++
<VirtualHost *:8006>

   Protocols h2 http/1.1
   ProtocolsHonorOrder on
   SSLEngine on
   ....

   ProxyPass "/" "h2c://localhost:8003/"

</VirtualHost>
+++

and h2load http://localhost:8003/ works too.

On 8003 I have the tomcat running configured as:
+++
    <Connector
        port="8003"
        protocol="org.apache.coyote.http11.Http11AprProtocol">
        <UpgradeProtocol
className="org.apache.coyote.http2.Http2Protocol" />
    </Connector>
+++
thanks

Jean-Frederic

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


Re: svn commit: r1741984 - in /tomcat/trunk: java/org/apache/coyote/ java/org/apache/coyote/ajp/ java/org/apache/coyote/http11/ java/org/apache/coyote/http11/upgrade/ java/org/apache/coyote/http2/ webapps/docs/

Posted by Rémy Maucherat <re...@apache.org>.
2016-05-02 16:46 GMT+02:00 <re...@apache.org>:

> Author: remm
> Date: Mon May  2 14:46:29 2016
> New Revision: 1741984
>
> URL: http://svn.apache.org/viewvc?rev=1741984&view=rev
> Log:
> 59421: Allow direct (plain text most likely) connection to HTTP/2. The
> performance cost of the preface matching at this stage should be minimal.
> Probably not polished enough, so no 8.5 port for now.
>
> I also refactored leftover bytes handling, since passing that parameter
around no longer made sense as it all ended up with an optional
wrapper.unRead(leftOverInput).

Rémy