hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1658389 - in /httpcomponents/httpcore/branches/4.4.x: ./ httpcore-nio/src/main/java/org/apache/http/impl/nio/ httpcore-nio/src/test/java/org/apache/http/nio/integration/
Date Mon, 09 Feb 2015 12:51:19 GMT
Author: olegk
Date: Mon Feb  9 12:51:18 2015
New Revision: 1658389

URL: http://svn.apache.org/r1658389
Log:
Non-blocking connection should not trigger end-of-stream callback as long as there is still
data in the session input buffer

Modified:
    httpcomponents/httpcore/branches/4.4.x/RELEASE_NOTES.txt
    httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
    httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
    httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/nio/integration/TestHttpAsyncHandlersPipelining.java

Modified: httpcomponents/httpcore/branches/4.4.x/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/RELEASE_NOTES.txt?rev=1658389&r1=1658388&r2=1658389&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpcore/branches/4.4.x/RELEASE_NOTES.txt Mon Feb  9 12:51:18 2015
@@ -1,3 +1,12 @@
+Changes since 4.4
+-----------------
+
+* Non-blocking connection should not trigger end-of-stream callback as long as there is still
+  data in the session input buffer. This can cause a series of short pipelined requests to
+  fail prematurely in case of an unexpected connection termination by the opposite endpoint.

+  Contributed by Oleg Kalnichevski <olegk at apache.org>
+
+
 Release 4.4
 -----------------
 

Modified: httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java?rev=1658389&r1=1658388&r2=1658389&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
(original)
+++ httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
Mon Feb  9 12:51:18 2015
@@ -259,7 +259,7 @@ public class DefaultNHttpClientConnectio
                         resetInput();
                     }
                 }
-                if (bytesRead == -1) {
+                if (bytesRead == -1 && !this.inbuf.hasData()) {
                     handler.endOfInput(this);
                 }
             }

Modified: httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java?rev=1658389&r1=1658388&r2=1658389&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
(original)
+++ httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
Mon Feb  9 12:51:18 2015
@@ -279,7 +279,7 @@ public class DefaultNHttpServerConnectio
                         resetInput();
                     }
                 }
-                if (bytesRead == -1) {
+                if (bytesRead == -1 && !this.inbuf.hasData()) {
                     handler.endOfInput(this);
                 }
             }

Modified: httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/nio/integration/TestHttpAsyncHandlersPipelining.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/nio/integration/TestHttpAsyncHandlersPipelining.java?rev=1658389&r1=1658388&r2=1658389&view=diff
==============================================================================
--- httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/nio/integration/TestHttpAsyncHandlersPipelining.java
(original)
+++ httpcomponents/httpcore/branches/4.4.x/httpcore-nio/src/test/java/org/apache/http/nio/integration/TestHttpAsyncHandlersPipelining.java
Mon Feb  9 12:51:18 2015
@@ -29,39 +29,49 @@ package org.apache.http.nio.integration;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
+import org.apache.http.ConnectionClosedException;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpException;
+import org.apache.http.HttpHeaders;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
 import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.nio.entity.NStringEntity;
 import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
+import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
+import org.apache.http.nio.protocol.BasicAsyncResponseConsumer;
 import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
 import org.apache.http.nio.protocol.HttpAsyncExchange;
 import org.apache.http.nio.protocol.HttpAsyncExpectationVerifier;
 import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
 import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
 import org.apache.http.nio.protocol.HttpAsyncRequestHandlerMapper;
+import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
+import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
 import org.apache.http.nio.protocol.UriHttpAsyncRequestHandlerMapper;
 import org.apache.http.nio.reactor.IOReactorStatus;
 import org.apache.http.nio.reactor.ListenerEndpoint;
 import org.apache.http.nio.testserver.HttpCoreNIOTestBase;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.protocol.ImmutableHttpProcessor;
 import org.apache.http.protocol.RequestConnControl;
 import org.apache.http.protocol.RequestContent;
@@ -351,4 +361,84 @@ public class TestHttpAsyncHandlersPipeli
         }
     }
 
