@Override
 public void connect(
     final HttpClientConnection managedConn,
     final HttpRoute route,
     final int connectTimeout,
     final HttpContext context)
     throws IOException {
   Args.notNull(managedConn, "Managed Connection");
   Args.notNull(route, "HTTP route");
   final ManagedHttpClientConnection conn;
   synchronized (managedConn) {
     final CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
     conn = entry.getConnection();
   }
   final HttpHost host;
   if (route.getProxyHost() != null) {
     host = route.getProxyHost();
   } else {
     host = route.getTargetHost();
   }
   final InetSocketAddress localAddress = route.getLocalSocketAddress();
   SocketConfig socketConfig = this.configData.getSocketConfig(host);
   if (socketConfig == null) {
     socketConfig = this.configData.getDefaultSocketConfig();
   }
   if (socketConfig == null) {
     socketConfig = SocketConfig.DEFAULT;
   }
   this.connectionOperator.connect(
       conn, host, localAddress, connectTimeout, socketConfig, context);
 }
 public SocketAddress resolveRemoteAddress(final HttpRoute route) {
   HttpHost firsthop = route.getProxyHost();
   if (firsthop == null) {
     firsthop = route.getTargetHost();
   }
   String hostname = firsthop.getHostName();
   int port = firsthop.getPort();
   if (port < 0) {
     Scheme scheme = this.schemeRegistry.getScheme(firsthop);
     port = scheme.resolvePort(port);
   }
   return new InetSocketAddress(hostname, port);
 }
    @Override
    public ConnectionRequest requestConnection(final HttpRoute route, final Object state) {
      // If this is the redirect route, stub the return value
      // so-as to pretend the host is waiting on a slot...
      if (route.getTargetHost().getHostName().equals("localhost")) {
        final Thread currentThread = Thread.currentThread();

        return new ConnectionRequest() {

          @Override
          public boolean cancel() {
            currentThread.interrupt();
            return true;
          }

          @Override
          public HttpClientConnection get(final long timeout, final TimeUnit tunit)
              throws InterruptedException, ConnectionPoolTimeoutException {
            connLatch.countDown(); // notify waiter that we're getting a connection

            // zero usually means sleep forever, but CountDownLatch doesn't interpret it that way.
            if (!awaitLatch.await(timeout > 0 ? timeout : Integer.MAX_VALUE, tunit)) {
              throw new ConnectionPoolTimeoutException();
            }

            return Mockito.mock(HttpClientConnection.class);
          }
        };
      } else {
        return super.requestConnection(route, state);
      }
    }
Esempio n. 4
0
  /**
   * Creates the CONNECT request for tunnelling. Called by {@link #createTunnelToTarget
   * createTunnelToTarget}.
   *
   * @param route the route to establish
   * @param context the context for request execution
   * @return the CONNECT request for tunnelling
   */
  protected HttpRequest createConnectRequest(HttpRoute route, HttpContext context) {
    // see RFC 2817, section 5.2 and
    // INTERNET-DRAFT: Tunneling TCP based protocols through
    // Web proxy servers

    HttpHost target = route.getTargetHost();

    String host = target.getHostName();
    int port = target.getPort();
    if (port < 0) {
      Scheme scheme = connManager.getSchemeRegistry().getScheme(target.getSchemeName());
      port = scheme.getDefaultPort();
    }

    StringBuilder buffer = new StringBuilder(host.length() + 6);
    buffer.append(host);
    buffer.append(':');
    buffer.append(Integer.toString(port));

    String authority = buffer.toString();
    ProtocolVersion ver = HttpProtocolParams.getVersion(params);
    HttpRequest req = new BasicHttpRequest("CONNECT", authority, ver);

    return req;
  }
 @Override
 public ManagedHttpClientConnection create(final HttpRoute route) throws IOException {
   ConnectionConfig config = null;
   if (route.getProxyHost() != null) {
     config = this.configData.getConnectionConfig(route.getProxyHost());
   }
   if (config == null) {
     config = this.configData.getConnectionConfig(route.getTargetHost());
   }
   if (config == null) {
     config = this.configData.getDefaultConnectionConfig();
   }
   if (config == null) {
     config = ConnectionConfig.DEFAULT;
   }
   return this.connFactory.create(route, config);
 }
 @Override
 protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) {
   if (args != null && args.length >= 2 && args[1] != null && args[1] instanceof HttpRoute) {
     final HttpRoute route = (HttpRoute) args[1];
     final StringBuilder sb = new StringBuilder();
     if (route.getProxyHost() != null) {
       sb.append(route.getProxyHost().getHostName()).append(":");
       sb.append(route.getProxyHost().getPort());
     } else {
       sb.append(route.getTargetHost().getHostName()).append(":");
       sb.append(route.getTargetHost().getPort());
     }
     recorder.recordAttribute(AnnotationKey.HTTP_INTERNAL_DISPLAY, sb.toString());
   }
   recorder.recordApi(methodDescriptor);
   recorder.recordServiceType(HttpClient4Constants.HTTP_CLIENT_4_INTERNAL);
 }
