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 2015/05/20 11:42:17 UTC

svn commit: r1680504 - in /tomcat/trunk: java/org/apache/coyote/ java/org/apache/coyote/http2/ java/org/apache/tomcat/util/net/ test/org/apache/coyote/http2/

Author: markt
Date: Wed May 20 09:42:17 2015
New Revision: 1680504

URL: http://svn.apache.org/r1680504
Log:
Plumb in the basics (i.e. what I needed to get a request for http://localhost:8080/exmaple to progress) for reading the request. The response gets generated. Still figuring out how best to handle writing of the response.

Added:
    tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java
    tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
    tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java
    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/LocalStrings.properties
    tomcat/trunk/java/org/apache/coyote/http2/Stream.java
    tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
    tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java

Modified: tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java?rev=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java Wed May 20 09:42:17 2015
@@ -61,16 +61,32 @@ public abstract class AbstractProcessor
         response = null;
     }
 
+
+    /**
+     * Used by HTTP/2.
+     *
+     * @param coyoteRequest
+     * @param coyoteResponse
+     */
+    protected AbstractProcessor(Request coyoteRequest, Response coyoteResponse) {
+        this(null, coyoteRequest, coyoteResponse);
+    }
+
+
     public AbstractProcessor(AbstractEndpoint<?> endpoint) {
+        this(endpoint, new Request(), new Response());
+    }
+
+
+    private AbstractProcessor(AbstractEndpoint<?> endpoint, Request coyoteRequest, Response coyoteResponse) {
         this.endpoint = endpoint;
         asyncStateMachine = new AsyncStateMachine(this);
-        request = new Request();
-        response = new Response();
+        request = coyoteRequest;
+        response = coyoteResponse;
         response.setHook(this);
         request.setResponse(response);
     }
 
-
     /**
      * Update the current error state to the new error state if the new error
      * state is more severe than the current error state.

Modified: tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java Wed May 20 09:42:17 2015
@@ -648,7 +648,8 @@ public abstract class AbstractProtocol<S
                         UpgradeProtocol upgradeProtocol =
                                 getProtocol().getNegotiatedProtocol(negotiatedProtocol);
                         if (upgradeProtocol != null) {
-                            processor = upgradeProtocol.getProcessor(wrapper);
+                            processor = upgradeProtocol.getProcessor(
+                                    wrapper, getProtocol().getAdapter());
                         } else if (negotiatedProtocol.equals("http/1.1")) {
                             // Explicitly negotiated the default protocol.
                             // Obtain a processor below.

Modified: tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java?rev=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java Wed May 20 09:42:17 2015
@@ -58,5 +58,5 @@ public interface UpgradeProtocol {
      * @return A processor instance for processing a connection using this
      *         protocol.
      */
-    public Processor getProcessor(SocketWrapperBase<?> socketWrapper);
+    public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter);
 }

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=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java Wed May 20 09:42:17 2015
@@ -18,6 +18,7 @@ package org.apache.coyote.http2;
 
 import java.nio.charset.StandardCharsets;
 
+import org.apache.coyote.Adapter;
 import org.apache.coyote.Processor;
 import org.apache.coyote.UpgradeProtocol;
 import org.apache.coyote.http11.upgrade.UpgradeProcessorInternal;
@@ -45,9 +46,9 @@ public class Http2Protocol implements Up
     }
 
     @Override
-    public Processor getProcessor(SocketWrapperBase<?> socketWrapper) {
+    public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter) {
         UpgradeProcessorInternal processor =
-                new UpgradeProcessorInternal(socketWrapper, null, new Http2UpgradeHandler());
+                new UpgradeProcessorInternal(socketWrapper, null, new Http2UpgradeHandler(adapter));
         return processor;
     }
 }

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=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Wed May 20 09:42:17 2015
@@ -25,6 +25,7 @@ import java.util.Map;
 
 import javax.servlet.http.WebConnection;
 
