@Override
  public void exchangeTerminated(HttpExchange exchange, Result result) {
    super.exchangeTerminated(exchange, result);

    Response response = result.getResponse();
    HttpFields responseHeaders = response.getHeaders();

    String closeReason = null;
    if (result.isFailed()) closeReason = "failure";
    else if (receiver.isShutdown()) closeReason = "server close";

    if (closeReason == null) {
      if (response.getVersion().compareTo(HttpVersion.HTTP_1_1) < 0) {
        // HTTP 1.0 must close the connection unless it has
        // an explicit keep alive or it's a CONNECT method.
        boolean keepAlive =
            responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString());
        boolean connect = HttpMethod.CONNECT.is(exchange.getRequest().getMethod());
        if (!keepAlive && !connect) closeReason = "http/1.0";
      } else {
        // HTTP 1.1 or greater closes only if it has an explicit close.
        if (responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()))
          closeReason = "http/1.1";
      }
    }

    if (closeReason != null) {
      if (LOG.isDebugEnabled()) LOG.debug("Closing, reason: {} - {}", closeReason, connection);
      connection.close();
    } else {
      if (response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101) connection.remove();
      else release();
    }
  }
Example #2
0
 private static ClientResponse translateResponse(
     final ClientRequest jerseyRequest,
     final org.eclipse.jetty.client.api.Response jettyResponse,
     final NonBlockingInputStream entityStream) {
   final ClientResponse jerseyResponse =
       new ClientResponse(Statuses.from(jettyResponse.getStatus()), jerseyRequest);
   processResponseHeaders(jettyResponse.getHeaders(), jerseyResponse);
   jerseyResponse.setEntityStream(entityStream);
   return jerseyResponse;
 }
 private InBoundHeaders getInBoundHeaders(Response response) {
   final InBoundHeaders headers = new InBoundHeaders();
   for (HttpField header : response.getHeaders()) {
     headers.add(header.getName(), header.getValue());
   }
   return headers;
 }
  @Slow
  @Test
  public void testProxyLongPoll() throws Exception {
    prepareProxy();
    final long timeout = 1000;
    prepareServer(
        new HttpServlet() {
          @Override
          protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
              throws ServletException, IOException {
            if (!request.isAsyncStarted()) {
              final AsyncContext asyncContext = request.startAsync();
              asyncContext.setTimeout(timeout);
              asyncContext.addListener(
                  new AsyncListener() {
                    @Override
                    public void onComplete(AsyncEvent event) throws IOException {}

                    @Override
                    public void onTimeout(AsyncEvent event) throws IOException {
                      if (request.getHeader("Via") != null)
                        response.addHeader(PROXIED_HEADER, "true");
                      asyncContext.complete();
                    }

                    @Override
                    public void onError(AsyncEvent event) throws IOException {}

                    @Override
                    public void onStartAsync(AsyncEvent event) throws IOException {}
                  });
            }
          }
        });

    Response response =
        client
            .newRequest("localhost", serverConnector.getLocalPort())
            .timeout(2 * timeout, TimeUnit.MILLISECONDS)
            .send();
    Assert.assertEquals(200, response.getStatus());
    Assert.assertTrue(response.getHeaders().containsKey(PROXIED_HEADER));
  }
  @Override
  public void onHeaders(Response response) {
    HttpFields headers = response.getHeaders();
    long length = headers.getLongField(HttpHeader.CONTENT_LENGTH.asString());
    if (length > maxLength)
      response.abort(new IllegalArgumentException("Buffering capacity exceeded"));

    String contentType = headers.get(HttpHeader.CONTENT_TYPE);
    if (contentType != null) {
      String charset = "charset=";
      int index = contentType.toLowerCase(Locale.ENGLISH).indexOf(charset);
      if (index > 0) {
        String encoding = contentType.substring(index + charset.length());
        // Sometimes charsets arrive with an ending semicolon
        index = encoding.indexOf(';');
        if (index > 0) encoding = encoding.substring(0, index);
        this.encoding = encoding;
      }
    }
  }
 @Override
 public boolean abort(Throwable cause) {
   return response.abort(cause);
 }
 @Override
 public HttpFields getHeaders() {
   return response.getHeaders();
 }
 @Override
 public String getReason() {
   return response.getReason();
 }
 @Override
 public int getStatus() {
   return response.getStatus();
 }
 @Override
 public HttpVersion getVersion() {
   return response.getVersion();
 }
 @Override
 public <T extends ResponseListener> List<T> getListeners(Class<T> listenerClass) {
   return response.getListeners(listenerClass);
 }
 @Override
 public long getConversationID() {
   return response.getConversationID();
 }
  @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());
  }