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/06/01 11:18:47 UTC
svn commit: r1682843 -
/tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
Author: markt
Date: Mon Jun 1 09:18:47 2015
New Revision: 1682843
URL: http://svn.apache.org/r1682843
Log:
Writing unit tests means we need an HTTP/2 client. Start to extract the HTTP/2 parsing code into a separate class so it can be shared by the test class and the server. This is a work in progress.
Added:
tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java (with props)
Added: tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java?rev=1682843&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java (added)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java Mon Jun 1 09:18:47 2015
@@ -0,0 +1,173 @@
+/*
+ * 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.nio.charset.StandardCharsets;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
+
+class Http2Parser {
+
+ private static final Log log = LogFactory.getLog(Http2Parser.class);
+ private static final StringManager sm = StringManager.getManager(Http2Parser.class);
+
+ private static final byte[] CLIENT_PREFACE_START =
+ "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n ".getBytes(StandardCharsets.ISO_8859_1);
+
+ private final Input input;
+ private final byte[] frameHeaderBuffer = new byte[9];
+
+ private volatile boolean readPreface = false;
+
+ Http2Parser(Input input) {
+ this.input = input;
+ }
+
+
+ /**
+ * Read and process a single frame. Once the start of a frame is read, the
+ * remainder will be read using blocking IO.
+ *
+ * @param block Should this method block until a frame is available is no
+ * frame is available immediately?
+ *
+ * @throws IOException If an IO error occurs while trying to read a frame
+ */
+ public void readFrame(boolean block) throws IOException {
+ input.fill(frameHeaderBuffer, block);
+
+ // TODO: This is incomplete
+ }
+
+
+ /**
+ * Read and validate the connection preface from input using blocking IO.
+ *
+ * @return <code>true</code> if a valid preface was read, otherwise false.
+ */
+ public boolean readConnectionPreface() {
+ if (readPreface) {
+ return true;
+ }
+
+ byte[] data = new byte[CLIENT_PREFACE_START.length];
+ try {
+ input.fill(data, true);
+ } catch (IOException ioe) {
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("http2Parser.preface.io"), ioe);
+ }
+ return false;
+ }
+
+ for (int i = 0; i < CLIENT_PREFACE_START.length; i++) {
+ if (CLIENT_PREFACE_START[i] != data[i]) {
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("http2Parser.preface.invalid",
+ new String(data, StandardCharsets.ISO_8859_1)));
+ }
+ return false;
+ }
+ }
+
+ readPreface = true;
+ return true;
+ }
+
+
+ boolean readHttpUpgradeResponse() throws IOException {
+ // Only used by test code so safe to keep this just a little larger than
+ // we are expecting.
+ ByteBuffer data = ByteBuffer.allocate(128);
+ byte[] singleByte = new byte[1];
+ // Looking for \r\n\r\n
+ int seen = 0;
+ while (seen < 4) {
+ input.fill(singleByte, true);
+ switch (seen) {
+ case 0:
+ case 2: {
+ if (singleByte[0] == '\r') {
+ seen++;
+ } else {
+ seen = 0;
+ }
+ break;
+ }
+ case 1:
+ case 3: {
+ if (singleByte[0] == '\n') {
+ seen++;
+ } else {
+ seen = 0;
+ }
+ break;
+ }
+ }
+ data.put(singleByte[0]);
+ }
+
+ String response = new String(data.array(), data.arrayOffset(),
+ data.arrayOffset() + data.position(), StandardCharsets.ISO_8859_1);
+
+ String[] responseLines = response.split("\r\n");
+
+ if (responseLines.length < 3) {
+ return false;
+ }
+ if (!responseLines[0].startsWith("HTTP/1.1 101")) {
+ return false;
+ }
+ // TODO: There may be other headers.
+ if (!responseLines[1].equals("Connection: Upgrade")) {
+ return false;
+ }
+ if (!responseLines[2].startsWith("Upgrade: h2c")) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Interface that must be implemented by the source of data for the parser.
+ */
+ static interface Input {
+
+ /**
+ * Fill the given array with data unless non-blocking is requested and
+ * no data is available. If any data is available then the buffer will
+ * be filled with blocking I/O.
+ *
+ * @param data Buffer to fill
+ * @param block Should the first read into the provided buffer be a
+ * blocking read or not.
+ *
+ * @return <code>true</code> if the buffer was filled otherwise
+ * <code>false</code>
+ *
+ * @throws IOException If an I/O occurred while obtaining data with
+ * which to fill the buffer
+ */
+ boolean fill(byte[] data, boolean block) throws IOException;
+ }
+}
Propchange: tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org