Author: markt Date: Tue May 12 12:02:15 2015 New Revision: 1678919 URL: http://svn.apache.org/r1678919 Log: Add some code to read & validate the byte sequence at the start of the client preface.
Modified: 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/Http2UpgradeHandler.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java?rev=1678919&r1=1678918&r2=1678919&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Tue May 12 12:02:15 2015 @@ -17,6 +17,7 @@ package org.apache.coyote.http2; import java.io.IOException; +import java.nio.charset.StandardCharsets; import javax.servlet.http.WebConnection; @@ -26,18 +27,38 @@ import org.apache.juli.logging.LogFactor import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapperBase; +import org.apache.tomcat.util.res.StringManager; /** * This represents an HTTP/2 connection from a client to Tomcat. It is designed * on the basis that there will never be more than one thread performing I/O at * a time. + * <br> + * Currently, it appears that Firefox needs to be configured with + * network.http.spdy.enforce-tls-profile=false in order for FireFox to be able + * to connect. I'm not sure what is going wrong here since as far as I have + * found that only requires TLSv1.2. openssl s_client and Wireshark confirm that + * TLSv1.2 is used and it still doesn't work if I limit the HTTPS connector to + * TLSv1.2. There looks to be some other restriction being applied. + * */ public class Http2UpgradeHandler implements InternalHttpUpgradeHandler { private static final Log log = LogFactory.getLog(Http2UpgradeHandler.class); + private static final StringManager sm = StringManager.getManager(Http2UpgradeHandler.class); + private static final byte[] CLIENT_PREFACE_START_EXPECTED; - private SocketWrapperBase<?> socketWrapper; + private volatile SocketWrapperBase<?> socketWrapper; private volatile boolean initialized = false; + private volatile byte[] clientPrefaceStartData = new byte[CLIENT_PREFACE_START_EXPECTED.length]; + private volatile int clientPrefaceStartBytesRead = 0; + private volatile boolean readFirstFrame = false; + + + static { + CLIENT_PREFACE_START_EXPECTED = + "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1); + } @Override @@ -59,16 +80,22 @@ public class Http2UpgradeHandler impleme init(null); } + if (clientPrefaceStartBytesRead < CLIENT_PREFACE_START_EXPECTED.length) { + readClientPrefaceStart(); + if (clientPrefaceStartBytesRead == -1) { + // A fatal (for this connection) error occurred + close(); + return SocketState.CLOSED; + } + // Preface start has been read and validated. No need to keep this + // buffer hanging around in memory. + clientPrefaceStartData = null; + } + // TODO This is for debug purposes to make sure ALPN is working. log.fatal("TODO: Handle SocketStatus: " + status); - try { - socketWrapper.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - + close(); return SocketState.CLOSED; } @@ -77,4 +104,43 @@ public class Http2UpgradeHandler impleme public void destroy() { // NO-OP } + + + private void close() { + try { + socketWrapper.close(); + } catch (IOException ioe) { + log.debug(sm.getString("upgradeHandler.socketCloseFailed"), ioe); + } + } + + + private void readClientPrefaceStart() { + int read = 0; + try { + read = socketWrapper.read(false, clientPrefaceStartData, clientPrefaceStartBytesRead, + clientPrefaceStartData.length - clientPrefaceStartBytesRead); + } catch (IOException ioe) { + log.error(sm.getString("upgradeHandler.prefaceErrorIo"), ioe); + clientPrefaceStartBytesRead = -1; + return; + } + + if (read == -1) { + log.error(sm.getString("upgradeHandler.prefaceErrorEos", + Integer.toString(clientPrefaceStartBytesRead))); + clientPrefaceStartBytesRead = -1; + return; + } + + for (int i = clientPrefaceStartBytesRead; i < (clientPrefaceStartBytesRead + read); i++) { + if (clientPrefaceStartData[i] != CLIENT_PREFACE_START_EXPECTED[i]) { + log.error(sm.getString("upgradeHandler.prefaceErrorMismatch", + new String(clientPrefaceStartData, StandardCharsets.ISO_8859_1))); + clientPrefaceStartBytesRead = -1; + return; + } + } + clientPrefaceStartBytesRead += read; + } } 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=1678919&r1=1678918&r2=1678919&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties Tue May 12 12:02:15 2015 @@ -17,4 +17,9 @@ hpack.integerEncodedOverTooManyOctets=HP hpackdecoder.zeroNotValidHeaderTableIndex=Zero is not a valid header table index -hpackhuffman.huffmanEncodedHpackValueDidNotEndWithEOS=Huffman encoded value in HPACK headers did not end with EOS padding \ No newline at end of file +hpackhuffman.huffmanEncodedHpackValueDidNotEndWithEOS=Huffman encoded value in HPACK headers did not end with EOS padding + +upgradeHandler.socketCloseFailed=Error closing socket +upgradeHandler.prefaceErrorEos=Unexpected end of stream while reading opening client preface byte sequence. Only [{0}] bytes read. +upgradeHandler.prefaceErrorIo=Failed to read opening client preface byte sequence +upgradeHandler.prefaceErrorMismatch=An unexpected byte sequence was received at the start of the client preface [{0}] \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org