Esempio n. 7
0
 /*  35:    */
 /*  36:    */ public static HttpRoute getForcedRoute(HttpParams params) /*  37:    */ {
   /*  38:119 */ if (params == null) {
     /*  39:120 */ throw new IllegalArgumentException("Parameters must not be null.");
     /*  40:    */ }
   /*  41:122 */ HttpRoute route = (HttpRoute) params.getParameter("http.route.forced-route");
   /*  42:124 */ if ((route != null) && (NO_ROUTE.equals(route))) {
     /*  43:126 */ route = null;
     /*  44:    */ }
   /*  45:128 */ return route;
   /*  46:    */ }
 @Override
 public void upgrade(
     final HttpClientConnection managedConn, final HttpRoute route, final HttpContext context)
     throws IOException {
   Args.notNull(managedConn, "Managed Connection");
   Args.notNull(route, "HTTP route");
   final ManagedHttpClientConnection conn;
   synchronized (managedConn) {
     final CPoolEntry entry = CPoolProxy.getPoolEntry(managedConn);
     conn = entry.getConnection();
   }
   this.connectionOperator.upgrade(conn, route.getTargetHost(), context);
 }
Esempio n. 9
0
  protected void rewriteRequestURI(final RequestWrapper request, final HttpRoute route)
      throws ProtocolException {
    try {

      URI uri = request.getURI();
      if (route.getProxyHost() != null && !route.isTunnelled()) {
        // Make sure the request URI is absolute
        if (!uri.isAbsolute()) {
          HttpHost target = route.getTargetHost();
          uri = URIUtils.rewriteURI(uri, target);
          request.setURI(uri);
        }
      } else {
        // Make sure the request URI is relative
        if (uri.isAbsolute()) {
          uri = URIUtils.rewriteURI(uri, null);
          request.setURI(uri);
        }
      }

    } catch (URISyntaxException ex) {
      throw new ProtocolException("Invalid URI: " + request.getRequestLine().getUri(), ex);
    }
  }
Esempio n. 10
0
 public SocketAddress resolveLocalAddress(final HttpRoute route) {
   return new InetSocketAddress(route.getLocalAddress(), 0);
 }
  /**
   * Send the request message asynchronously to the given EPR
   *
   * @param epr the destination EPR for the message
   * @param msgContext the message being sent
   * @throws AxisFault on error
   */
  private void sendAsyncRequest(EndpointReference epr, MessageContext msgContext) throws AxisFault {
    try {
      URL url = new URL(epr.getAddress());
      String scheme = url.getProtocol() != null ? url.getProtocol() : "http";
      String hostname = url.getHost();
      int port = url.getPort();
      if (port == -1) {
        // use default
        if ("http".equals(scheme)) {
          port = 80;
        } else if ("https".equals(scheme)) {
          port = 443;
        }
      }
      HttpHost target = new HttpHost(hostname, port, scheme);
      boolean secure = "https".equalsIgnoreCase(target.getSchemeName());

      HttpHost proxy = proxyConfig.selectProxy(target);

      HttpRoute route;
      if (proxy != null) {
        route = new HttpRoute(target, null, proxy, secure);
      } else {
        route = new HttpRoute(target, null, secure);
      }
      Axis2HttpRequest axis2Req = new Axis2HttpRequest(epr, route, msgContext);
      Object timeout = msgContext.getProperty(NhttpConstants.SEND_TIMEOUT);
      if (timeout != null && timeout instanceof Long) {
        axis2Req.setTimeout((int) ((Long) timeout).longValue());
      }

      NHttpClientConnection conn = connpool.getConnection(route);

      // Ensure MessageContext has a ClientConnectionDebug attached before we start streaming
      ServerConnectionDebug scd =
          (ServerConnectionDebug) msgContext.getProperty(ServerHandler.SERVER_CONNECTION_DEBUG);

      ClientConnectionDebug ccd;
      if (scd != null) {
        ccd = scd.getClientConnectionDebug();
        if (ccd == null) {
          ccd = new ClientConnectionDebug(scd);
          scd.setClientConnectionDebug(ccd);
        }
        ccd.recordRequestStartTime(conn, axis2Req);
        msgContext.setProperty(ClientHandler.CLIENT_CONNECTION_DEBUG, ccd);
      }

      if (conn == null) {
        HttpHost host = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
        ioReactor.connect(
            new InetSocketAddress(host.getHostName(), host.getPort()),
            null,
            axis2Req,
            sessionRequestCallback);
        if (log.isDebugEnabled()) {
          log.debug("A new connection established to : " + route);
        }
      } else {
        conn.setSocketTimeout(socketTimeout); // reinitialize timeouts for the pooled connection
        try {
          handler.submitRequest(conn, axis2Req);
          if (log.isDebugEnabled()) {
            log.debug("An existing connection reused to : " + hostname + ":" + port);
          }
        } catch (ConnectionClosedException e) {
          ioReactor.connect(
              new InetSocketAddress(hostname, port), null, axis2Req, sessionRequestCallback);
          if (log.isDebugEnabled()) {
            log.debug("A new connection established to : " + hostname + ":" + port);
          }
        }
      }
      try {
        axis2Req.streamMessageContents();
      } catch (AxisFault af) {
        throw af;
      }

    } catch (MalformedURLException e) {
      handleException("Malformed destination EPR : " + epr.getAddress(), e);
    }
  }
