@Test
  public void testExecRequestPersistentStatefulConnection() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);
    Mockito.when(reuseStrategy.keepAlive(Mockito.same(response), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.TRUE);
    Mockito.when(userTokenHandler.getUserToken(Mockito.<HttpClientContext>any()))
        .thenReturn("this and that");

    mainClientExec.execute(route, request, context, execAware);
    Mockito.verify(connManager).requestConnection(route, null);
    Mockito.verify(connRequest).get(0, TimeUnit.MILLISECONDS);
    Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
    Mockito.verify(connManager)
        .releaseConnection(managedConn, "this and that", 0, TimeUnit.MILLISECONDS);
    Mockito.verify(managedConn, Mockito.never()).close();

    Assert.assertEquals("this and that", context.getUserToken());
  }
  @Test
  public void testExecRequestPersistentConnection() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);
    Mockito.when(reuseStrategy.keepAlive(Mockito.same(response), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.TRUE);
    Mockito.when(
            keepAliveStrategy.getKeepAliveDuration(
                Mockito.same(response), Mockito.<HttpClientContext>any()))
        .thenReturn(678L);

    final CloseableHttpResponse finalResponse =
        mainClientExec.execute(route, request, context, execAware);
    Mockito.verify(connManager).requestConnection(route, null);
    Mockito.verify(connRequest).get(0, TimeUnit.MILLISECONDS);
    Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
    Mockito.verify(connManager).releaseConnection(managedConn, null, 678L, TimeUnit.MILLISECONDS);
    Mockito.verify(managedConn, Mockito.never()).close();

    Assert.assertNotNull(finalResponse);
    Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
  }
  @Test(expected = HttpException.class)
  public void testEstablishRouteViaProxyTunnelFailure() throws Exception {
    final AuthState authState = new AuthState();
    final HttpRoute route = new HttpRoute(target, null, proxy, true);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 500, "Boom");
    response.setEntity(new StringEntity("Ka-boom"));

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.<HttpRequest>any(),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);

    try {
      mainClientExec.establishRoute(authState, managedConn, route, request, context);
    } catch (final TunnelRefusedException ex) {
      final HttpResponse r = ex.getResponse();
      Assert.assertEquals("Ka-boom", EntityUtils.toString(r.getEntity()));

      Mockito.verify(managedConn).close();

      throw ex;
    }
  }
  @Test
  public void testEstablishRouteViaProxyTunnelRetryOnAuthChallengeNonPersistentConnection()
      throws Exception {
    final AuthState authState = new AuthState();
    final HttpRoute route = new HttpRoute(target, null, proxy, true);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
    final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
    response1.setEntity(EntityBuilder.create().setStream(instream1).build());
    final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(
            proxyAuthStrategy.isAuthenticationRequested(
                Mockito.eq(proxy), Mockito.same(response1), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.TRUE);
    Mockito.when(
            reuseStrategy.keepAlive(Mockito.<HttpResponse>any(), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.FALSE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.<HttpRequest>any(),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response1, response2);

    mainClientExec.establishRoute(authState, managedConn, route, request, context);

    Mockito.verify(connManager).connect(managedConn, route, 0, context);
    Mockito.verify(connManager).routeComplete(managedConn, route, context);
    Mockito.verify(instream1, Mockito.never()).close();
    Mockito.verify(managedConn).close();
  }
  @Test(expected = InterruptedIOException.class)
  public void testExecConnectionShutDown() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));

    Mockito.when(
            requestExecutor.execute(
                Mockito.<HttpRequest>any(),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenThrow(new ConnectionShutdownException());

    mainClientExec.execute(route, request, context, execAware);
  }
  @Test
  public void testSocketTimeoutReset() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);

    mainClientExec.execute(route, request, context, execAware);
    Mockito.verify(managedConn, Mockito.never()).setSocketTimeout(Mockito.anyInt());
  }
  @Test
  public void testExecEntityEnclosingRequestRetryOnAuthChallenge() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
    final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
    response1.setEntity(EntityBuilder.create().setStream(instream1).build());
    final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
    final InputStream instream2 = Mockito.spy(new ByteArrayInputStream(new byte[] {2, 3, 4}));
    response2.setEntity(EntityBuilder.create().setStream(instream2).build());

    final AuthState proxyAuthState = new AuthState();
    proxyAuthState.setState(AuthProtocolState.SUCCESS);
    proxyAuthState.update(new NTLMScheme(), new NTCredentials("user:pass"));

    final HttpClientContext context = new HttpClientContext();
    context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response1, response2);
    Mockito.when(
            reuseStrategy.keepAlive(Mockito.<HttpResponse>any(), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.FALSE);
    Mockito.when(
            targetAuthStrategy.isAuthenticationRequested(
                Mockito.eq(target), Mockito.same(response1), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.TRUE);

    final CloseableHttpResponse finalResponse =
        mainClientExec.execute(route, request, context, execAware);
    Mockito.verify(requestExecutor, Mockito.times(2)).execute(request, managedConn, context);
    Mockito.verify(managedConn).close();
    Mockito.verify(instream2, Mockito.never()).close();

    Assert.assertNotNull(finalResponse);
    Assert.assertEquals(200, finalResponse.getStatusLine().getStatusCode());
    Assert.assertNull(proxyAuthState.getAuthScheme());
    Assert.assertNull(proxyAuthState.getCredentials());
  }
  @Test(expected = HttpException.class)
  public void testEstablishRouteViaProxyTunnelUnexpectedResponse() throws Exception {
    final AuthState authState = new AuthState();
    final HttpRoute route = new HttpRoute(target, null, proxy, true);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 101, "Lost");

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.<HttpRequest>any(),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);

    mainClientExec.establishRoute(authState, managedConn, route, request, context);
  }
  @Test
  public void testSocketTimeoutExistingConnection() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final RequestConfig config = RequestConfig.custom().setSocketTimeout(3000).build();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    context.setRequestConfig(config);
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
    Mockito.when(managedConn.isOpen()).thenReturn(true);
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);

    mainClientExec.execute(route, request, context, execAware);
    Mockito.verify(managedConn).setSocketTimeout(3000);
  }
  @Test(expected = NonRepeatableRequestException.class)
  public void testExecEntityEnclosingRequest() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final HttpPost post = new HttpPost("http://bar/test");
    final InputStream instream0 = new ByteArrayInputStream(new byte[] {1, 2, 3});
    post.setEntity(EntityBuilder.create().setStream(instream0).build());
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(post);

    final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
    final InputStream instream1 = new ByteArrayInputStream(new byte[] {1, 2, 3});
    response1.setEntity(EntityBuilder.create().setStream(instream1).build());

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenAnswer(
            new Answer<HttpResponse>() {

              @Override
              public HttpResponse answer(final InvocationOnMock invocationOnMock) throws Throwable {
                final Object[] args = invocationOnMock.getArguments();
                final HttpEntityEnclosingRequest requestEE = (HttpEntityEnclosingRequest) args[0];
                requestEE.getEntity().writeTo(new ByteArrayOutputStream());
                return response1;
              }
            });
    Mockito.when(
            reuseStrategy.keepAlive(Mockito.<HttpResponse>any(), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.TRUE);
    Mockito.when(
            targetAuthStrategy.isAuthenticationRequested(
                Mockito.eq(target), Mockito.same(response1), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.TRUE);

    mainClientExec.execute(route, request, context, execAware);
  }
  @Test(expected = IOException.class)
  public void testExecIOException() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));

    Mockito.when(
            requestExecutor.execute(
                Mockito.<HttpRequest>any(),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenThrow(new IOException("Ka-boom"));

    try {
      mainClientExec.execute(route, request, context, execAware);
    } catch (final Exception ex) {
      Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);

      throw ex;
    }
  }
  @Test
  public void testExecRequestNonPersistentConnection() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final RequestConfig config =
        RequestConfig.custom()
            .setConnectTimeout(123)
            .setSocketTimeout(234)
            .setConnectionRequestTimeout(345)
            .build();
    context.setRequestConfig(config);
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);

    final CloseableHttpResponse finalResponse =
        mainClientExec.execute(route, request, context, execAware);
    Mockito.verify(connManager).requestConnection(route, null);
    Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
    Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
    Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
    Mockito.verify(connManager).connect(managedConn, route, 123, context);
    Mockito.verify(connManager).routeComplete(managedConn, route, context);
    Mockito.verify(managedConn).setSocketTimeout(234);
    Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
    Mockito.verify(managedConn, Mockito.times(1)).close();
    Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);

    Assert.assertNotNull(context.getTargetAuthState());
    Assert.assertNotNull(context.getProxyAuthState());
    Assert.assertSame(managedConn, context.getConnection());
    Assert.assertNull(context.getUserToken());
    Assert.assertNotNull(finalResponse);
    Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
  }
  @Test
  public void testExecRequestConnectionRelease() throws Exception {
    final HttpRoute route = new HttpRoute(target);
    final HttpClientContext context = new HttpClientContext();
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
    // The entity is streaming
    response.setEntity(
        EntityBuilder.create().setStream(new ByteArrayInputStream(new byte[] {})).build());

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.same(request),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);
    Mockito.when(reuseStrategy.keepAlive(Mockito.same(response), Mockito.<HttpClientContext>any()))
        .thenReturn(Boolean.FALSE);

    final CloseableHttpResponse finalResponse =
        mainClientExec.execute(route, request, context, execAware);
    Mockito.verify(connManager).requestConnection(route, null);
    Mockito.verify(connRequest).get(0, TimeUnit.MILLISECONDS);
    Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
    Mockito.verify(connManager, Mockito.never())
        .releaseConnection(
            Mockito.same(managedConn), Mockito.any(), Mockito.anyInt(), Mockito.<TimeUnit>any());
    Mockito.verify(managedConn, Mockito.never()).close();

    Assert.assertNotNull(finalResponse);
    Assert.assertTrue(finalResponse instanceof HttpResponseProxy);
    finalResponse.close();

    Mockito.verify(connManager, Mockito.times(1))
        .releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
    Mockito.verify(managedConn, Mockito.times(1)).shutdown();
  }
  public static void main(String[] args) throws Exception {

    HttpParams params = new SyncBasicHttpParams();
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, "UTF-8");
    HttpProtocolParams.setUserAgent(params, "HttpComponents/1.1");
    HttpProtocolParams.setUseExpectContinue(params, true);
    HttpProcessor httpproc =
        new ImmutableHttpProcessor(
            new HttpRequestInterceptor[] {
              new RequestContent(),
              new RequestTargetHost(),
              new RequestConnControl(),
              new RequestUserAgent(),
              new RequestExpectContinue()
            });
    HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
    HttpContext context = new BasicHttpContext(null);
    HttpHost host = new HttpHost("localhost", 8080);
    DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
    ConnectionReuseStrategy connStrategy = new DefaultConnectionReuseStrategy();
    context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
    context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, host);
    try {

      String[] targets = {"/t.html"};

      for (int i = 0; i < targets.length; i++) {

        if (!conn.isOpen()) {

          Socket socket = new Socket(host.getHostName(), host.getPort());

          conn.bind(socket, params);
        }

        BasicHttpRequest request = new BasicHttpRequest("GET", targets[i]);

        System.out.println(">> Request URI: " + request.getRequestLine().getUri());

        request.setParams(params);

        httpexecutor.preProcess(request, httpproc, context);

        HttpResponse response = httpexecutor.execute(request, conn, context);

        response.setParams(params);

        httpexecutor.postProcess(response, httpproc, context);

        System.out.println("<< Response: " + response.getStatusLine());

        System.out.println(EntityUtils.toString(response.getEntity()));

        System.out.println("==============");

        if (!connStrategy.keepAlive(response, context)) {

          conn.close();

        } else {

          System.out.println("Connection kept alive...");
        }
      }

    } finally {

      conn.close();
    }
  }
