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/21 15:11:33 UTC

svn commit: r1680867 - in /tomcat/trunk/java/org/apache/coyote/http2: Http2UpgradeHandler.java Stream.java StreamProcessor.java

Author: markt
Date: Thu May 21 13:11:32 2015
New Revision: 1680867

URL: http://svn.apache.org/r1680867
Log:
Get basic response body writing working.
Lots of TODOs remain (flow control is currently ignored, stream state is not stracked etc.) but it is in a state where at least some of the examples app can be used.

Modified:
    tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
    tomcat/trunk/java/org/apache/coyote/http2/Stream.java
    tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java

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=1680867&r1=1680866&r2=1680867&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Thu May 21 13:11:32 2015
@@ -66,6 +66,7 @@ public class Http2UpgradeHandler extends
     private static final int FLAG_END_OF_STREAM = 1;
     private static final int FLAG_END_OF_HEADERS = 4;
 
+    private static final int FRAME_TYPE_DATA = 0;
     private static final int FRAME_TYPE_HEADERS = 1;
     private static final int FRAME_TYPE_PRIORITY = 2;
     private static final int FRAME_TYPE_SETTINGS = 4;
@@ -701,12 +702,14 @@ public class Http2UpgradeHandler extends
                 ByteUtil.setThreeBytes(header, 0, target.limit());
                 if (first) {
                     header[3] = FRAME_TYPE_HEADERS;
+                    if (stream.getOutputBuffer().hasNoBody()) {
+                        header[4] = FLAG_END_OF_STREAM;
+                    }
                 } else {
                     header[3] = FRAME_TYPE_CONTINUATION;
                 }
                 if (state == State.COMPLETE) {
-                    // TODO Determine end of stream correctly
-                    header[4] = FLAG_END_OF_HEADERS + FLAG_END_OF_STREAM;
+                    header[4] += FLAG_END_OF_HEADERS;
                 }
                 if (log.isDebugEnabled()) {
                     log.debug(target.limit() + " bytes");
@@ -719,6 +722,29 @@ public class Http2UpgradeHandler extends
         }
     }
 
+
+    void writeBody(Stream stream, ByteBuffer data) throws IOException {
+        data.flip();
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("upgradeHandler.writeBody", Integer.toString(connectionId),
+                    stream.getIdentifier(), Integer.toString(data.remaining())));
+        }
+        synchronized (socketWrapper) {
+            // TODO Manage window sizes
+            byte[] header = new byte[9];
+            ByteUtil.setThreeBytes(header, 0, data.remaining());
+            header[3] = FRAME_TYPE_DATA;
+            if (stream.getOutputBuffer().isFinished()) {
+                header[4] = FLAG_END_OF_STREAM;
+            }
+            ByteUtil.set31Bits(header, 5, stream.getIdentifier().intValue());
+            socketWrapper.write(true, header, 0, header.length);
+            socketWrapper.write(true, data.array(), data.arrayOffset(), data.limit());
+            socketWrapper.flush(true);
+        }
+    }
+
+
     private void processWrites() throws IOException {
         if (socketWrapper.flush(false)) {
             socketWrapper.registerWriteInterest();

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=1680867&r1=1680866&r2=1680867&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Thu May 21 13:11:32 2015
@@ -17,6 +17,7 @@
 package org.apache.coyote.http2;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
 import org.apache.coyote.OutputBuffer;
 import org.apache.coyote.Request;
@@ -35,6 +36,7 @@ public class Stream extends AbstractStre
     private final Http2UpgradeHandler handler;
     private final Request coyoteRequest = new Request();
     private final Response coyoteResponse = new Response();
+    private final StreamOutputBuffer outputBuffer = new StreamOutputBuffer();
 
     private volatile long flowControlWindowSize;
 
@@ -44,7 +46,7 @@ public class Stream extends AbstractStre
         this.handler = handler;
         setParentStream(handler);
         flowControlWindowSize = handler.getRemoteSettings().getInitialWindowSize();
-        coyoteResponse.setOutputBuffer(new StreamOutputBuffer());
+        coyoteResponse.setOutputBuffer(outputBuffer);
     }
 
 
@@ -110,8 +112,12 @@ public class Stream extends AbstractStre
             log.debug(sm.getString("stream.write",
                     Long.toString(getConnectionId()), getIdentifier()));
         }