Esempio n. 12
0
  @Override
  public Header authenticate(
      final Credentials credentials, final HttpRequest request, final HttpContext context)
      throws AuthenticationException {
    Args.notNull(request, "HTTP request");
    switch (state) {
      case UNINITIATED:
        throw new AuthenticationException(
            getSchemeName() + " authentication has not been initiated");
      case FAILED:
        throw new AuthenticationException(getSchemeName() + " authentication has failed");
      case CHALLENGE_RECEIVED:
        try {
          final HttpRoute route = (HttpRoute) context.getAttribute(HttpClientContext.HTTP_ROUTE);
          if (route == null) {
            throw new AuthenticationException("Connection route is not available");
          }
          HttpHost host;
          if (isProxy()) {
            host = route.getProxyHost();
            if (host == null) {
              host = route.getTargetHost();
            }
          } else {
            host = route.getTargetHost();
          }
          final String authServer;
          String hostname = host.getHostName();

          if (this.useCanonicalHostname) {
            try {
              // TODO: uncomment this statement and delete the resolveCanonicalHostname,
              // TODO: as soon canonical hostname resolving is implemented in the
              // SystemDefaultDnsResolver
              // final DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;
              // hostname = dnsResolver.resolveCanonicalHostname(host.getHostName());
              hostname = resolveCanonicalHostname(hostname);
            } catch (UnknownHostException ignore) {
            }
          }
          if (this.stripPort) { // || host.getPort()==80 || host.getPort()==443) {
            authServer = hostname;
          } else {
            authServer = hostname + ":" + host.getPort();
          }

          if (log.isDebugEnabled()) {
            log.debug("init " + authServer);
          }
          token = generateToken(token, authServer, credentials);
          state = State.TOKEN_GENERATED;
        } catch (final GSSException gsse) {
          state = State.FAILED;
          if (gsse.getMajor() == GSSException.DEFECTIVE_CREDENTIAL
              || gsse.getMajor() == GSSException.CREDENTIALS_EXPIRED) {
            throw new InvalidCredentialsException(gsse.getMessage(), gsse);
          }
          if (gsse.getMajor() == GSSException.NO_CRED) {
            throw new InvalidCredentialsException(gsse.getMessage(), gsse);
          }
          if (gsse.getMajor() == GSSException.DEFECTIVE_TOKEN
              || gsse.getMajor() == GSSException.DUPLICATE_TOKEN
              || gsse.getMajor() == GSSException.OLD_TOKEN) {
            throw new AuthenticationException(gsse.getMessage(), gsse);
          }
          // other error
          throw new AuthenticationException(gsse.getMessage());
        }
      case TOKEN_GENERATED:
        final String tokenstr = new String(base64codec.encode(token));
        if (log.isDebugEnabled()) {
          log.debug("Sending response '" + tokenstr + "' back to the auth server");
        }
        final CharArrayBuffer buffer = new CharArrayBuffer(32);
        if (isProxy()) {
          buffer.append(AUTH.PROXY_AUTH_RESP);
        } else {
          buffer.append(AUTH.WWW_AUTH_RESP);
        }
        buffer.append(": Negotiate ");
        buffer.append(tokenstr);
        return new BufferedHeader(buffer);
      default:
        throw new IllegalStateException("Illegal state: " + state);
    }
  }
