From c7cff6ec7e28f74156d8f78bada08ae5c9cabf48 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 19 May 2015 19:05:06 +0200 Subject: [PATCH] 467603 - Response 401 from server hangs client. --- .../org/eclipse/jetty/client/HttpClient.java | 2 +- .../jetty/proxy/AbstractProxyServlet.java | 10 +++-- .../jetty/proxy/AsyncMiddleManServlet.java | 5 ++- .../proxy/AsyncMiddleManServletTest.java | 40 +++++++++++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 6678007f8d2..1ca2c7598d6 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -548,7 +548,7 @@ public class HttpClient extends ContainerLifeCycle return new HttpConversation(); } - protected List getProtocolHandlers() + public List getProtocolHandlers() { return handlers; } diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java index 944e3c2c03f..08506b989b9 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java @@ -30,6 +30,7 @@ import java.util.Locale; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; + import javax.servlet.AsyncContext; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -235,10 +236,10 @@ public abstract class AbstractProxyServlet extends HttpServlet HttpClient client = newHttpClient(); - // Redirects must be proxied as is, not followed + // Redirects must be proxied as is, not followed. client.setFollowRedirects(false); - // Must not store cookies, otherwise cookies of different clients will mix + // Must not store cookies, otherwise cookies of different clients will mix. client.setCookieStore(new HttpCookieStore.Empty()); Executor executor; @@ -289,9 +290,12 @@ public abstract class AbstractProxyServlet extends HttpServlet { client.start(); - // Content must not be decoded, otherwise the client gets confused + // Content must not be decoded, otherwise the client gets confused. client.getContentDecoderFactories().clear(); + // No protocol handlers, pass everything to the client. + client.getProtocolHandlers().clear(); + return client; } catch (Exception x) diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java index daad2fdb78a..f011bb2412d 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Queue; import java.util.concurrent.TimeUnit; import java.util.zip.GZIPOutputStream; + import javax.servlet.AsyncContext; import javax.servlet.ReadListener; import javax.servlet.ServletConfig; @@ -420,7 +421,7 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet length += contentBytes; - boolean finished = contentLength > 0 && length == contentLength; + boolean finished = contentLength >= 0 && length == contentLength; transform(transformer, content, finished, buffers); int newContentBytes = 0; @@ -452,7 +453,7 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet } else { - if (contentLength > 0) + if (contentLength >= 0) proxyResponse.setContentLength(-1); // Setting the WriteListener triggers an invocation to diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java index c9121e7f07d..347028bcd38 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -1241,6 +1242,45 @@ public class AsyncMiddleManServletTest Assert.assertEquals(value1, obj.get(key1)); } + @Test + public void testServer401() throws Exception + { + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.setStatus(HttpStatus.UNAUTHORIZED_401); + response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "Basic realm=\"test\""); + } + }); + final AtomicBoolean transformed = new AtomicBoolean(); + startProxy(new AsyncMiddleManServlet() + { + @Override + protected ContentTransformer newServerResponseContentTransformer(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Response serverResponse) + { + return new AfterContentTransformer() + { + @Override + public boolean transform(Source source, Sink sink) throws IOException + { + transformed.set(true); + return false; + } + }; + } + }); + startClient(); + + ContentResponse response = client.newRequest("localhost", serverConnector.getLocalPort()) + .timeout(5, TimeUnit.SECONDS) + .send(); + + Assert.assertEquals(HttpStatus.UNAUTHORIZED_401, response.getStatus()); + Assert.assertFalse(transformed.get()); + } + private Path prepareTargetTestsDir() throws IOException { final Path targetTestsDir = MavenTestingUtils.getTargetTestingDir().toPath();