@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()); }
@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()); }
private void testServerSendsConnectionClose(boolean chunked, String content) throws Exception { ServerSocket server = new ServerSocket(0); int port = server.getLocalPort(); startClient(); Request request = client.newRequest("localhost", port).scheme("https").path("/ctx/path"); FutureResponseListener listener = new FutureResponseListener(request); request.send(listener); Socket socket = server.accept(); SSLContext sslContext = client.getSslContextFactory().getSslContext(); SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, "localhost", port, false); sslSocket.setUseClientMode(false); sslSocket.startHandshake(); InputStream input = sslSocket.getInputStream(); consumeRequest(input); OutputStream output = sslSocket.getOutputStream(); String serverResponse = "" + "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n"; if (chunked) { serverResponse += "" + "Transfer-Encoding: chunked\r\n" + "\r\n"; for (int i = 0; i < 2; ++i) { serverResponse += Integer.toHexString(content.length()) + "\r\n" + content + "\r\n"; } serverResponse += "" + "0\r\n" + "\r\n"; } else { serverResponse += "Content-Length: " + content.length() + "\r\n"; serverResponse += "\r\n"; serverResponse += content; } output.write(serverResponse.getBytes("UTF-8")); output.flush(); switch (closeMode) { case NONE: { break; } case CLOSE: { sslSocket.close(); break; } case ABRUPT: { socket.shutdownOutput(); break; } default: { throw new IllegalStateException(); } } ContentResponse response = listener.get(5, TimeUnit.SECONDS); Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); // Give some time to process the connection. Thread.sleep(1000); // Connection should have been removed from pool. HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP) client.getDestination("http", "localhost", port); DuplexConnectionPool connectionPool = (DuplexConnectionPool) destination.getConnectionPool(); Assert.assertEquals(0, connectionPool.getConnectionCount()); Assert.assertEquals(0, connectionPool.getIdleConnectionCount()); Assert.assertEquals(0, connectionPool.getActiveConnectionCount()); }