Esempio n. 13
0
  @Override
  public Header authenticate(
      final Credentials credentials, final HttpRequest request, final HttpContext context)
      throws AuthenticationException {
    Args.notNull(request, "HTTP request");
    switch (state) {
      case UNINITIATED:
        throw new AuthenticationException(
            getSchemeName() + " authentication has not been initiated");
      case FAILED:
        throw new AuthenticationException(getSchemeName() + " authentication has failed");
      case CHALLENGE_RECEIVED:
        try {
          final HttpRoute route = (HttpRoute) context.getAttribute(HttpClientContext.HTTP_ROUTE);
          if (route == null) {
            throw new AuthenticationException("Connection route is not available");
          }
          HttpHost host;
          if (isProxy()) {
            host = route.getProxyHost();
            if (host == null) {
              host = route.getTargetHost();
            }
          } else {
            host = route.getTargetHost();
          }
          final String authServer;
          if (!this.stripPort && host.getPort() > 0) {
            authServer = host.toHostString();
          } else {
            authServer = host.getHostName();
          }

          if (log.isDebugEnabled()) {
            log.debug("init " + authServer);
          }
          token = generateToken(token, authServer);
          state = State.TOKEN_GENERATED;
        } catch (final GSSException gsse) {
          state = State.FAILED;
          if (gsse.getMajor() == GSSException.DEFECTIVE_CREDENTIAL
              || gsse.getMajor() == GSSException.CREDENTIALS_EXPIRED) {
            throw new InvalidCredentialsException(gsse.getMessage(), gsse);
          }
          if (gsse.getMajor() == GSSException.NO_CRED) {
            throw new InvalidCredentialsException(gsse.getMessage(), gsse);
          }
          if (gsse.getMajor() == GSSException.DEFECTIVE_TOKEN
              || gsse.getMajor() == GSSException.DUPLICATE_TOKEN
              || gsse.getMajor() == GSSException.OLD_TOKEN) {
            throw new AuthenticationException(gsse.getMessage(), gsse);
          }
          // other error
          throw new AuthenticationException(gsse.getMessage());
        }
      case TOKEN_GENERATED:
        final String tokenstr = new String(base64codec.encode(token));
        if (log.isDebugEnabled()) {
          log.debug("Sending response '" + tokenstr + "' back to the auth server");
        }
        final CharArrayBuffer buffer = new CharArrayBuffer(32);
        if (isProxy()) {
          buffer.append(AUTH.PROXY_AUTH_RESP);
        } else {
          buffer.append(AUTH.WWW_AUTH_RESP);
        }
        buffer.append(": Negotiate ");
        buffer.append(tokenstr);
        return new BufferedHeader(buffer);
      default:
        throw new IllegalStateException("Illegal state: " + state);
    }
  }
