Author: markt
Date: Mon Jun  1 12:31:56 2015
New Revision: 1682885

URL: http://svn.apache.org/r1682885
Log:
Refactor
 - put the test only code in the test classes
 - reorganise to make it easier to test various connection scenarios
Implement a couple of TODO tests

Modified:
    tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java
    tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java
    tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_3_2.java

Modified: 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=1682885&r1=1682884&r2=1682885&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Http2Parser.java Mon Jun  1 
12:31:56 2015
@@ -17,7 +17,6 @@
 package org.apache.coyote.http2;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 
 import org.apache.juli.logging.Log;
@@ -92,61 +91,6 @@ class Http2Parser {
         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.

Modified: tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java?rev=1682885&r1=1682884&r2=1682885&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http2/Http2TestBase.java Mon Jun  1 
12:31:56 2015
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.Socket;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 
 import javax.net.SocketFactory;
@@ -29,12 +30,13 @@ import javax.servlet.http.HttpServletReq
 import javax.servlet.http.HttpServletResponse;
 
 import org.junit.Assert;
-import org.junit.Before;
 
 import org.apache.catalina.Context;
+import org.apache.catalina.LifecycleException;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.coyote.http2.Http2Parser.Input;
 import org.apache.tomcat.util.codec.binary.Base64;
 
 
@@ -52,31 +54,34 @@ public abstract class Http2TestBase exte
     }
 
     private Socket s;
+    protected Input input;
     protected Http2Parser parser;
     protected OutputStream os;
 
 
