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/05/09 20:01:29 UTC

[03/50] httpcomponents-core git commit: HTTPCORE-434: Handling of HEAD responses without payload headers

HTTPCORE-434: Handling of HEAD responses without payload headers

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpcore/branches/4.4.x@1763889 13f79535-47bb-0310-9956-ffa450edef68


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

Branch: refs/heads/4.4.x
Commit: 441c9c46f6f2c8fb1c54c7c9233f578a4e4056a5
Parents: 5b2dee7
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Sat Oct 8 11:11:09 2016 +0000
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Sat Oct 8 11:11:09 2016 +0000

----------------------------------------------------------------------
 .../impl/DefaultConnectionReuseStrategy.java    | 42 +++++++++++++++-----
 .../TestDefaultConnectionReuseStrategy.java     | 24 +++++++++++
 2 files changed, 55 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/441c9c46/httpcore/src/main/java/org/apache/http/impl/DefaultConnectionReuseStrategy.java
----------------------------------------------------------------------
diff --git a/httpcore/src/main/java/org/apache/http/impl/DefaultConnectionReuseStrategy.java b/httpcore/src/main/java/org/apache/http/impl/DefaultConnectionReuseStrategy.java
index 8f73a6e..7a81d45 100644
--- a/httpcore/src/main/java/org/apache/http/impl/DefaultConnectionReuseStrategy.java
+++ b/httpcore/src/main/java/org/apache/http/impl/DefaultConnectionReuseStrategy.java
@@ -30,18 +30,20 @@ package org.apache.http.impl;
 import org.apache.http.ConnectionReuseStrategy;
 import org.apache.http.Header;
 import org.apache.http.HeaderIterator;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
 import org.apache.http.ParseException;
 import org.apache.http.ProtocolVersion;
 import org.apache.http.TokenIterator;
-import org.apache.http.annotation.ThreadingBehavior;
 import org.apache.http.annotation.Contract;
-import org.apache.http.message.BasicHeaderIterator;
+import org.apache.http.annotation.ThreadingBehavior;
 import org.apache.http.message.BasicTokenIterator;
 import org.apache.http.protocol.HTTP;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.util.Args;
 
 /**
@@ -78,6 +80,22 @@ public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
         Args.notNull(response, "HTTP response");
         Args.notNull(context, "HTTP context");
 
+        final HttpRequest request = (HttpRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST);
+        if (request != null) {
+            try {
+                final TokenIterator ti = new BasicTokenIterator(request.headerIterator(HttpHeaders.CONNECTION));
+                while (ti.hasNext()) {
+                    final String token = ti.nextToken();
+                    if (HTTP.CONN_CLOSE.equalsIgnoreCase(token)) {
+                        return false;
+                    }
+                }
+            } catch (final ParseException px) {
+                // invalid connection header. do not re-use
+                return false;
+            }
+        }
+
         // Check for a self-terminating entity. If the end of the entity will
         // be indicated by closing the connection, there is no keep-alive.
         final ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
@@ -87,7 +105,7 @@ public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
                 return false;
             }
         } else {
-            if (canResponseHaveBody(response)) {
+            if (canResponseHaveBody(request, response)) {
                 final Header[] clhs = response.getHeaders(HTTP.CONTENT_LEN);
                 // Do not reuse if not properly content-length delimited
                 if (clhs.length == 1) {
@@ -109,9 +127,9 @@ public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
         // Check for the "Connection" header. If that is absent, check for
         // the "Proxy-Connection" header. The latter is an unspecified and
         // broken but unfortunately common extension of HTTP.
-        Header[] connHeaders = response.getHeaders(HTTP.CONN_DIRECTIVE);
-        if (connHeaders.length == 0) {
-            connHeaders = response.getHeaders("Proxy-Connection");
+        HeaderIterator headerIterator = response.headerIterator(HTTP.CONN_DIRECTIVE);
+        if (!headerIterator.hasNext()) {
+            headerIterator = response.headerIterator("Proxy-Connection");
         }
 
         // Experimental usage of the "Connection" header in HTTP/1.0 is
@@ -137,9 +155,9 @@ public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
         // it takes precedence and indicates a non-persistent connection.
         // If there is no "close" but a "keep-alive", we take the hint.
 
-        if (connHeaders.length != 0) {
+        if (headerIterator.hasNext()) {
             try {
-                final TokenIterator ti = new BasicTokenIterator(new BasicHeaderIterator(connHeaders, null));
+                final TokenIterator ti = new BasicTokenIterator(headerIterator);
                 boolean keepalive = false;
                 while (ti.hasNext()) {
                     final String token = ti.nextToken();
@@ -156,8 +174,7 @@ public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
                 }
 
             } catch (final ParseException px) {
-                // invalid connection header means no persistent connection
-                // we don't have logging in HttpCore, so the exception is lost
+                // invalid connection header. do not re-use
                 return false;
             }
         }
@@ -180,7 +197,10 @@ public class DefaultConnectionReuseStrategy implements ConnectionReuseStrategy {
         return new BasicTokenIterator(hit);
     }
 
-    private boolean canResponseHaveBody(final HttpResponse response) {
+    private boolean canResponseHaveBody(final HttpRequest request, final HttpResponse response) {
+        if (request != null && request.getRequestLine().getMethod().equalsIgnoreCase("HEAD")) {
+            return false;
+        }
         final int status = response.getStatusLine().getStatusCode();
         return status >= HttpStatus.SC_OK
             && status != HttpStatus.SC_NO_CONTENT

http://git-wip-us.apache.org/repos/asf/httpcomponents-core/blob/441c9c46/httpcore/src/test/java/org/apache/http/impl/TestDefaultConnectionReuseStrategy.java
----------------------------------------------------------------------
diff --git a/httpcore/src/test/java/org/apache/http/impl/TestDefaultConnectionReuseStrategy.java b/httpcore/src/test/java/org/apache/http/impl/TestDefaultConnectionReuseStrategy.java
index aad37ab..44f89ce 100644
--- a/httpcore/src/test/java/org/apache/http/impl/TestDefaultConnectionReuseStrategy.java
+++ b/httpcore/src/test/java/org/apache/http/impl/TestDefaultConnectionReuseStrategy.java
@@ -28,12 +28,15 @@
 package org.apache.http.impl;
 
 import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
+import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpCoreContext;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -260,5 +263,26 @@ public class TestDefaultConnectionReuseStrategy {
         Assert.assertFalse(reuseStrategy.keepAlive(response, context));
     }
 
+    @Test
+    public void testRequestClose() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", "/");
+        request.addHeader("Connection", "close");
+        context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
+        final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+        response.addHeader("Content-Length", "10");
+        response.addHeader("Connection", "keep-alive");
+
+        Assert.assertFalse(reuseStrategy.keepAlive(response, context));
+    }
+
+    @Test
+    public void testHeadRequestWithout() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("HEAD", "/");
+        context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
+        final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
+
+        Assert.assertTrue(reuseStrategy.keepAlive(response, context));
+    }
+
 }