Merged branch 'master' into '431642'.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
index afe214f..9b6eec6 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
@@ -50,6 +50,7 @@
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
public class HttpRequest implements Request
@@ -449,12 +450,34 @@
@Override
public Request onResponseContent(final Response.ContentListener listener)
{
- this.responseListeners.add(new Response.ContentListener()
+ this.responseListeners.add(new Response.AsyncContentListener()
{
@Override
- public void onContent(Response response, ByteBuffer content)
+ public void onContent(Response response, ByteBuffer content, Callback callback)
{
- listener.onContent(response, content);
+ try
+ {
+ listener.onContent(response, content);
+ callback.succeeded();
+ }
+ catch (Exception x)
+ {
+ callback.failed(x);
+ }
+ }
+ });
+ return this;
+ }
+
+ @Override
+ public Request onResponseContentAsync(final Response.AsyncContentListener listener)
+ {
+ this.responseListeners.add(new Response.AsyncContentListener()
+ {
+ @Override
+ public void onContent(Response response, ByteBuffer content, Callback callback)
+ {
+ listener.onContent(response, content, callback);
}
});
return this;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java
index 6fa640c..4b82405 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java
@@ -108,6 +108,10 @@
public void notifyContent(List<Response.ResponseListener> listeners, Response response, ByteBuffer buffer)
{
+ // TODO: we need to create a "cumulative" callback that keeps track of how many listeners
+ // TODO: are invoked, and how many of these actually invoked the callback, and eventually
+ // TODO: call the callback passed to this method.
+
// Slice the buffer to avoid that listeners peek into data they should not look at.
buffer = buffer.slice();
if (!buffer.hasRemaining())
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
index cc3b5f8..b7caf08 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
@@ -338,12 +338,18 @@
Request onResponseHeaders(Response.HeadersListener listener);
/**
- * @param listener a listener for response content events
+ * @param listener a consuming listener for response content events
* @return this request object
*/
Request onResponseContent(Response.ContentListener listener);
/**
+ * @param listener an asynchronous listener for response content events
+ * @return this request object
+ */
+ Request onResponseContentAsync(Response.AsyncContentListener listener);
+
+ /**
* @param listener a listener for response success event
* @return this request object
*/
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
index 5f60ef8..f1ef5c5 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
@@ -26,6 +26,7 @@
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.util.Callback;
/**
* <p>{@link Response} represents a HTTP response and offers methods to retrieve status code, HTTP version
@@ -152,6 +153,11 @@
public void onContent(Response response, ByteBuffer content);
}
+ public interface AsyncContentListener extends ResponseListener
+ {
+ public void onContent(Response response, ByteBuffer content, Callback callback);
+ }
+
/**
* Listener for the response succeeded event.
*/
@@ -204,7 +210,7 @@
/**
* Listener for all response events.
*/
- public interface Listener extends BeginListener, HeaderListener, HeadersListener, ContentListener, SuccessListener, FailureListener, CompleteListener
+ public interface Listener extends BeginListener, HeaderListener, HeadersListener, ContentListener, AsyncContentListener, SuccessListener, FailureListener, CompleteListener
{
/**
* An empty implementation of {@link Listener}
@@ -233,6 +239,20 @@
}
@Override
+ public void onContent(Response response, ByteBuffer content, Callback callback)
+ {
+ try
+ {
+ onContent(response, content);
+ callback.succeeded();
+ }
+ catch (Exception x)
+ {
+ callback.failed(x);
+ }
+ }
+
+ @Override
public void onSuccess(Response response)
{
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
index 1b688e1..0447164 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
@@ -195,6 +195,11 @@
if (exchange == null)
return false;
+ // TODO: need to create the callback here, then check whether it has completed
+ // TODO: after the call to responseContent. If it has, return false.
+ // TODO: if it has not, return true, and when will be invoked, we need to
+ // TODO: proceed with parsing.
+
responseContent(exchange, buffer);
return false;
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
index a0af295..73ad961 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
@@ -24,6 +24,7 @@
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -33,6 +34,7 @@
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.util.ArrayQueue;
+import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
/**
@@ -83,10 +85,11 @@
*/
public class DeferredContentProvider implements AsyncContentProvider, Closeable
{
- private static final ByteBuffer CLOSE = ByteBuffer.allocate(0);
+ private static final Callback EMPTY_CALLBACK = new Callback.Adapter();
+ private static final AsyncChunk CLOSE = new AsyncChunk(BufferUtil.EMPTY_BUFFER, EMPTY_CALLBACK);
private final Object lock = this;
- private final Queue<ByteBuffer> chunks = new ArrayQueue<>(4, 64, lock);
+ private final Queue<AsyncChunk> chunks = new ArrayQueue<>(4, 64, lock);
private final AtomicReference<Listener> listener = new AtomicReference<>();
private final Iterator<ByteBuffer> iterator = new DeferredContentProviderIterator();
private final AtomicBoolean closed = new AtomicBoolean();
@@ -127,11 +130,21 @@
*/
public boolean offer(ByteBuffer buffer)
{
+ return offer(buffer, EMPTY_CALLBACK);
+ }
+
+ public boolean offer(ByteBuffer buffer, Callback callback)
+ {
+ return offer(new AsyncChunk(buffer, callback));
+ }
+
+ private boolean offer(AsyncChunk chunk)
+ {
boolean result;
synchronized (lock)
{
- result = chunks.offer(buffer);
- if (result && buffer != CLOSE)
+ result = chunks.offer(chunk);
+ if (result && chunk != CLOSE)
++size;
}
if (result)
@@ -186,7 +199,7 @@
private class DeferredContentProviderIterator implements Iterator<ByteBuffer>, Callback
{
- private ByteBuffer current;
+ private AsyncChunk current;
@Override
public boolean hasNext()
@@ -202,10 +215,10 @@
{
synchronized (lock)
{
- ByteBuffer element = current = chunks.poll();
- if (element == CLOSE)
+ AsyncChunk chunk = current = chunks.poll();
+ if (chunk == CLOSE)
throw new NoSuchElementException();
- return element;
+ return chunk == null ? null : chunk.buffer;
}
}
@@ -218,24 +231,39 @@
@Override
public void succeeded()
{
+ AsyncChunk chunk;
synchronized (lock)
{
- if (current != null)
- {
- --size;
- lock.notify();
- }
+ chunk = current;
+ --size;
+ lock.notify();
}
+ chunk.callback.succeeded();
}
@Override
public void failed(Throwable x)
{
+ AsyncChunk chunk;
synchronized (lock)
{
+ chunk = current;
failure = x;
lock.notify();
}
+ chunk.callback.failed(x);
+ }
+ }
+
+ private static class AsyncChunk
+ {
+ private final ByteBuffer buffer;
+ private final Callback callback;
+
+ private AsyncChunk(ByteBuffer buffer, Callback callback)
+ {
+ this.buffer = Objects.requireNonNull(buffer);
+ this.callback = Objects.requireNonNull(callback);
}
}
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
index bedd348..14de5bd 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
@@ -69,6 +69,7 @@
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.eclipse.jetty.toolchain.test.annotation.Slow;
+import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -986,6 +987,13 @@
}
@Override
+ public void onContent(Response response, ByteBuffer content, Callback callback)
+ {
+ // Should not be invoked
+ counter.incrementAndGet();
+ }
+
+ @Override
public void onSuccess(Response response)
{
counter.incrementAndGet();
@@ -1012,6 +1020,7 @@
.onResponseHeader(listener)
.onResponseHeaders(listener)
.onResponseContent(listener)
+ .onResponseContentAsync(listener)
.onResponseSuccess(listener)
.onResponseFailure(listener)
.send(listener);
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
new file mode 100644
index 0000000..b59dff3
--- /dev/null
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
@@ -0,0 +1,190 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.proxy;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import javax.servlet.AsyncContext;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.ContentProvider;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.util.DeferredContentProvider;
+import org.eclipse.jetty.util.Callback;
+
+public class AsyncProxyServlet extends ProxyServlet
+{
+ private static final String WRITE_LISTENER_ATTRIBUTE = AsyncProxyServlet.class.getName() + ".writeListener";
+
+ @Override
+ protected ContentProvider proxyRequestContent(AsyncContext asyncContext, final int requestId) throws IOException
+ {
+ ServletInputStream input = asyncContext.getRequest().getInputStream();
+ DeferredContentProvider provider = new DeferredContentProvider();
+ input.setReadListener(new StreamReader(input, requestId, provider));
+ return provider;
+ }
+
+ @Override
+ protected void onResponseContent(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, byte[] buffer, int offset, int length, Callback callback) throws IOException
+ {
+ StreamWriter writeListener = (StreamWriter)request.getAttribute(WRITE_LISTENER_ATTRIBUTE);
+ if (writeListener == null)
+ {
+ writeListener = new StreamWriter(request.getAsyncContext());
+ request.setAttribute(WRITE_LISTENER_ATTRIBUTE, writeListener);
+ response.getOutputStream().setWriteListener(writeListener);
+ }
+ _log.debug("{} proxying content to downstream: {} bytes", getRequestId(request), length);
+ if (writeListener.data(buffer, offset, length, callback))
+ writeListener.onWritePossible();
+ else
+ ;// TODO: fail callback
+ }
+
+ private class StreamReader implements ReadListener, Callback
+ {
+ private final byte[] buffer = new byte[512];
+ private final ServletInputStream input;
+ private final int requestId;
+ private final DeferredContentProvider provider;
+
+ public StreamReader(ServletInputStream input, int requestId, DeferredContentProvider provider)
+ {
+ this.input = input;
+ this.requestId = requestId;
+ this.provider = provider;
+ }
+
+ @Override
+ public void onDataAvailable() throws IOException
+ {
+ _log.debug("Asynchronous read start from {}", input);
+
+ // First check for isReady() because it has
+ // side effects, and then for isFinished().
+ while (input.isReady() && !input.isFinished())
+ {
+ int read = input.read(buffer);
+ _log.debug("Asynchronous read {} bytes from {}", read, input);
+ if (read > 0)
+ {
+ _log.debug("{} proxying content to upstream: {} bytes", requestId, read);
+ provider.offer(ByteBuffer.wrap(buffer, 0, read), this);
+ // Do not call isReady() so that we can apply backpressure.
+ break;
+ }
+ }
+ if (!input.isFinished())
+ _log.debug("Asynchronous read pending from {}", input);
+ }
+
+ @Override
+ public void onAllDataRead() throws IOException
+ {
+ _log.debug("{} proxying content to upstream completed", requestId);
+ provider.close();
+ }
+
+ @Override
+ public void onError(Throwable x)
+ {
+ failed(x);
+ }
+
+ @Override
+ public void succeeded()
+ {
+ // Notify the container that it may call onDataAvailable() again.
+ input.isReady();
+ }
+
+ @Override
+ public void failed(Throwable x)
+ {
+ // TODO: send a response error ?
+ // complete the async context since we cannot throw an exception from here.
+ }
+ }
+
+ private class StreamWriter implements WriteListener
+ {
+ private final AsyncContext asyncContext;
+ private byte[] buffer;
+ private int offset;
+ private int length;
+ private volatile Callback callback;
+
+ private StreamWriter(AsyncContext asyncContext)
+ {
+ this.asyncContext = asyncContext;
+ }
+
+ private boolean data(byte[] bytes, int offset, int length, Callback callback)
+ {
+ if (this.callback != null)
+ return false;
+
+ this.buffer = bytes;
+ this.offset = offset;
+ this.length = length;
+ this.callback = callback;
+ return true;
+ }
+
+ @Override
+ public void onWritePossible() throws IOException
+ {
+ if (callback == null)
+ {
+ ServletOutputStream output = asyncContext.getResponse().getOutputStream();
+ output.write(buffer, offset, length);
+ if (output.isReady())
+ complete();
+ }
+ else
+ {
+ // If we have a pending callback, it means
+ // that the write blocked but is now complete.
+ complete();
+ }
+ }
+
+ private void complete()
+ {
+ this.buffer = null;
+ this.offset = 0;
+ this.length = 0;
+ Callback callback = this.callback;
+ this.callback = null;
+ callback.succeeded();
+ }
+
+ @Override
+ public void onError(Throwable t)
+ {
+ // TODO:
+ }
+ }
+}
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
index 09217f0..8799234 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
@@ -427,25 +427,6 @@
addViaHeader(proxyRequest);
addXForwardedHeaders(proxyRequest, request);
- if (hasContent)
- {
- proxyRequest.content(new InputStreamContentProvider(request.getInputStream())
- {
- @Override
- public long getLength()
- {
- return request.getContentLength();
- }
-
- @Override
- protected ByteBuffer onRead(byte[] buffer, int offset, int length)
- {
- _log.debug("{} proxying content to upstream: {} bytes", requestId, length);
- return super.onRead(buffer, offset, length);
- }
- });
- }
-
final AsyncContext asyncContext = request.startAsync();
// We do not timeout the continuation, but the proxy request
asyncContext.setTimeout(0);
@@ -453,6 +434,9 @@
customizeProxyRequest(proxyRequest, request);
+ if (hasContent)
+ proxyRequest.content(proxyRequestContent(asyncContext, requestId));
+
if (_log.isDebugEnabled())
{
StringBuilder builder = new StringBuilder(request.getMethod());
@@ -490,6 +474,26 @@
proxyRequest.send(new ProxyResponseListener(request, response));
}
+ protected ContentProvider proxyRequestContent(final AsyncContext asyncContext, final int requestId) throws IOException
+ {
+ final HttpServletRequest request = (HttpServletRequest)asyncContext.getRequest();
+ return new InputStreamContentProvider(request.getInputStream())
+ {
+ @Override
+ public long getLength()
+ {
+ return request.getContentLength();
+ }
+
+ @Override
+ protected ByteBuffer onRead(byte[] buffer, int offset, int length)
+ {
+ _log.debug("{} proxying content to upstream: {} bytes", requestId, length);
+ return super.onRead(buffer, offset, length);
+ }
+ };
+ }
+
protected void onRewriteFailed(HttpServletRequest request, HttpServletResponse response) throws IOException
{
response.sendError(HttpServletResponse.SC_FORBIDDEN);
@@ -525,7 +529,7 @@
}
}
- protected void onResponseContent(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, byte[] buffer, int offset, int length) throws IOException
+ protected void onResponseContent(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, byte[] buffer, int offset, int length, Callback callback) throws IOException
{
response.getOutputStream().write(buffer, offset, length);
_log.debug("{} proxying content to downstream: {} bytes", getRequestId(request), length);
@@ -603,8 +607,7 @@
* <li>proxyTo - a mandatory URI like http://host:80/context to which the request is proxied.</li>
* <li>prefix - an optional URI prefix that is stripped from the start of the forwarded URI.</li>
* </ul>
- * <p/>
- * For example, if a request is received at "/foo/bar", the 'proxyTo' parameter is "http://host:80/context"
+ * For example, if a request is received at /foo/bar and the 'proxyTo' parameter is "http://host:80/context"
* and the 'prefix' parameter is "/foo", then the request would be proxied to "http://host:80/context/bar".
*/
public static class Transparent extends ProxyServlet
@@ -727,7 +730,7 @@
}
@Override
- public void onContent(Response proxyResponse, ByteBuffer content)
+ public void onContent(Response proxyResponse, ByteBuffer content, Callback callback)
{
byte[] buffer;
int offset;
@@ -746,7 +749,7 @@
try
{
- onResponseContent(request, response, proxyResponse, buffer, offset, length);
+ onResponseContent(request, response, proxyResponse, buffer, offset, length, callback);
}
catch (IOException x)
{
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
index 7c384b0..93ea5db 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
@@ -28,7 +28,7 @@
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -38,6 +38,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.zip.GZIPOutputStream;
+
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
@@ -62,10 +63,10 @@
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestTracker;
import org.eclipse.jetty.toolchain.test.annotation.Slow;
+import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StdErrLog;
@@ -76,11 +77,22 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
-@RunWith(AdvancedRunner.class)
+@RunWith(Parameterized.class)
public class ProxyServletTest
{
private static final String PROXIED_HEADER = "X-Proxied";
+
+ @Parameterized.Parameters
+ public static Iterable<Object[]> data()
+ {
+ return Arrays.asList(new Object[][]{
+ {new ProxyServlet()},
+ {new AsyncProxyServlet()}
+ });
+ }
+
@Rule
public final TestTracker tracker = new TestTracker();
private HttpClient client;
@@ -90,12 +102,17 @@
private Server server;
private ServerConnector serverConnector;
- private void prepareProxy(ProxyServlet proxyServlet) throws Exception
+ public ProxyServletTest(ProxyServlet proxyServlet)
{
- prepareProxy(proxyServlet, new HashMap<String, String>());
+ this.proxyServlet = proxyServlet;
}
- private void prepareProxy(ProxyServlet proxyServlet, Map<String, String> initParams) throws Exception
+ private void prepareProxy() throws Exception
+ {
+ prepareProxy(proxyServlet);
+ }
+
+ private void prepareProxy(ProxyServlet proxyServlet) throws Exception
{
proxy = new Server();
proxyConnector = new ServerConnector(proxy);
@@ -202,8 +219,8 @@
});
ContentResponse response = client.newRequest("localhost", serverConnector.getLocalPort())
- .timeout(5, TimeUnit.SECONDS)
- .send();
+ .timeout(5, TimeUnit.SECONDS)
+ .send();
Assert.assertEquals(500, response.getStatus());
}
@@ -263,16 +280,16 @@
}
});
- for ( int i = 0; i < 10; ++i )
+ for (int i = 0; i < 10; ++i)
{
- // Request is for the target server
+ // Request is for the target server
responses[i] = result.newRequest("localhost", serverConnector.getLocalPort())
.timeout(5, TimeUnit.SECONDS)
.send();
}
- for ( int i = 0; i < 10; ++i )
+ for (int i = 0; i < 10; ++i)
{
Assert.assertEquals(200, responses[i].getStatus());
Assert.assertTrue(responses[i].getHeaders().containsKey(PROXIED_HEADER));
@@ -811,7 +828,7 @@
}
@Override
- protected void onResponseContent(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, byte[] buffer, int offset, int length) throws IOException
+ protected void onResponseContent(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, byte[] buffer, int offset, int length, Callback callback) throws IOException
{
// Accumulate the response content
ByteArrayOutputStream baos = temp.get(request.getRequestURI());
@@ -821,7 +838,7 @@
temp.put(request.getRequestURI(), baos);
}
baos.write(buffer, offset, length);
- super.onResponseContent(request, response, proxyResponse, buffer, offset, length);
+ super.onResponseContent(request, response, proxyResponse, buffer, offset, length, callback);
}
@Override
@@ -908,12 +925,14 @@
public void shouldHandleWrongContentLength() throws Exception
{
prepareProxy(new ProxyServlet());
- prepareServer(new HttpServlet() {
+ prepareServer(new HttpServlet()
+ {
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
byte[] message = "tooshort".getBytes("ascii");
resp.setContentType("text/plain;charset=ascii");
- resp.setHeader("Content-Length", Long.toString(message.length+1));
+ resp.setHeader("Content-Length", Long.toString(message.length + 1));
resp.getOutputStream().write(message);
}
});