/** * Delegates to {@link BodyDeferringAsyncHandler#getResponse()}. Will * blocks as long as headers arrives only. Might return * <code>null</code>. See * {@link BodyDeferringAsyncHandler#getResponse()} method for details. * * @return a {@link Response} * @throws InterruptedException if the latch is interrupted * @throws IOException if the handler completed with an exception */ public Response getAsapResponse() throws InterruptedException, IOException { return bdah.getResponse(); }
@Override public void onThrowable(Throwable t) { this.throwable = t; // Counting down to handle error cases too. // In "premature exceptions" cases, the onBodyPartReceived() and // onCompleted() // methods will never be invoked, leaving caller of getResponse() method // blocked forever. try { semaphore.acquire(); } catch (InterruptedException e) { // Ignore } finally { headersArrived.countDown(); semaphore.release(); } try { closeOut(); } catch (IOException e) { // ignore } }
@Test(expectedExceptions = IOException.class) public void testConnectionRefused() throws IOException, InterruptedException { int newPortWithoutAnyoneListening = findFreePort(); try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet("http://localhost:" + newPortWithoutAnyoneListening + "/testConnectionRefused"); CountingOutputStream cos = new CountingOutputStream(); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); r.execute(bdah); bdah.getResponse(); } }
@Test(expectedExceptions = RemotelyClosedException.class) public void deferredInputStreamTrickWithFailure() throws Throwable { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()).addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pos); Future<Response> f = r.execute(bdah); BodyDeferringInputStream is = new BodyDeferringInputStream(f, bdah, pis); Response resp = is.getAsapResponse(); assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); assertEquals(resp.getHeader(CONTENT_LENGTH), String.valueOf(CONTENT_LENGTH_VALUE)); // "consume" the body, but our code needs input stream CountingOutputStream cos = new CountingOutputStream(); try { try { copy(is, cos); } finally { is.close(); cos.close(); } } catch (IOException e) { throw e.getCause(); } } }
@Test public void testPipedStreams() throws Exception { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { PipedOutputStream pout = new PipedOutputStream(); try (PipedInputStream pin = new PipedInputStream(pout)) { BodyDeferringAsyncHandler handler = new BodyDeferringAsyncHandler(pout); ListenableFuture<Response> respFut = client.prepareGet(getTargetUrl()).execute(handler); Response resp = handler.getResponse(); if (resp.getStatusCode() == 200) { try (BodyDeferringInputStream is = new BodyDeferringInputStream(respFut, handler, pin)) { String body = IOUtils.toString(is, StandardCharsets.UTF_8); assertTrue(body.contains("ABCDEF")); } } else { throw new IOException("HTTP error " + resp.getStatusCode()); } } } }
@Test public void deferredInputStreamTrick() throws IOException, InterruptedException { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()); PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pos); Future<Response> f = r.execute(bdah); BodyDeferringInputStream is = new BodyDeferringInputStream(f, bdah, pis); Response resp = is.getAsapResponse(); assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); assertEquals(resp.getHeader(CONTENT_LENGTH), String.valueOf(CONTENT_LENGTH_VALUE)); // "consume" the body, but our code needs input stream CountingOutputStream cos = new CountingOutputStream(); try { copy(is, cos); } finally { is.close(); cos.close(); } // now we don't need to be polite, since consuming and closing // BodyDeferringInputStream does all. // it all should be here now assertEquals(cos.getByteCount(), CONTENT_LENGTH_VALUE); } }
@Test public void deferredSimple() throws IOException, ExecutionException, InterruptedException { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()); CountingOutputStream cos = new CountingOutputStream(); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); Future<Response> f = r.execute(bdah); Response resp = bdah.getResponse(); assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); assertEquals(resp.getHeader(CONTENT_LENGTH), String.valueOf(CONTENT_LENGTH_VALUE)); // we got headers only, it's probably not all yet here (we have BIG file // downloading) assertTrue(cos.getByteCount() <= CONTENT_LENGTH_VALUE); // now be polite and wait for body arrival too (otherwise we would be // dropping the "line" on server) f.get(); // it all should be here now assertEquals(cos.getByteCount(), CONTENT_LENGTH_VALUE); } }
/** * Delegates to {@link BodyDeferringAsyncHandler#getResponse()}. Will * blocks as long as headers arrives only. Might return * <code>null</code>. See * {@link BodyDeferringAsyncHandler#getResponse()} method for details. * * @return a {@link Response} * @throws InterruptedException */ public Response getAsapResponse() throws InterruptedException, IOException { return bdah.getResponse(); }
@Override public Response onCompleted() throws IOException { if (!responseSet) { response = responseBuilder.build(); responseSet = true; } // Counting down to handle error cases too. // In "normal" cases, latch is already at 0 here // But in other cases, for example when because of some error // onBodyPartReceived() is never called, the caller // of getResponse() would remain blocked infinitely. // By contract, onCompleted() is always invoked, even in case of errors headersArrived.countDown(); closeOut(); try { semaphore.acquire(); if (throwable != null) { throw new IOException(throwable); } else { // sending out current response return responseBuilder.build(); } } catch (InterruptedException e) { return null; } finally { semaphore.release(); } }
@Test(expectedExceptions = UnsupportedOperationException.class) public void deferredInputStreamTrickWithCloseConnectionAndRetry() throws Throwable { try (AsyncHttpClient client = asyncHttpClient(config().setMaxRequestRetry(1).setRequestTimeout(10000).build())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()).addHeader("X-CLOSE-CONNECTION", Boolean.TRUE.toString()); PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pos); Future<Response> f = r.execute(bdah); BodyDeferringInputStream is = new BodyDeferringInputStream(f, bdah, pis); Response resp = is.getAsapResponse(); assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); assertEquals(resp.getHeader(CONTENT_LENGTH), String.valueOf(CONTENT_LENGTH_VALUE)); // "consume" the body, but our code needs input stream CountingOutputStream cos = new CountingOutputStream(); try { try { copy(is, cos); } finally { is.close(); cos.close(); } } catch (IOException e) { throw e.getCause(); } } }
@Test(expectedExceptions = RemotelyClosedException.class, enabled = false) public void deferredSimpleWithFailure() throws Throwable { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()).addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); CountingOutputStream cos = new CountingOutputStream(); BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); Future<Response> f = r.execute(bdah); Response resp = bdah.getResponse(); assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); assertEquals(resp.getHeader(CONTENT_LENGTH), String.valueOf(CONTENT_LENGTH_VALUE)); // we got headers only, it's probably not all yet here (we have BIG file // downloading) assertTrue(cos.getByteCount() <= CONTENT_LENGTH_VALUE); // now be polite and wait for body arrival too (otherwise we would be // dropping the "line" on server) try { f.get(); } catch (ExecutionException e) { // good // it's incomplete, there was an error assertNotEquals(cos.getByteCount(), CONTENT_LENGTH_VALUE); throw e.getCause(); } } }
public void onThrowable(Throwable t) { this.throwable = t; // Counting down to handle error cases too. // In "premature exceptions" cases, the onBodyPartReceived() and // onCompleted() // methods will never be invoked, leaving caller of getResponse() method // blocked forever. try { semaphore.acquire(); } catch (InterruptedException e) { // Ignore } finally { headersArrived.countDown(); semaphore.release(); } try { closeOut(); } catch (IOException e) { // ignore } }
public Response onCompleted() throws IOException { if (!responseSet) { response = responseBuilder.build(); responseSet = true; } // Counting down to handle error cases too. // In "normal" cases, latch is already at 0 here // But in other cases, for example when because of some error // onBodyPartReceived() is never called, the caller // of getResponse() would remain blocked infinitely. // By contract, onCompleted() is always invoked, even in case of errors headersArrived.countDown(); closeOut(); try { semaphore.acquire(); if (throwable != null) { IOException ioe = new IOException(throwable.getMessage()); ioe.initCause(throwable); throw ioe; } else { // sending out current response return responseBuilder.build(); } } catch (InterruptedException e) { return null; } finally { semaphore.release(); } }