Beispiel #15
0
  /**
   * Creates a tunnel to the target server. The connection must be established to the (last) proxy.
   * A CONNECT request for tunnelling through the proxy will be created and sent, the response
   * received and checked. This method does <i>not</i> update the connection with information about
   * the tunnel, that is left to the caller.
   *
   * @param route the route to establish
   * @param context the context for request execution
   * @return <code>true</code> if the tunnelled route is secure, <code>false</code> otherwise. The
   *     implementation here always returns <code>false</code>, but derived classes may override.
   * @throws HttpException in case of a problem
   * @throws IOException in case of an IO problem
   */
  protected boolean createTunnelToTarget(HttpRoute route, HttpContext context)
      throws HttpException, IOException {

    HttpHost proxy = route.getProxyHost();
    HttpHost target = route.getTargetHost();
    HttpResponse response = null;

    boolean done = false;
    while (!done) {

      done = true;

      if (!this.managedConn.isOpen()) {
        this.managedConn.open(route, context, this.params);
      }

      HttpRequest connect = createConnectRequest(route, context);

      String agent = HttpProtocolParams.getUserAgent(params);
      if (agent != null) {
        connect.addHeader(HTTP.USER_AGENT, agent);
      }
      connect.addHeader(HTTP.TARGET_HOST, target.toHostString());

      AuthScheme authScheme = this.proxyAuthState.getAuthScheme();
      AuthScope authScope = this.proxyAuthState.getAuthScope();
      Credentials creds = this.proxyAuthState.getCredentials();
      if (creds != null) {
        if (authScope != null || !authScheme.isConnectionBased()) {
          try {
            connect.addHeader(authScheme.authenticate(creds, connect));
          } catch (AuthenticationException ex) {
            if (this.log.isErrorEnabled()) {
              this.log.error("Proxy authentication error: " + ex.getMessage());
            }
          }
        }
      }

      response = requestExec.execute(connect, this.managedConn, context);

      int status = response.getStatusLine().getStatusCode();
      if (status < 200) {
        throw new HttpException(
            "Unexpected response to CONNECT request: " + response.getStatusLine());
      }

      CredentialsProvider credsProvider =
          (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);

      if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
        if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {

          this.log.debug("Proxy requested authentication");
          Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(response, context);
          try {
            processChallenges(
                challenges, this.proxyAuthState, this.proxyAuthHandler, response, context);
          } catch (AuthenticationException ex) {
            if (this.log.isWarnEnabled()) {
              this.log.warn("Authentication error: " + ex.getMessage());
              break;
            }
          }
          updateAuthState(this.proxyAuthState, proxy, credsProvider);

          if (this.proxyAuthState.getCredentials() != null) {
            done = false;

            // Retry request
            if (this.reuseStrategy.keepAlive(response, context)) {
              this.log.debug("Connection kept alive");
              // Consume response content
              HttpEntity entity = response.getEntity();
              if (entity != null) {
                entity.consumeContent();
              }
            } else {
              this.managedConn.close();
            }
          }

        } else {
          // Reset proxy auth scope
          this.proxyAuthState.setAuthScope(null);
        }
      }
    }

    int status = response.getStatusLine().getStatusCode();

    if (status > 299) {

      // Buffer response content
      HttpEntity entity = response.getEntity();
      if (entity != null) {
        response.setEntity(new BufferedHttpEntity(entity));
      }

      this.managedConn.close();
      throw new TunnelRefusedException(
          "CONNECT refused by proxy: " + response.getStatusLine(), response);
    }

    this.managedConn.markReusable();

    // How to decide on security of the tunnelled connection?
    // The socket factory knows only about the segment to the proxy.
    // Even if that is secure, the hop to the target may be insecure.
    // Leave it to derived classes, consider insecure by default here.
    return false;
  } // createTunnelToTarget