+    @Test
+    public void testUnexpectedConnectionClosure() throws Exception {
+        final UriHttpAsyncRequestHandlerMapper registry = new UriHttpAsyncRequestHandlerMapper();
+        registry.register("*", new BasicAsyncRequestHandler(new HttpRequestHandler() {
+
+            @Override
+            public void handle(
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
+                response.setStatusCode(HttpStatus.SC_OK);
+                response.setEntity(new StringEntity("all is well", ContentType.TEXT_PLAIN));
+            }
+
+        }));
+        registry.register("/boom", new BasicAsyncRequestHandler(new HttpRequestHandler()
{
+
+            @Override
+            public void handle(
+                    final HttpRequest request,
+                    final HttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
+                response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+                response.setHeader(HttpHeaders.CONNECTION, "Close");
+                response.setEntity(new StringEntity("boooooom!!!!!", ContentType.TEXT_PLAIN));
+            }
+
+        }));
+        final HttpHost target = start(registry, null);
+
+        this.client.setMaxPerRoute(3);
+        this.client.setMaxTotal(3);
+
+        for (int i = 0; i < 20; i++) {
+
+            final HttpAsyncRequestProducer p1 = new BasicAsyncRequestProducer(target, new
BasicHttpRequest("GET", "/"));
+            final HttpAsyncRequestProducer p2 = new BasicAsyncRequestProducer(target, new
BasicHttpRequest("GET", "/"));
+            final HttpAsyncRequestProducer p3 = new BasicAsyncRequestProducer(target, new
BasicHttpRequest("GET", "/boom"));
+            final HttpAsyncRequestProducer p4 = new BasicAsyncRequestProducer(target, new
BasicHttpRequest("GET", "/"));
+            final HttpAsyncRequestProducer p5 = new BasicAsyncRequestProducer(target, new
BasicHttpRequest("GET", "/"));
+            final List<HttpAsyncRequestProducer> requestProducers = new ArrayList<HttpAsyncRequestProducer>();
+            requestProducers.add(p1);
+            requestProducers.add(p2);
+            requestProducers.add(p3);
+            requestProducers.add(p4);
+            requestProducers.add(p5);
+
+            final HttpAsyncResponseConsumer<HttpResponse> c1 = new BasicAsyncResponseConsumer();
+            final HttpAsyncResponseConsumer<HttpResponse> c2 = new BasicAsyncResponseConsumer();
+            final HttpAsyncResponseConsumer<HttpResponse> c3 = new BasicAsyncResponseConsumer();
+            final HttpAsyncResponseConsumer<HttpResponse> c4 = new BasicAsyncResponseConsumer();
+            final HttpAsyncResponseConsumer<HttpResponse> c5 = new BasicAsyncResponseConsumer();
+            final List<HttpAsyncResponseConsumer<HttpResponse>> responseConsumers
= new ArrayList<HttpAsyncResponseConsumer<HttpResponse>>();
+            responseConsumers.add(c1);
+            responseConsumers.add(c2);
+            responseConsumers.add(c3);
+            responseConsumers.add(c4);
+            responseConsumers.add(c5);
+
+            final Future<List<HttpResponse>> future = this.client.executePipelined(target,
requestProducers, responseConsumers, null, null);
+            try {
+                future.get();
+            } catch (ExecutionException ex) {
+                final Throwable cause = ex.getCause();
+                Assert.assertTrue(cause instanceof ConnectionClosedException);
+            }
+
+            Assert.assertTrue(c1.isDone());
+            Assert.assertNotNull(c1.getResult());
+            Assert.assertTrue(c2.isDone());
+            Assert.assertNotNull(c2.getResult());
+            Assert.assertTrue(c2.isDone());
+            Assert.assertNotNull(c3.getResult());
+            Assert.assertTrue(c4.isDone());
+            Assert.assertNull(c4.getResult());
+            Assert.assertTrue(c5.isDone());
+            Assert.assertNull(c5.getResult());
+        }
+    }
+
 }



Mime
View raw message