+import org.apache.coyote.Adapter;
 import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -62,6 +63,7 @@ public class Http2UpgradeHandler extends
     private static final byte[] SETTINGS_ACK = { 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 };
     private static final byte[] GOAWAY = { 0x07, 0x00, 0x00, 0x00, 0x00 };
 
+    private final Adapter adapter;
     private volatile SocketWrapperBase<?> socketWrapper;
     private volatile boolean initialized = false;
     private volatile ConnectionPrefaceParser connectionPrefaceParser =
@@ -79,8 +81,10 @@ public class Http2UpgradeHandler extends
 
     private final Map<Integer,Stream> streams = new HashMap<>();
 
-    public Http2UpgradeHandler() {
+
+    public Http2UpgradeHandler(Adapter adapter) {
         super (STREAM_ID_ZERO);
+        this.adapter = adapter;
     }
 
 
@@ -129,6 +133,7 @@ public class Http2UpgradeHandler extends
             }
             connectionPrefaceParser = null;
 
+            // Process all the incoming data
             try {
                 while (processFrame()) {
                 }
@@ -150,6 +155,8 @@ public class Http2UpgradeHandler extends
                 return SocketState.CLOSED;
             }
 
+            // TODO process writes
+
             return SocketState.LONG;
 
         case OPEN_WRITE:
@@ -292,6 +299,10 @@ public class Http2UpgradeHandler extends
         if (padLength > 0) {
             swallowPayload(padLength);
         }
+
+        // Process this stream on a container thread
+        StreamProcessor streamProcessor = new StreamProcessor(stream, adapter, socketWrapper);
+        socketWrapper.getEndpoint().getExecutor().execute(streamProcessor);
     }
 
 
@@ -381,7 +392,6 @@ public class Http2UpgradeHandler extends
         }
 
         // Acknowledge the settings
-        // TODO Need to coordinate writes with other threads
         socketWrapper.write(true, SETTINGS_ACK, 0, SETTINGS_ACK.length);
         socketWrapper.flush(true);
     }
@@ -593,6 +603,11 @@ public class Http2UpgradeHandler extends
     }
 
 
+    String getProperty(String key) {
+        return socketWrapper.getEndpoint().getProperty(key);
+    }
+
+
     @Override
     protected final Log getLog() {
         return log;

Modified: tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties?rev=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties Wed May 20 09:42:17 2015
@@ -32,6 +32,8 @@ hpackhuffman.huffmanEncodedHpackValueDid
 
 stream.header.debug=Stream [{0}] recieved HTTP header [{1}] with value [{2}]
 
+streamProcessor.httpupgrade.notsupported=HTTP upgrade is not supported within HTTP/2 streams
+
 upgradeHandler.connectionError=An error occurred that requires the HTTP/2 connection to be closed.
 upgradeHandler.payloadTooBig=The payload is [{0}] bytes long but the maximum frame size is [{1}]
 upgradeHandler.processFrame=Processing frame of type [{0}] for stream [{2}] with flags [{1}] and payload size [{3}]

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=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Wed May 20 09:42:17 2015
@@ -16,9 +16,15 @@
  */
 package org.apache.coyote.http2;
 
+import java.io.IOException;
+
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
 import org.apache.coyote.http2.HpackDecoder.HeaderEmitter;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.res.StringManager;
 
 public class Stream extends AbstractStream implements HeaderEmitter {
@@ -26,13 +32,19 @@ public class Stream extends AbstractStre
     private static final Log log = LogFactory.getLog(Stream.class);
     private static final StringManager sm = StringManager.getManager(Stream.class);
 
+    private final Http2UpgradeHandler handler;
+    private final Request coyoteRequest = new Request();
+    private final Response coyoteResponse = new Response();
+
     private volatile long flowControlWindowSize;
 
 
     public Stream(Integer identifier, Http2UpgradeHandler handler) {
         super(identifier);
+        this.handler = handler;
         setParentStream(handler);
         flowControlWindowSize = handler.getRemoteSettings().getInitialWindowSize();
+        coyoteResponse.setOutputBuffer(new StreamOutputBuffer());
     }
 
 
@@ -47,7 +59,49 @@ public class Stream extends AbstractStre
             log.debug(sm.getString("stream.header.debug", getIdentifier(), name, value));
         }
 
-        // TODO: Do something with these headers
+        switch(name) {
+        case ":method": {
+            coyoteRequest.method().setString(value);
+            break;
+        }
+        case ":path": {
+            coyoteRequest.requestURI().setString(value);
+            // TODO: This is almost certainly wrong and needs to be decoded
+            coyoteRequest.decodedURI().setString(value);
+            break;
+        }
+        case ":authority": {
+            int i = value.lastIndexOf(':');
+            if (i > -1) {
+                coyoteRequest.serverName().setString(value.substring(0, i));
+                coyoteRequest.setServerPort(Integer.parseInt(value.substring(i + 1)));
+            } else {
+                coyoteRequest.serverName().setString(value);
+                boolean secure = Boolean.parseBoolean(handler.getProperty("secure"));
+                if (secure) {
+                    coyoteRequest.setServerPort(443);
+                } else {
+                    coyoteRequest.setServerPort(80);
+                }
+            }
+            break;
+        }
+        default: {
+            // Assume other HTTP header
+            coyoteRequest.getMimeHeaders().addValue(name).setString(value);
+        }
+        }
+    }
+
+
+    void writeHeaders() {
+        // Format the frames.
+        // TODO
+    }
+
+
+    void flushData() {
+        // TODO
     }
 
 
