You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2017/11/14 16:56:44 UTC

[4/4] httpcomponents-core git commit: Fixed incorrect handing of premature i/o session termination by the server side application protocol negotiator

Fixed incorrect handing of premature i/o session termination by the server side application protocol negotiator


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/commit/502f9d9a
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/tree/502f9d9a
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/diff/502f9d9a

Branch: refs/heads/master
Commit: 502f9d9acd674708ace6765e4845d9a4371a72d9
Parents: 001c901
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Tue Nov 14 17:00:27 2017 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Tue Nov 14 17:00:27 2017 +0100

----------------------------------------------------------------------
 .../impl/nio/ServerHttpProtocolNegotiator.java  | 16 +++++--
 .../hc/core5/testing/nio/Http2ALPNTest.java     | 47 ++++++++++++++++++++
 2 files changed, 59 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/502f9d9a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttpProtocolNegotiator.java
----------------------------------------------------------------------
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttpProtocolNegotiator.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttpProtocolNegotiator.java
index 64fba27..e90d825 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttpProtocolNegotiator.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/ServerHttpProtocolNegotiator.java
@@ -36,15 +36,15 @@ import javax.net.ssl.SSLSession;
 
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.http.EndpointDetails;
+import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.ProtocolVersion;
 import org.apache.hc.core5.http.URIScheme;
 import org.apache.hc.core5.http.impl.nio.HttpConnectionEventHandler;
 import org.apache.hc.core5.http.impl.nio.ServerHttp1IOEventHandler;
 import org.apache.hc.core5.http.impl.nio.ServerHttp1StreamDuplexer;
 import org.apache.hc.core5.http.impl.nio.ServerHttp1StreamDuplexerFactory;
-import org.apache.hc.core5.http2.H2ConnectionException;
-import org.apache.hc.core5.http2.H2Error;
 import org.apache.hc.core5.http2.HttpVersionPolicy;
 import org.apache.hc.core5.http2.ssl.ApplicationProtocols;
 import org.apache.hc.core5.io.ShutdownType;
@@ -111,8 +111,12 @@ public class ServerHttpProtocolNegotiator implements HttpConnectionEventHandler
     @Override
     public void inputReady(final IOSession session) {
         try {
+            boolean endOfStream = false;
             if (bytebuf.position() < PREFACE.length) {
-                session.channel().read(bytebuf);
+                final int bytesRead = session.channel().read(bytebuf);
+                if (bytesRead == -1) {
+                    endOfStream = true;
+                }
             }
             if (bytebuf.position() >= PREFACE.length) {
                 bytebuf.flip();
@@ -121,7 +125,7 @@ public class ServerHttpProtocolNegotiator implements HttpConnectionEventHandler
                 for (int i = 0; i < PREFACE.length; i++) {
                     if (bytebuf.get() != PREFACE[i]) {
                         if (expectValidH2Preface) {
-                            throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "Unexpected HTTP/2 preface");
+                            throw new HttpException("Unexpected HTTP/2 preface");
                         } else {
                             validH2Preface = false;
                         }
@@ -142,6 +146,10 @@ public class ServerHttpProtocolNegotiator implements HttpConnectionEventHandler
                     http1StreamHandler.onConnect(bytebuf);
                     http1StreamHandler.onInput();
                 }
+            } else {
+                if (endOfStream) {
+                    throw new ConnectionClosedException("Connection closed");
+                }
             }
         } catch (final Exception ex) {
             exception(session, ex);

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/502f9d9a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ALPNTest.java
----------------------------------------------------------------------
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ALPNTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ALPNTest.java
index bae22f4..3f29e26 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ALPNTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http2ALPNTest.java
@@ -30,10 +30,12 @@ package org.apache.hc.core5.testing.nio;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
 import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
@@ -67,6 +69,7 @@ import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.rules.ExternalResource;
 
 public class Http2ALPNTest {
@@ -159,6 +162,9 @@ public class Http2ALPNTest {
 
     };
 
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
     private static int javaVersion;
 
     @BeforeClass
@@ -204,4 +210,45 @@ public class Http2ALPNTest {
         Assert.assertThat(body1, CoreMatchers.equalTo("some stuff"));
     }
 
+    @Test()
+    public void testALPNStrict() throws Exception {
+
+        thrown.expect(HttpException.class);
+        thrown.expectMessage("ALPN: missing application protocol");
+
+        log.debug("Starting up test client");
+        requester = Http2MultiplexingRequesterBootstrap.bootstrap()
+                .setIOReactorConfig(IOReactorConfig.custom()
+                        .setSoTimeout(TIMEOUT)
+                        .build())
+                .setTlsStrategy(new H2ClientTlsStrategy(SSLTestContexts.createClientSSLContext()))
+                .setStrictALPNHandshake(true)
+                .setIOSessionListener(LoggingIOSessionListener.INSTANCE)
+                .setIOSessionDecorator(LoggingIOSessionDecorator.INSTANCE)
+                .setStreamListener(LoggingHttp2StreamListener.INSTANCE)
+                .create();
+
+        server.start();
+        final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(0));
+        final ListenerEndpoint listener = future.get();
+        final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
+        requester.start();
+
+        final HttpHost target = new HttpHost("localhost", address.getPort(), URIScheme.HTTPS.id);
+        final Future<Message<HttpResponse, String>> resultFuture1 = requester.execute(
+                new BasicRequestProducer("POST", target, "/stuff",
+                        new StringAsyncEntityProducer("some stuff", ContentType.TEXT_PLAIN)),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
+        try {
+            resultFuture1.get();
+            Assert.fail("ExecutionException expected");
+        } catch (final ExecutionException ex) {
+            if (ex.getCause() instanceof HttpException) {
+                throw (Exception) ex.getCause();
+            } else {
+                throw ex;
+            }
+        }
+    }
+
 }