-        // TODO
-        handler.addWrite("DATA");
+        try {
+            outputBuffer.flush();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
     }
 
 
@@ -127,31 +133,76 @@ public class Stream extends AbstractStre
     }
 
 
-    public Request getCoyoteRequest() {
+    Request getCoyoteRequest() {
         return coyoteRequest;
     }
 
 
-    public Response getCoyoteResponse() {
+    Response getCoyoteResponse() {
         return coyoteResponse;
     }
 
 
-    private class StreamOutputBuffer implements OutputBuffer {
+    StreamOutputBuffer getOutputBuffer() {
+        return outputBuffer;
+    }
+
+
+    class StreamOutputBuffer implements OutputBuffer {
 
+        private volatile ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
         private volatile long written = 0;
+        private volatile boolean finished = false;
 
         @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();
+            if (finished) {
+                // TODO i18n
+                throw new IllegalStateException();
+            }
+            int len = chunk.getLength();
+            int offset = 0;
+            while (len > 0) {
+                int thisTime = Math.min(buffer.remaining(), len);
+                buffer.put(chunk.getBytes(), chunk.getOffset() + offset, thisTime);
+                offset += thisTime;
+                len -= thisTime;
+                if (!buffer.hasRemaining()) {
+                    flush();
+                }
+            }
+            written += offset;
+            return offset;
+        }
+
+        public void flush() throws IOException {
+            if (buffer.position() == 0) {
+                // Buffer is empty. Nothing to do.
+                return;
+            }
+            handler.writeBody(Stream.this, buffer);
+            buffer.clear();
         }
 
         @Override
         public long getBytesWritten() {
             return written;
         }
+
+        public void finished() {
+            finished = true;
+        }
+
+        public boolean isFinished() {
+            return finished;
+        }
+
+        /**
+         * @return <code>true</code> if it is certain that the associated
+         *         response has no body.
+         */
+        public boolean hasNoBody() {
+            return ((written == 0) && finished);
+        }
     }
 }

Modified: 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=1680867&r1=1680866&r2=1680867&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java Thu May 21 13:11:32 2015
@@ -56,7 +56,7 @@ public class StreamProcessor extends Abs
         try {
             adapter.service(request, response);
             // Ensure the response is complete
-            response.action(ActionCode.CLIENT_FLUSH, null);
+            response.action(ActionCode.CLOSE, null);
         } catch (Exception e) {
             // TODO
             e.printStackTrace();
@@ -67,12 +67,18 @@ public class StreamProcessor extends Abs
     @Override
     public void action(ActionCode actionCode, Object param) {
         switch (actionCode) {
-        case REQ_HOST_ADDR_ATTRIBUTE: {
-            request.remoteAddr().setString(socketWrapper.getRemoteAddr());
+        case COMMIT: {
+            if (!response.isCommitted()) {
+                response.setCommitted(true);
+                stream.writeHeaders();
+            }
             break;
         }
-        case IS_ERROR: {
-            ((AtomicBoolean) param).set(getErrorState().isError());
+        case CLOSE: {
+            // Tell the output buffer there will be no more data
+            stream.getOutputBuffer().finished();
+            // Then flush it
+            action(ActionCode.CLIENT_FLUSH, null);
             break;
         }
         case CLIENT_FLUSH: {
@@ -80,11 +86,12 @@ public class StreamProcessor extends Abs
             stream.flushData();
             break;
         }
-        case COMMIT: {
-            if (!response.isCommitted()) {
-                response.setCommitted(true);
-                stream.writeHeaders();
-            }
+        case REQ_HOST_ADDR_ATTRIBUTE: {
+            request.remoteAddr().setString(socketWrapper.getRemoteAddr());
+            break;
+        }
+        case IS_ERROR: {
+            ((AtomicBoolean) param).set(getErrorState().isError());
             break;
         }
 



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