@@ -55,4 +109,33 @@ public class Stream extends AbstractStre
     protected final Log getLog() {
         return log;
     }
+
+
+    public Request getCoyoteRequest() {
+        return coyoteRequest;
+    }
+
+
+    public Response getCoyoteResponse() {
+        return coyoteResponse;
+    }
+
+
+    private class StreamOutputBuffer implements OutputBuffer {
+
+        private volatile long written = 0;
+
+        @Override
+        public int doWrite(ByteChunk chunk) throws IOException {
+            // TODO Blocking. Write to buffer. flushData() if full.
+            log.debug("Write [" + chunk.getLength() + "] bytes");
+            written += chunk.getLength();
+            return chunk.getLength();
+        }
+
+        @Override
+        public long getBytesWritten() {
+            return written;
+        }
+    }
 }

Added: tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java?rev=1680504&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java (added)
+++ tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java Wed May 20 09:42:17 2015
@@ -0,0 +1,147 @@
+/*
+ *  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.coyote.http2;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.servlet.http.HttpUpgradeHandler;
+
+import org.apache.coyote.AbstractProcessor;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Adapter;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.SocketWrapperBase;
+import org.apache.tomcat.util.res.StringManager;
+
+public class StreamProcessor extends AbstractProcessor implements Runnable {
+
+    private static final Log log = LogFactory.getLog(StreamProcessor.class);
+    private static final StringManager sm = StringManager.getManager(StreamProcessor.class);
+
+    private final Stream stream;
+
+
+    public StreamProcessor(Stream stream, Adapter adapter, SocketWrapperBase<?> socketWrapper) {
+        super(stream.getCoyoteRequest(), stream.getCoyoteResponse());
+        this.stream = stream;
+        setAdapter(adapter);
+        setSocketWrapper(socketWrapper);
+    }
+
+
+    @Override
+    public void run() {
+        try {
+            adapter.service(request, response);
+            // Ensure the response is complete
+            response.action(ActionCode.CLIENT_FLUSH, null);
+        } catch (Exception e) {
+            // TODO
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public SocketState process(SocketWrapperBase<?> socket) throws IOException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+
+    @Override
+    public SocketState dispatch(SocketStatus status) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+
+    @Override
+    public void action(ActionCode actionCode, Object param) {
+        switch (actionCode) {
+        case REQ_HOST_ATTRIBUTE: {
+            request.remoteHost().setString(socketWrapper.getRemoteHost());
+            break;
+        }
+        case IS_ERROR: {
+            ((AtomicBoolean) param).set(getErrorState().isError());
+            break;
+        }
+        case CLIENT_FLUSH: {
+            action(ActionCode.COMMIT, null);
+            stream.flushData();
+            break;
+        }
+        case COMMIT: {
+            if (!response.isCommitted()) {
+                response.setCommitted(true);
+                stream.writeHeaders();
+            }
+            break;
+        }
+        default:
+            // TODO
+            log.debug("TODO: Action: " + actionCode);
+        }
+    }
+
+
+    @Override
+    public void recycle() {
+        // TODO Auto-generated method stub
+
+    }
+
+
+    @Override
+    public void setSslSupport(SSLSupport sslSupport) {
+        // TODO Auto-generated method stub
+
+    }
+
+
+    @Override
+    public boolean isUpgrade() {
+        return false;
+    }
+
+
+    @Override
+    protected Log getLog() {
+        return log;
+    }
+
+
+    @Override
+    public HttpUpgradeHandler getHttpUpgradeHandler() {
+        // Should never happen
+        throw new IllegalStateException(sm.getString("streamProcessor.httpupgrade.notsupported"));
+    }
+
+
+    @Override
+    public ByteBuffer getLeftoverInput() {
+        // Should never happen
+        throw new IllegalStateException(sm.getString("streamProcessor.httpupgrade.notsupported"));
+    }
+}

Propchange: tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Wed May 20 09:42:17 2015
@@ -2510,7 +2510,7 @@ public class AprEndpoint extends Abstrac
             if (result > 0) {
                 socketReadBuffer.position(socketReadBuffer.position() + result);
                 return result;
-            } else if (-result == Status.EAGAIN) {
+            } else if (result == 0 || -result == Status.EAGAIN) {
                 return 0;
             } else if (-result == Status.APR_EGENERAL && isSecure()) {
                 // Not entirely sure why this is necessary. Testing to date has not

Modified: tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java?rev=1680504&r1=1680503&r2=1680504&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java Wed May 20 09:42:17 2015
@@ -28,7 +28,7 @@ public class TestAbstractStream {
     @Test
     public void testDependenciesFig3() {
         // Setup
-        Http2UpgradeHandler handler = new Http2UpgradeHandler();
+        Http2UpgradeHandler handler = new Http2UpgradeHandler(null);
         Stream a = new Stream(Integer.valueOf(1), handler);
         Stream b = new Stream(Integer.valueOf(2), handler);
         Stream c = new Stream(Integer.valueOf(3), handler);
@@ -59,7 +59,7 @@ public class TestAbstractStream {
     @Test
     public void testDependenciesFig4() {
         // Setup
-        Http2UpgradeHandler handler = new Http2UpgradeHandler();
+        Http2UpgradeHandler handler = new Http2UpgradeHandler(null);
         Stream a = new Stream(Integer.valueOf(1), handler);
         Stream b = new Stream(Integer.valueOf(2), handler);
         Stream c = new Stream(Integer.valueOf(3), handler);
@@ -90,7 +90,7 @@ public class TestAbstractStream {
     @Test
     public void testDependenciesFig5NonExclusive() {
         // Setup
-        Http2UpgradeHandler handler = new Http2UpgradeHandler();
+        Http2UpgradeHandler handler = new Http2UpgradeHandler(null);
         Stream a = new Stream(Integer.valueOf(1), handler);
         Stream b = new Stream(Integer.valueOf(2), handler);
         Stream c = new Stream(Integer.valueOf(3), handler);
@@ -132,7 +132,7 @@ public class TestAbstractStream {
     @Test
     public void testDependenciesFig5Exclusive() {
         // Setup
-        Http2UpgradeHandler handler = new Http2UpgradeHandler();
+        Http2UpgradeHandler handler = new Http2UpgradeHandler(null);
         Stream a = new Stream(Integer.valueOf(1), handler);
         Stream b = new Stream(Integer.valueOf(2), handler);
         Stream c = new Stream(Integer.valueOf(3), handler);



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