@Test public void testProxyRequestFailureInTheMiddleOfProxyingBigContent() throws Exception { final long proxyTimeout = 1000; int outputBufferSize = 1024; Map<String, String> proxyParams = new HashMap<>(); proxyParams.put("timeout", String.valueOf(proxyTimeout)); proxyParams.put("outputBufferSize", String.valueOf(outputBufferSize)); prepareProxy(proxyParams); final CountDownLatch chunk1Latch = new CountDownLatch(1); final byte[] chunk1 = new byte[outputBufferSize]; new Random().nextBytes(chunk1); final int chunk2 = 'w'; prepareServer( new HttpServlet() { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletOutputStream output = response.getOutputStream(); output.write(chunk1); response.flushBuffer(); // Wait for the client to receive this chunk. await(chunk1Latch, 5000); // Send second chunk, must not be received by proxy. output.write(chunk2); } private boolean await(CountDownLatch latch, long ms) throws IOException { try { return latch.await(ms, TimeUnit.MILLISECONDS); } catch (InterruptedException x) { throw new InterruptedIOException(); } } }); HttpClient client = prepareClient(); InputStreamResponseListener listener = new InputStreamResponseListener(); int port = serverConnector.getLocalPort(); client.newRequest("localhost", port).send(listener); Response response = listener.get(5, TimeUnit.SECONDS); Assert.assertEquals(200, response.getStatus()); InputStream input = listener.getInputStream(); for (int i = 0; i < chunk1.length; ++i) Assert.assertEquals(chunk1[i] & 0xFF, input.read()); TimeUnit.MILLISECONDS.sleep(2 * proxyTimeout); chunk1Latch.countDown(); try { // Make sure the proxy does not receive chunk2. input.read(); Assert.fail(); } catch (EOFException x) { // Expected } HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP) client.getDestination("http", "localhost", port); Assert.assertEquals(0, destination.getConnectionPool().getIdleConnections().size()); }
@Test public void testProxyRequestFailureInTheMiddleOfProxyingSmallContent() throws Exception { final long proxyTimeout = 1000; Map<String, String> proxyParams = new HashMap<>(); proxyParams.put("timeout", String.valueOf(proxyTimeout)); prepareProxy(proxyParams); final CountDownLatch chunk1Latch = new CountDownLatch(1); final int chunk1 = 'q'; final int chunk2 = 'w'; prepareServer( new HttpServlet() { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletOutputStream output = response.getOutputStream(); output.write(chunk1); response.flushBuffer(); // Wait for the client to receive this chunk. await(chunk1Latch, 5000); // Send second chunk, must not be received by proxy. output.write(chunk2); } private boolean await(CountDownLatch latch, long ms) throws IOException { try { return latch.await(ms, TimeUnit.MILLISECONDS); } catch (InterruptedException x) { throw new InterruptedIOException(); } } }); HttpClient client = prepareClient(); InputStreamResponseListener listener = new InputStreamResponseListener(); int port = serverConnector.getLocalPort(); client.newRequest("localhost", port).send(listener); // Make the proxy request fail; given the small content, the // proxy-to-client response is not committed yet so it will be reset. TimeUnit.MILLISECONDS.sleep(2 * proxyTimeout); Response response = listener.get(5, TimeUnit.SECONDS); Assert.assertEquals(504, response.getStatus()); // Make sure there is no content, as the proxy-to-client response has been reset. InputStream input = listener.getInputStream(); Assert.assertEquals(-1, input.read()); chunk1Latch.countDown(); // Result succeeds because a 504 is a valid HTTP response. Result result = listener.await(5, TimeUnit.SECONDS); Assert.assertTrue(result.isSucceeded()); // Make sure the proxy does not receive chunk2. Assert.assertEquals(-1, input.read()); HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP) client.getDestination("http", "localhost", port); Assert.assertEquals(0, destination.getConnectionPool().getIdleConnections().size()); }