Beispiel #16
0
  public void run() {
    try {
      Socket socket = new Socket(host.getHostName(), host.getPort());
      conn.bind(socket, params);

      // build request
      BasicHttpRequest request;

      if (!this.getRequest().getBody().isEmpty()) {
        request =
            new BasicHttpEntityEnclosingRequest(
                this.getRequest().getMethod(), this.getRequest().getPath());
      } else {
        request = new BasicHttpRequest(this.getRequest().getMethod(), this.getRequest().getPath());
      }

      // add headers
      Map<String, String> headers = this.getRequest().getHeaders();
      Iterator<Map.Entry<String, String>> it = headers.entrySet().iterator();

      while (it.hasNext()) {
        Map.Entry<String, String> pairs = it.next();

        request.addHeader(pairs.getKey(), pairs.getValue());
      }

      // set body
      if (request instanceof BasicHttpEntityEnclosingRequest) {
        StringEntity body = new StringEntity(this.getRequest().getBody());

        ((BasicHttpEntityEnclosingRequest) request).setEntity(body);
      }

      logger.info("> " + request.getRequestLine().getUri());

      // request
      request.setParams(params);
      httpexecutor.preProcess(request, httpproc, context);

      HttpResponse response = httpexecutor.execute(request, conn, context);
      response.setParams(params);
      httpexecutor.postProcess(response, httpproc, context);

      logger.info("< " + response.getStatusLine());

      // set all request headers
      Header[] allHeaders = request.getAllHeaders();

      for (int i = 0; i < allHeaders.length; i++) {
        this.getRequest().setHeader(allHeaders[i].getName(), allHeaders[i].getValue());
      }

      // create response
      String content = "";
      HttpEntity entity = response.getEntity();

      if (entity != null) {
        content = EntityUtils.toString(entity);
      }

      this.response = new Response(response, content);

      // call callback
      callback.onResponse(this.request, this.response);
    } catch (Exception e) {
      Aletheia.handleException(e);
    } finally {
      try {
        conn.close();
      } catch (Exception e) {
        Aletheia.handleException(e);
      }
    }
  }