-    @Before
-    public void setup() throws Exception {
-        Tomcat tomcat = getTomcatInstance();
-
-        // Enable HTTP/2
-        Connector connector = tomcat.getConnector();
+    protected void enableHttp2() {
+        Connector connector = getTomcatInstance().getConnector();
         Http2Protocol http2Protocol = new Http2Protocol();
         // Short timeouts for now. May need to increase these for CI systems.
         http2Protocol.setReadTimeout(2000);
         http2Protocol.setKeepAliveTimeout(5000);
         http2Protocol.setWriteTimeout(2000);
         connector.addUpgradeProtocol(http2Protocol);
+    }
+
+
+    protected void configureAndStartWebApplication() throws LifecycleException 
{
+        Tomcat tomcat = getTomcatInstance();
 
-        // Add a web application
         Context ctxt = tomcat.addContext("", null);
         Tomcat.addServlet(ctxt, "simple", new SimpleServlet());
         ctxt.addServletMapping("/*", "simple");
 
-        // Start the Tomcat instance
         tomcat.start();
+    }
+
 
+    protected void openClientConnection() throws IOException {
         // Open a connection
         s = SocketFactory.getDefault().createSocket("localhost", getPort());
         s.setSoTimeout(30000);
@@ -84,23 +89,89 @@ public abstract class Http2TestBase exte
         os = s.getOutputStream();
         InputStream is = s.getInputStream();
 
-        TestInput testInput = new TestInput(is);
-        parser = new Http2Parser(testInput);
+        input = new TestInput(is);
+        parser = new Http2Parser(input);
     }
 
 
-    protected void doHttpUpgrade() throws IOException {
+    protected void doHttpUpgrade(String upgrade, boolean validate) throws 
IOException {
         byte[] upgradeRequest = ("GET / HTTP/1.1\r\n" +
                 "Host: localhost:" + getPort() + "\r\n" +
                 "Connection: Upgrade, HTTP2-Settings\r\n" +
-                "Upgrade: h2c\r\n" +
+                "Upgrade: " + upgrade + "\r\n" +
                 "HTTP2-Settings: "+ HTTP2_SETTINGS + "\r\n" +
                 "\r\n").getBytes(StandardCharsets.ISO_8859_1);
         os.write(upgradeRequest);
         os.flush();
 
-        Assert.assertTrue("Failed to read HTTP Upgrade response", 
parser.readHttpUpgradeResponse());
+        if (validate) {
+            Assert.assertTrue("Failed to read HTTP Upgrade response",
+                    readHttpUpgradeResponse());
+        }
+    }
+
+
+    boolean readHttpUpgradeResponse() throws IOException {
+        String[] responseHeaders = readHttpResponseHeaders();
+
+        if (responseHeaders.length < 3) {
+            return false;
+        }
+        if (!responseHeaders[0].startsWith("HTTP/1.1 101")) {
+            return false;
+        }
+        // TODO: There may be other headers.
+        if (!responseHeaders[1].equals("Connection: Upgrade")) {
+            return false;
+        }
+        if (!responseHeaders[2].startsWith("Upgrade: h2c")) {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    String[] readHttpResponseHeaders() throws IOException {
+        // Only used by test code so safe to keep this just a little larger 
than
+        // we are expecting.
+        ByteBuffer data = ByteBuffer.allocate(256);
+        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]);
+        }
+
+        if (seen != 4) {
+            throw new IOException("End of headers not found");
+        }
+
+        String response = new String(data.array(), data.arrayOffset(),
+                data.arrayOffset() + data.position(), 
StandardCharsets.ISO_8859_1);
 
+        return response.split("\r\n");
     }
 
 
@@ -141,10 +212,15 @@ public abstract class Http2TestBase exte
                 throws ServletException, IOException {
             // Generate content with a simple known format.
             resp.setContentType("application/octet-stream");
+
+            int count = 16 * 1024;
+            // Two bytes per entry
+            resp.setContentLengthLong(count * 2);
+
             OutputStream os = resp.getOutputStream();
             byte[] data = new byte[2];
             // 1024 * 16 * 2 bytes = 32k of content.
-            for (int i = 0; i < 1024 * 16; i++) {
+            for (int i = 0; i < count; i++) {
                 data[0] = (byte) (i & 0xFF);
                 data[1] = (byte) ((i >> 8) & 0xFF);
                 os.write(data);

Modified: tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_3_2.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_3_2.java?rev=1682885&r1=1682884&r2=1682885&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_3_2.java 
(original)
+++ tomcat/trunk/test/org/apache/coyote/http2/TestHttp2Section_3_2.java Mon Jun 
 1 12:31:56 2015
@@ -18,7 +18,9 @@ package org.apache.coyote.http2;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.Locale;
 
+import org.junit.Assert;
 import org.junit.Test;
 
 /**
@@ -35,13 +37,28 @@ public class TestHttp2Section_3_2 extend
 
     // TODO: Test initial requests with bodies of various sizes
 
-    // TODO: Test response with HTTP/2 is not enabled
+    @Test
+    public void testConnectionNoHttp2Support() throws Exception {
+        configureAndStartWebApplication();
+        openClientConnection();
+        doHttpUpgrade("h2c", false);
+        parseHttp11Response();
+    }
+
+
+    @Test
+    public void testConnectionUpgradeWrongProtocol() throws Exception {
+        enableHttp2();
+        configureAndStartWebApplication();
+        openClientConnection();
+        doHttpUpgrade("h2", false);
+        parseHttp11Response();
+    }
 
-    // TODO: Test HTTP upgrade with h2 rather tan h2c
 
     @Test(timeout=10000)
-    public void testConnectionNoPreface() throws IOException {
-        doHttpUpgrade();
+    public void testConnectionNoPreface() throws Exception {
+        setupAsFarAsUpgrade();
 
         // If we don't send the preface the server should kill the connection.
         try {
@@ -54,8 +71,8 @@ public class TestHttp2Section_3_2 extend
 
 
     @Test(timeout=10000)
-    public void testConnectionIncompletePrefaceStart() throws IOException {
-        doHttpUpgrade();
+    public void testConnectionIncompletePrefaceStart() throws Exception {
+        setupAsFarAsUpgrade();
 
         // If we send an incomplete preface the server should kill the
         // connection.
@@ -71,8 +88,8 @@ public class TestHttp2Section_3_2 extend
 
 
     @Test(timeout=10000)
-    public void testConnectionInvalidPrefaceStart() throws IOException {
-        doHttpUpgrade();
+    public void testConnectionInvalidPrefaceStart() throws Exception {
+        setupAsFarAsUpgrade();
 
         // If we send an incomplete preface the server should kill the
         // connection.
@@ -93,4 +110,34 @@ public class TestHttp2Section_3_2 extend
     // TODO: Test if client doesn't send SETTINGS as part of the preface
 
     // TODO: Test response is received on stream 1
+
+
+    private void setupAsFarAsUpgrade() throws Exception {
+        enableHttp2();
+        configureAndStartWebApplication();
+        openClientConnection();
+        doHttpUpgrade("h2c", true);
+    }
+
+
+    private void parseHttp11Response() throws IOException {
+        String[] responseHeaders = readHttpResponseHeaders();
+        Assert.assertTrue(responseHeaders[0], 
responseHeaders[0].startsWith("HTTP/1.1 200"));
+
+        // Find the content length (chunked responses not handled)
+        for (int i = 1; i < responseHeaders.length; i++) {
+            if 
(responseHeaders[i].toLowerCase(Locale.ENGLISH).startsWith("content-length")) {
+                String cl = responseHeaders[i];
+                int pos = cl.indexOf(':');
+                if (pos == -1) {
+                    throw new IOException("Invalid: [" + cl + "]");
+                }
+                int len = Integer.parseInt(cl.substring(pos + 1).trim());
+                byte[] content = new byte[len];
+                input.fill(content, true);
+                return;
+            }
+        }
+        throw new IOException("No content-length");
+    }
 }



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

Reply via email to