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