Esempio n. 14
0
  /**
   * Analyzes a response to check need for a followup.
   *
   * @param roureq the request and route.
   * @param response the response to analayze
   * @param context the context used for the current request execution
   * @return the followup request and route if there is a followup, or <code>null</code> if the
   *     response should be returned as is
   * @throws HttpException in case of a problem
   * @throws IOException in case of an IO problem
   */
  protected RoutedRequest handleResponse(
      RoutedRequest roureq, HttpResponse response, HttpContext context)
      throws HttpException, IOException {

    HttpRoute route = roureq.getRoute();
    HttpHost proxy = route.getProxyHost();
    RequestWrapper request = roureq.getRequest();

    HttpParams params = request.getParams();
    if (HttpClientParams.isRedirecting(params)
        && this.redirectHandler.isRedirectRequested(response, context)) {

      if (redirectCount >= maxRedirects) {
        throw new RedirectException("Maximum redirects (" + maxRedirects + ") exceeded");
      }
      redirectCount++;

      URI uri = this.redirectHandler.getLocationURI(response, context);

      HttpHost newTarget = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());

      HttpGet redirect = new HttpGet(uri);

      HttpRequest orig = request.getOriginal();
      redirect.setHeaders(orig.getAllHeaders());

      RequestWrapper wrapper = new RequestWrapper(redirect);
      wrapper.setParams(params);

      HttpRoute newRoute = determineRoute(newTarget, wrapper, context);
      RoutedRequest newRequest = new RoutedRequest(wrapper, newRoute);

      if (this.log.isDebugEnabled()) {
        this.log.debug("Redirecting to '" + uri + "' via " + newRoute);
      }

      return newRequest;
    }

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

    if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {

      if (this.targetAuthHandler.isAuthenticationRequested(response, context)) {

        HttpHost target = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
        if (target == null) {
          target = route.getTargetHost();
        }

        this.log.debug("Target requested authentication");
        Map<String, Header> challenges = this.targetAuthHandler.getChallenges(response, context);
        try {
          processChallenges(
              challenges, this.targetAuthState, this.targetAuthHandler, response, context);
        } catch (AuthenticationException ex) {
          if (this.log.isWarnEnabled()) {
            this.log.warn("Authentication error: " + ex.getMessage());
            return null;
          }
        }
        updateAuthState(this.targetAuthState, target, credsProvider);

        if (this.targetAuthState.getCredentials() != null) {
          // Re-try the same request via the same route
          return roureq;
        } else {
          return null;
        }
      } else {
        // Reset target auth scope
        this.targetAuthState.setAuthScope(null);
      }

      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());
            return null;
          }
        }
        updateAuthState(this.proxyAuthState, proxy, credsProvider);

        if (this.proxyAuthState.getCredentials() != null) {
          // Re-try the same request via the same route
          return roureq;
        } else {
          return null;
        }
      } else {
        // Reset proxy auth scope
        this.proxyAuthState.setAuthScope(null);
      }
    }
    return null;
  } // handleResponse
Esempio n. 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
Esempio n. 16
0
  /**
   * Establishes the target route.
   *
   * @param route the route to establish
   * @param context the context for the request execution
   * @throws HttpException in case of a problem
   * @throws IOException in case of an IO problem
   */
  protected void establishRoute(HttpRoute route, HttpContext context)
      throws HttpException, IOException {

    // @@@ how to handle CONNECT requests for tunnelling?
    // @@@ refuse to send external CONNECT via director? special handling?

    // @@@ should the request parameters already be used below?
    // @@@ probably yes, but they're not linked yet
    // @@@ will linking above cause problems with linking in reqExec?
    // @@@ probably not, because the parent is replaced
    // @@@ just make sure we don't link parameters to themselves

    HttpRouteDirector rowdy = new BasicRouteDirector();
    int step;
    do {
      HttpRoute fact = managedConn.getRoute();
      step = rowdy.nextStep(route, fact);

      switch (step) {
        case HttpRouteDirector.CONNECT_TARGET:
        case HttpRouteDirector.CONNECT_PROXY:
          managedConn.open(route, context, this.params);
          break;

        case HttpRouteDirector.TUNNEL_TARGET:
          {
            boolean secure = createTunnelToTarget(route, context);
            this.log.debug("Tunnel to target created.");
            managedConn.tunnelTarget(secure, this.params);
          }
          break;

        case HttpRouteDirector.TUNNEL_PROXY:
          {
            // The most simple example for this case is a proxy chain
            // of two proxies, where P1 must be tunnelled to P2.
            // route: Source -> P1 -> P2 -> Target (3 hops)
            // fact:  Source -> P1 -> Target       (2 hops)
            final int hop = fact.getHopCount() - 1; // the hop to establish
            boolean secure = createTunnelToProxy(route, hop, context);
            this.log.debug("Tunnel to proxy created.");
            managedConn.tunnelProxy(route.getHopTarget(hop), secure, this.params);
          }
          break;

        case HttpRouteDirector.LAYER_PROTOCOL:
          managedConn.layerProtocol(context, this.params);
          break;

        case HttpRouteDirector.UNREACHABLE:
          throw new IllegalStateException(
              "Unable to establish route." + "\nplanned = " + route + "\ncurrent = " + fact);

        case HttpRouteDirector.COMPLETE:
          // do nothing
          break;

        default:
          throw new IllegalStateException(
              "Unknown step indicator " + step + " from RouteDirector.");
      } // switch

    } while (step > HttpRouteDirector.COMPLETE);
  } // establishConnection
Esempio n. 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