Beispiel #17
0
  // non-javadoc, see interface ClientRequestDirector
  public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context)
      throws HttpException, IOException {

    HttpRequest orig = request;
    RequestWrapper origWrapper = wrapRequest(orig);
    origWrapper.setParams(params);
    HttpRoute origRoute = determineRoute(target, origWrapper, context);

    RoutedRequest roureq = new RoutedRequest(origWrapper, origRoute);

    long timeout = ConnManagerParams.getTimeout(params);

    int execCount = 0;

    boolean reuse = false;
    HttpResponse response = null;
    boolean done = false;
    try {
      while (!done) {
        // In this loop, the RoutedRequest may be replaced by a
        // followup request and route. The request and route passed
        // in the method arguments will be replaced. The original
        // request is still available in 'orig'.

        RequestWrapper wrapper = roureq.getRequest();
        HttpRoute route = roureq.getRoute();

        // See if we have a user token bound to the execution context
        Object userToken = context.getAttribute(ClientContext.USER_TOKEN);

        // Allocate connection if needed
        if (managedConn == null) {
          ClientConnectionRequest connRequest = connManager.requestConnection(route, userToken);
          if (orig instanceof AbortableHttpRequest) {
            ((AbortableHttpRequest) orig).setConnectionRequest(connRequest);
          }

          try {
            managedConn = connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
          } catch (InterruptedException interrupted) {
            InterruptedIOException iox = new InterruptedIOException();
            iox.initCause(interrupted);
            throw iox;
          }

          if (HttpConnectionParams.isStaleCheckingEnabled(params)) {
            // validate connection
            this.log.debug("Stale connection check");
            if (managedConn.isStale()) {
              this.log.debug("Stale connection detected");
              // BEGIN android-changed
              try {
                managedConn.close();
              } catch (IOException ignored) {
                // SSLSocket's will throw IOException
                // because they can't send a "close
                // notify" protocol message to the
                // server. Just supresss any
                // exceptions related to closing the
                // stale connection.
              }
              // END android-changed
            }
          }
        }

        if (orig instanceof AbortableHttpRequest) {
          ((AbortableHttpRequest) orig).setReleaseTrigger(managedConn);
        }

        // Reopen connection if needed
        if (!managedConn.isOpen()) {
          managedConn.open(route, context, params);
        }
        // BEGIN android-added
        else {
          // b/3241899 set the per request timeout parameter on reused connections
          managedConn.setSocketTimeout(HttpConnectionParams.getSoTimeout(params));
        }
        // END android-added

        try {
          establishRoute(route, context);
        } catch (TunnelRefusedException ex) {
          if (this.log.isDebugEnabled()) {
            this.log.debug(ex.getMessage());
          }
          response = ex.getResponse();
          break;
        }

        // Reset headers on the request wrapper
        wrapper.resetHeaders();

        // Re-write request URI if needed
        rewriteRequestURI(wrapper, route);

        // Use virtual host if set
        target = (HttpHost) wrapper.getParams().getParameter(ClientPNames.VIRTUAL_HOST);

        if (target == null) {
          target = route.getTargetHost();
        }

        HttpHost proxy = route.getProxyHost();

        // Populate the execution context
        context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
        context.setAttribute(ExecutionContext.HTTP_PROXY_HOST, proxy);
        context.setAttribute(ExecutionContext.HTTP_CONNECTION, managedConn);
        context.setAttribute(ClientContext.TARGET_AUTH_STATE, targetAuthState);
        context.setAttribute(ClientContext.PROXY_AUTH_STATE, proxyAuthState);

        // Run request protocol interceptors
        requestExec.preProcess(wrapper, httpProcessor, context);

        context.setAttribute(ExecutionContext.HTTP_REQUEST, wrapper);

        boolean retrying = true;
        while (retrying) {
          // Increment total exec count (with redirects)
          execCount++;
          // Increment exec count for this particular request
          wrapper.incrementExecCount();
          if (wrapper.getExecCount() > 1 && !wrapper.isRepeatable()) {
            throw new NonRepeatableRequestException(
                "Cannot retry request " + "with a non-repeatable request entity");
          }

          try {
            if (this.log.isDebugEnabled()) {
              this.log.debug("Attempt " + execCount + " to execute request");
            }
            response = requestExec.execute(wrapper, managedConn, context);
            retrying = false;

          } catch (IOException ex) {
            this.log.debug("Closing the connection.");
            managedConn.close();
            if (retryHandler.retryRequest(ex, execCount, context)) {
              if (this.log.isInfoEnabled()) {
                this.log.info(
                    "I/O exception ("
                        + ex.getClass().getName()
                        + ") caught when processing request: "
                        + ex.getMessage());
              }
              if (this.log.isDebugEnabled()) {
                this.log.debug(ex.getMessage(), ex);
              }
              this.log.info("Retrying request");
            } else {
              throw ex;
            }

            // If we have a direct route to the target host
            // just re-open connection and re-try the request
            if (route.getHopCount() == 1) {
              this.log.debug("Reopening the direct connection.");
              managedConn.open(route, context, params);
            } else {
              // otherwise give up
              throw ex;
            }
          }
        }

        // Run response protocol interceptors
        response.setParams(params);
        requestExec.postProcess(response, httpProcessor, context);

        // The connection is in or can be brought to a re-usable state.
        reuse = reuseStrategy.keepAlive(response, context);
        if (reuse) {
          // Set the idle duration of this connection
          long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
          managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
        }

        RoutedRequest followup = handleResponse(roureq, response, context);
        if (followup == null) {
          done = true;
        } else {
          if (reuse) {
            this.log.debug("Connection kept alive");
            // Make sure the response body is fully consumed, if present
            HttpEntity entity = response.getEntity();
            if (entity != null) {
              entity.consumeContent();
            }
            // entity consumed above is not an auto-release entity,
            // need to mark the connection re-usable explicitly
            managedConn.markReusable();
          } else {
            managedConn.close();
          }
          // check if we can use the same connection for the followup
          if (!followup.getRoute().equals(roureq.getRoute())) {
            releaseConnection();
          }
          roureq = followup;
        }

        userToken = this.userTokenHandler.getUserToken(context);
        context.setAttribute(ClientContext.USER_TOKEN, userToken);
        if (managedConn != null) {
          managedConn.setState(userToken);
        }
      } // while not done

      // check for entity, release connection if possible
      if ((response == null)
          || (response.getEntity() == null)
          || !response.getEntity().isStreaming()) {
        // connection not needed and (assumed to be) in re-usable state
        if (reuse) managedConn.markReusable();
        releaseConnection();
      } else {
        // install an auto-release entity
        HttpEntity entity = response.getEntity();
        entity = new BasicManagedEntity(entity, managedConn, reuse);
        response.setEntity(entity);
      }

      return response;

    } catch (HttpException ex) {
      abortConnection();
      throw ex;
    } catch (IOException ex) {
      abortConnection();
      throw ex;
    } catch (RuntimeException ex) {
      abortConnection();
      throw ex;
    }
  } // execute
  @Test
  public void testEstablishRouteViaProxyTunnel() throws Exception {
    final AuthState authState = new AuthState();
    final HttpRoute route = new HttpRoute(target, null, proxy, true);
    final HttpClientContext context = new HttpClientContext();
    final RequestConfig config = RequestConfig.custom().setConnectTimeout(321).build();
    context.setRequestConfig(config);
    final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
    final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");

    Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
    Mockito.when(
            requestExecutor.execute(
                Mockito.<HttpRequest>any(),
                Mockito.<HttpClientConnection>any(),
                Mockito.<HttpClientContext>any()))
        .thenReturn(response);

    mainClientExec.establishRoute(authState, managedConn, route, request, context);

    Mockito.verify(connManager).connect(managedConn, route, 321, context);
    Mockito.verify(connManager).routeComplete(managedConn, route, context);
    final ArgumentCaptor<HttpRequest> reqCaptor = ArgumentCaptor.forClass(HttpRequest.class);
    Mockito.verify(requestExecutor)
        .execute(reqCaptor.capture(), Mockito.same(managedConn), Mockito.same(context));
    final HttpRequest connect = reqCaptor.getValue();
    Assert.assertNotNull(connect);
    Assert.assertEquals("CONNECT", connect.getRequestLine().getMethod());
    Assert.assertEquals(HttpVersion.HTTP_1_1, connect.getRequestLine().getProtocolVersion());
    Assert.assertEquals("foo:80", connect.getRequestLine().getUri());
  }