Author: markt
Date: Wed May 13 12:45:56 2015
New Revision: 1679196

URL: http://svn.apache.org/r1679196
Log:
Add processing support for window update frames (required initial support for 
streams)

Added:
    tomcat/trunk/java/org/apache/coyote/http2/Stream.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java
    tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java
    tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties

Modified: tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java?rev=1679196&r1=1679195&r2=1679196&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/ConnectionSettings.java Wed May 
13 12:45:56 2015
@@ -27,6 +27,7 @@ public class ConnectionSettings {
     private final Log log = LogFactory.getLog(ConnectionSettings.class);
     private final StringManager sm = 
StringManager.getManager(ConnectionSettings.class);
 
+    public static final long DEFAULT_WINDOW_SIZE = (1 << 16) - 1;
     private static final long UNLIMITED = 1 << 32; // Use the maximum possible
     private static final long MAX_WINDOW_SIZE = (1 << 31) - 1;
     private static final long MIN_MAX_FRAME_SIZE = 1 << 14;
@@ -35,7 +36,7 @@ public class ConnectionSettings {
     private volatile long headerTableSize = 4096;
     private volatile long enablePush = 1;
     private volatile long maxConcurrentStreams = UNLIMITED;
-    private volatile long initialWindowSize = (1 << 16) - 1;
+    private volatile long initialWindowSize = DEFAULT_WINDOW_SIZE;
     private volatile long maxFrameSize = MIN_MAX_FRAME_SIZE;
     private volatile long maxHeaderListSize = UNLIMITED;
 

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=1679196&r1=1679195&r2=1679196&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Wed May 
13 12:45:56 2015
@@ -19,6 +19,8 @@ package org.apache.coyote.http2;
 import java.io.EOFException;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.servlet.http.WebConnection;
 
@@ -48,11 +50,12 @@ public class Http2UpgradeHandler impleme
     private static final Log log = 
LogFactory.getLog(Http2UpgradeHandler.class);
     private static final StringManager sm = 
StringManager.getManager(Http2UpgradeHandler.class);
 
-    private static final int FRAME_SETTINGS = 4;
+    private static final int FRAME_TYPE_SETTINGS = 4;
+    private static final int FRAME_TYPE_WINDOW_UPDATE = 8;
 
     private static final byte[] SETTINGS_EMPTY = { 0x00, 0x00, 0x00, 0x04, 
0x00, 0x00, 0x00, 0x00, 0x00 };
     private static final byte[] SETTINGS_ACK = { 0x00, 0x00, 0x00, 0x04, 0x01, 
0x00, 0x00, 0x00, 0x00 };
-    private static final byte[] GOAWAY = { 0x07, 0x00, 0x00, 0x00 };
+    private static final byte[] GOAWAY = { 0x07, 0x00, 0x00, 0x00, 0x00 };
 
     private volatile SocketWrapperBase<?> socketWrapper;
     private volatile boolean initialized = false;
@@ -61,6 +64,9 @@ public class Http2UpgradeHandler impleme
     private volatile boolean firstFrame = true;
 
     private final ConnectionSettings remoteSettings = new ConnectionSettings();
+    private volatile long flowControlWindowSize = 
ConnectionSettings.DEFAULT_WINDOW_SIZE;
+
+    private final Map<Integer,Stream> streams = new HashMap<>();
 
     @Override
     public void init(WebConnection unused) {
@@ -172,9 +178,12 @@ public class Http2UpgradeHandler impleme
         int payloadSize = getPayloadSize(streamId, frameHeader);
 
         switch (frameType) {
-        case FRAME_SETTINGS:
+        case FRAME_TYPE_SETTINGS:
             processFrameSettings(flags, streamId, payloadSize);
             break;
+        case FRAME_TYPE_WINDOW_UPDATE:
+            processFrameWindowUpdate(flags, streamId, payloadSize);
+            break;
         default:
             // Unknown frame type.
             processFrameUnknown(streamId, frameType, payloadSize);
@@ -185,7 +194,8 @@ public class Http2UpgradeHandler impleme
 
     private void processFrameSettings(int flags, int streamId, int 
payloadSize) throws IOException {
         if (log.isDebugEnabled()) {
-            log.debug(sm.getString("upgradeHandler.processFrameSettings", 
Integer.toString(flags),
+            log.debug(sm.getString("upgradeHandler.processFrame",
+                    Integer.toString(FRAME_TYPE_SETTINGS), 
Integer.toString(flags),
                     Integer.toString(streamId), 
Integer.toString(payloadSize)));
         }
         // Validate the frame
@@ -211,14 +221,7 @@ public class Http2UpgradeHandler impleme
             // Process the settings
             byte[] setting = new byte[6];
             for (int i = 0; i < payloadSize / 6; i++) {
-                int read = 0;
-                while (read < 6) {
-                    int thisTime = socketWrapper.read(true, setting, read, 
setting.length - read);
-                    if (thisTime == -1) {
-                        throw new 
EOFException(sm.getString("upgradeHandler.unexpectedEos"));
-                    }
-                    read += thisTime;
-                }
+                readFully(setting);
                 int id = ((setting[0] & 0xFF) << 8) + (setting[1] & 0xFF);
                 long value = ((setting[2] & 0xFF) << 24) + ((setting[3] & 
0xFF) << 16) +
                         ((setting[4] & 0xFF) << 8) + (setting[5] & 0xFF);
@@ -233,6 +236,43 @@ public class Http2UpgradeHandler impleme
     }
 
 
+    private void processFrameWindowUpdate(int flags, int streamId, int 
payloadSize)
+            throws IOException {
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("upgradeHandler.processFrame",
+                    Integer.toString(FRAME_TYPE_WINDOW_UPDATE), 
Integer.toString(flags),
+                    Integer.toString(streamId), 
Integer.toString(payloadSize)));
+        }
+        // Validate the frame
+        if (payloadSize != 4) {
+            // TODO i18n
+            // Use stream 0 since this is always a connection error
+            throw new Http2Exception("", 0, Http2Exception.FRAME_SIZE_ERROR);
+        }
+
+        byte[] payload = new byte[4];
+        readFully(payload);
+        int windowSizeIncrement = ((payload[0] & 0x7F) << 24) + ((payload[1] & 
0xFF) << 16) +
+                ((payload[2] & 0xFF) << 8) + (payload[3] & 0xFF);
+
+        // Validate the data
+        if (windowSizeIncrement == 0) {
+            // TODO i18n
+            throw new Http2Exception("", streamId, 
Http2Exception.PROTOCOL_ERROR);
+        }
+        if (streamId == 0) {
+            flowControlWindowSize += windowSizeIncrement;
+        } else {
+            Integer key = Integer.valueOf(streamId);
+            Stream stream = streams.get(key);
+            if (stream == null) {
+                stream = new Stream(key, 
remoteSettings.getInitialWindowSize());
+            }
+            stream.incrementWindowSize(windowSizeIncrement);
+        }
+    }
+
+
     private void processFrameUnknown(int streamId, int type, int payloadSize) 
throws IOException {
         // Swallow the payload
         log.info("Swallowing [" + payloadSize + "] bytes of unknown frame type 
+ [" + type +
@@ -282,7 +322,7 @@ public class Http2UpgradeHandler impleme
         int frameType = frameHeader[3] & 0xFF;
         // Make sure the first frame is a settings frame
         if (firstFrame) {
-            if (frameType != FRAME_SETTINGS) {
+            if (frameType != FRAME_TYPE_SETTINGS) {
                 throw new 
Http2Exception(sm.getString("upgradeHandler.receivePrefaceNotSettings"),
                         0, Http2Exception.PROTOCOL_ERROR);
             } else {
@@ -296,7 +336,7 @@ public class Http2UpgradeHandler impleme
     private int getStreamIdentifier(byte[] frameHeader) {
         // MSB of [5] is reserved and must be ignored.
         return ((frameHeader[5] & 0x7F) << 24) + ((frameHeader[6] & 0xFF) << 
16) +
-                ((frameHeader[7] & 0xFF) << 6) + (frameHeader[8] & 0xFF);
+                ((frameHeader[7] & 0xFF) << 8) + (frameHeader[8] & 0xFF);
     }
 
 
@@ -353,6 +393,19 @@ public class Http2UpgradeHandler impleme
         return result;
     }
 
+
+    private void readFully(byte[] dest) throws IOException {
+        int read = 0;
+        while (read < dest.length) {
+            int thisTime = socketWrapper.read(true, dest, read, dest.length - 
read);
+            if (thisTime == -1) {
+                throw new 
EOFException(sm.getString("upgradeHandler.unexpectedEos"));
+            }
+            read += thisTime;
+        }
+    }
+
+
     private void close() {
         try {
             socketWrapper.close();

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=1679196&r1=1679195&r2=1679196&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties Wed May 
13 12:45:56 2015
@@ -30,8 +30,8 @@ hpackhuffman.huffmanEncodedHpackValueDid
 
 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}]
 upgradeHandler.processFrame.ioerror=An I/O error occurred while reading an 
incoming HTTP/2 frame
-upgradeHandler.processFrameSettings=Processing settings frame for stream [{1}] 
with flags [{0}] and payload size [{2}]
 upgradeHandler.processFrameSettings.ackWithNonZeroPayload=Settings frame 
received with the ACK flag set and payload present
 upgradeHandler.processFrameSettings.invalidPayloadSize=Settings frame received 
with a payload size of [{0}] which is not a multiple of 6
 upgradeHandler.processFrameSettings.invalidStream=Settings frame received for 
stream [{0}]

Added: 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=1679196&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (added)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Wed May 13 12:45:56 
2015
@@ -0,0 +1,39 @@
+/*
+ *  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;
+
+public class Stream {
+
+    private final Integer identifier;
+
+    private volatile long flowControlWindowSize;
+
+    public Stream(Integer identifier, long intitalWindowSize) {
+        this.identifier = identifier;
+        flowControlWindowSize = intitalWindowSize;
+    }
+
+
+    public Integer getIdentifier() {
+        return identifier;
+    }
+
+
+    public void incrementWindowSize(int windowSizeIncrement) {
+        flowControlWindowSize += windowSizeIncrement;
+    }
+}

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



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

Reply via email to