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-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to