private void writeToFromFile(OutputStream os, RequestParams.FileWrapper wrapper)
      throws IOException {

    // Send the meta data.
    writeMetaData(os, wrapper.file.getName(), wrapper.contentType);

    int bytesRead;
    long bytesWritten = 0, totalSize = wrapper.file.length();

    // Open the file for reading.
    FileInputStream in = new FileInputStream(wrapper.file);

    // Upload the file's contents in Base64.
    Base64OutputStream bos = new Base64OutputStream(os, Base64.NO_CLOSE | Base64.NO_WRAP);

    // Read from file until no more data's left to read.
    while ((bytesRead = in.read(buffer)) != -1) {
      bos.write(buffer, 0, bytesRead);
      bytesWritten += bytesRead;
      progressHandler.sendProgressMessage(bytesWritten, totalSize);
    }

    // Close the Base64 output stream.
    AsyncHttpClient.silentCloseOutputStream(bos);

    // End the meta data.
    endMetaData(os);

    // Safely close the input stream.
    AsyncHttpClient.silentCloseInputStream(in);
  }
  @Test(groups = {"standalone", "default_provider"})
  public void testListenableFuture() throws Exception {
    final AtomicInteger statusCode = new AtomicInteger(500);
    try (AsyncHttpClient ahc = asyncHttpClient()) {
      final CountDownLatch latch = new CountDownLatch(1);
      final ListenableFuture<Response> future = ahc.prepareGet(getTargetUrl()).execute();
      future.addListener(
          new Runnable() {

            public void run() {
              try {
                statusCode.set(future.get().getStatusCode());
                latch.countDown();
              } catch (InterruptedException e) {
                e.printStackTrace();
              } catch (ExecutionException e) {
                e.printStackTrace();
              }
            }
          },
          Executors.newFixedThreadPool(1));

      latch.await(10, TimeUnit.SECONDS);
      assertEquals(statusCode.get(), 200);
    }
  }
  @Test(groups = "standalone")
  public void asyncStreamThrowableRefusedTest() throws Exception {

    final CountDownLatch l = new CountDownLatch(1);
    try (AsyncHttpClient c = asyncHttpClient()) {
      c.prepareGet(getTargetUrl())
          .execute(
              new AsyncHandlerAdapter() {

                @Override
                public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                  throw new RuntimeException("FOO");
                }

                @Override
                public void onThrowable(Throwable t) {
                  try {
                    if (t.getMessage() != null) {
                      assertEquals(t.getMessage(), "FOO");
                    }
                  } finally {
                    l.countDown();
                  }
                }
              });

      if (!l.await(10, TimeUnit.SECONDS)) {
        fail("Timed out");
      }
    }
  }
  @Test(groups = "online")
  public void asyncOptionsTest() throws Exception {
    final AtomicReference<HttpHeaders> responseHeaders = new AtomicReference<>();

    try (AsyncHttpClient c = asyncHttpClient()) {
      final String[] expected = {"GET", "HEAD", "OPTIONS", "POST", "TRACE"};
      Future<String> f =
          c.prepareOptions("http://www.apache.org/")
              .execute(
                  new AsyncHandlerAdapter() {

                    @Override
                    public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                      responseHeaders.set(content.getHeaders());
                      return State.ABORT;
                    }

                    @Override
                    public String onCompleted() throws Exception {
                      return "OK";
                    }
                  });

      f.get(20, TimeUnit.SECONDS);
      HttpHeaders h = responseHeaders.get();
      assertNotNull(h);
      String[] values = h.get(HttpHeaders.Names.ALLOW).split(",|, ");
      assertNotNull(values);
      assertEquals(values.length, expected.length);
      Arrays.sort(values);
      assertEquals(values, expected);
    }
  }
  private F.Promise<WSResponse> execute(Request request) {

    final scala.concurrent.Promise<WSResponse> scalaPromise =
        scala.concurrent.Promise$.MODULE$.<WSResponse>apply();
    try {
      AsyncHttpClient asyncHttpClient = (AsyncHttpClient) client.getUnderlying();
      asyncHttpClient.executeRequest(
          request,
          new AsyncCompletionHandler<Response>() {
            @Override
            public Response onCompleted(Response response) {
              final Response ahcResponse = response;
              scalaPromise.success(new AhcWSResponse(ahcResponse));
              return response;
            }

            @Override
            public void onThrowable(Throwable t) {
              scalaPromise.failure(t);
            }
          });
    } catch (RuntimeException exception) {
      scalaPromise.failure(exception);
    }
    return F.Promise.wrap(scalaPromise.future());
  }
  @Test(groups = "online")
  public void asyncStatusHEADContentLenghtTest() throws Exception {
    try (AsyncHttpClient p = asyncHttpClient(config().setFollowRedirect(true))) {
      final CountDownLatch l = new CountDownLatch(1);

      p.executeRequest(
              head("http://www.google.com/"),
              new AsyncCompletionHandlerAdapter() {
                @Override
                public Response onCompleted(Response response) throws Exception {
                  try {
                    assertEquals(response.getStatusCode(), 200);
                    return response;
                  } finally {
                    l.countDown();
                  }
                }
              })
          .get();

      if (!l.await(5, TimeUnit.SECONDS)) {
        fail("Timeout out");
      }
    }
  }
  private void writeToFromStream(OutputStream os, RequestParams.StreamWrapper entry)
      throws IOException {

    // Send the meta data.
    writeMetaData(os, entry.name, entry.contentType);

    int bytesRead;

    // Upload the file's contents in Base64.
    Base64OutputStream bos = new Base64OutputStream(os, Base64.NO_CLOSE | Base64.NO_WRAP);

    // Read from input stream until no more data's left to read.
    while ((bytesRead = entry.inputStream.read(buffer)) != -1) {
      bos.write(buffer, 0, bytesRead);
    }

    // Close the Base64 output stream.
    AsyncHttpClient.silentCloseOutputStream(bos);

    // End the meta data.
    endMetaData(os);

    // Close input stream.
    if (entry.autoClose) {
      // Safely close the input stream.
      AsyncHttpClient.silentCloseInputStream(entry.inputStream);
    }
  }
 @Test(groups = "online")
 public void testGoogleComWithTimeout() throws Exception {
   try (AsyncHttpClient c = asyncHttpClient(config().setRequestTimeout(10000))) {
     Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS);
     assertNotNull(response);
     assertTrue(response.getStatusCode() == 301 || response.getStatusCode() == 302);
   }
 }
 @Test(groups = "online")
 public void testMailGoogleCom() throws Exception {
   try (AsyncHttpClient c = asyncHttpClient(config().setRequestTimeout(10000))) {
     Response response =
         c.prepareGet("http://mail.google.com/").execute().get(10, TimeUnit.SECONDS);
     assertNotNull(response);
     assertEquals(response.getStatusCode(), 200);
   }
 }
 @Test(groups = "online", enabled = false)
 // FIXME
 public void testMicrosoftCom() throws Exception {
   try (AsyncHttpClient c = asyncHttpClient(config().setRequestTimeout(10000))) {
     Response response = c.prepareGet("http://microsoft.com/").execute().get(10, TimeUnit.SECONDS);
     assertNotNull(response);
     assertEquals(response.getStatusCode(), 301);
   }
 }
 // FIXME Get a 302 in France...
 @Test(groups = "online", enabled = false)
 public void testUrlRequestParametersEncoding() throws Exception {
   try (AsyncHttpClient client = asyncHttpClient()) {
     String requestUrl2 = URL + URLEncoder.encode(REQUEST_PARAM, UTF_8.name());
     logger.info(String.format("Executing request [%s] ...", requestUrl2));
     Response response = client.prepareGet(requestUrl2).execute().get();
     assertEquals(response.getStatusCode(), 302);
   }
 }
  @Test(groups = "online")
  public void stripQueryStringTest() throws Exception {

    try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) {
      Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get();

      assertNotNull(response);
      assertEquals(response.getStatusCode(), 200);
    }
  }
  @Test(groups = "online")
  public void asyncFullBodyProperlyRead() throws Exception {
    try (AsyncHttpClient client = asyncHttpClient()) {
      Response r = client.prepareGet("http://www.cyberpresse.ca/").execute().get();

      InputStream stream = r.getResponseBodyAsStream();
      int contentLength = Integer.valueOf(r.getHeader("Content-Length"));

      assertEquals(contentLength, IOUtils.toByteArray(stream).length);
    }
  }
 // @Test(groups = "online")
 public void notRedirected302Test() throws Exception {
   isSet.getAndSet(false);
   try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) {
     Response response =
         c.prepareGet(getTargetUrl())
             .setFollowRedirect(false)
             .setHeader("X-redirect", "http://www.microsoft.com/")
             .execute()
             .get();
     assertNotNull(response);
     assertEquals(response.getStatusCode(), 302);
   }
 }
 @Test(groups = "standalone")
 public void testQueryParameters() throws Exception {
   try (AsyncHttpClient client = asyncHttpClient()) {
     Future<Response> f =
         client
             .prepareGet("http://127.0.0.1:" + port1 + "/foo")
             .addHeader("Accepts", "*/*")
             .execute();
     Response resp = f.get(3, TimeUnit.SECONDS);
     assertNotNull(resp);
     assertEquals(resp.getStatusCode(), 400);
     assertEquals(resp.getResponseBody(), BAD_REQUEST_STR);
   }
 }
 public static ResponseCacheMiddleware addCache(AsyncHttpClient client, File cacheDir, long size)
     throws IOException {
   for (AsyncHttpClientMiddleware middleware : client.getMiddleware()) {
     if (middleware instanceof ResponseCacheMiddleware)
       throw new IOException("Response cache already added to http client");
   }
   ResponseCacheMiddleware ret = new ResponseCacheMiddleware();
   ret.size = size;
   ret.client = client;
   ret.cacheDir = cacheDir;
   ret.open();
   client.insertMiddleware(ret);
   return ret;
 }
  // @Test(groups = "standalone")
  public void relativeLocationUrl() throws Exception {
    isSet.getAndSet(false);

    try (AsyncHttpClient c = asyncHttpClient()) {
      Response response =
          c.preparePost(getTargetUrl())
              .setFollowRedirect(true)
              .setHeader("X-redirect", "/foo/test")
              .execute()
              .get();
      assertNotNull(response);
      assertEquals(response.getStatusCode(), 200);
      assertEquals(response.getUri().toString(), getTargetUrl());
    }
  }
 /**
  * Deconstructs response into given content handler
  *
  * @param entity returned HttpEntity
  * @return deconstructed response
  * @throws java.io.IOException
  * @see org.apache.http.HttpEntity
  */
 @Override
 protected byte[] getResponseData(HttpEntity entity) throws IOException {
   if (entity != null) {
     InputStream instream = entity.getContent();
     InputStreamReader inputStreamReader = null;
     if (instream != null) {
       try {
         SAXParserFactory sfactory = SAXParserFactory.newInstance();
         SAXParser sparser = sfactory.newSAXParser();
         XMLReader rssReader = sparser.getXMLReader();
         rssReader.setContentHandler(handler);
         inputStreamReader = new InputStreamReader(instream, DEFAULT_CHARSET);
         rssReader.parse(new InputSource(inputStreamReader));
       } catch (SAXException e) {
         Log.e(LOG_TAG, "getResponseData exception", e);
       } catch (ParserConfigurationException e) {
         Log.e(LOG_TAG, "getResponseData exception", e);
       } finally {
         AsyncHttpClient.silentCloseInputStream(instream);
         if (inputStreamReader != null) {
           try {
             inputStreamReader.close();
           } catch (IOException e) {
             /*ignore*/
           }
         }
       }
     }
   }
   return null;
 }
  @Test(groups = "standalone")
  public void asyncStreamFutureTest() throws Exception {
    final AtomicReference<HttpHeaders> responseHeaders = new AtomicReference<>();
    final AtomicReference<Throwable> throwable = new AtomicReference<>();
    try (AsyncHttpClient c = asyncHttpClient()) {
      Future<String> f =
          c.preparePost(getTargetUrl())
              .addFormParam("param_1", "value_1")
              .execute(
                  new AsyncHandlerAdapter() {
                    private StringBuilder builder = new StringBuilder();

                    @Override
                    public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                      responseHeaders.set(content.getHeaders());
                      return State.CONTINUE;
                    }

                    @Override
                    public State onBodyPartReceived(HttpResponseBodyPart content) throws Exception {
                      builder.append(new String(content.getBodyPartBytes()));
                      return State.CONTINUE;
                    }

                    @Override
                    public String onCompleted() throws Exception {
                      return builder.toString().trim();
                    }

                    @Override
                    public void onThrowable(Throwable t) {
                      throwable.set(t);
                    }
                  });

      String responseBody = f.get(5, TimeUnit.SECONDS);
      HttpHeaders h = responseHeaders.get();
      assertNotNull(h, "Should receive non null headers");
      assertEquals(
          h.get(HttpHeaders.Names.CONTENT_TYPE).toLowerCase(Locale.ENGLISH),
          TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH),
          "Unexpected content-type");
      assertNotNull(responseBody, "No response body");
      assertEquals(responseBody.trim(), RESPONSE, "Unexpected response body");
      assertNull(throwable.get(), "Unexpected exception");
    }
  }
  @Test(groups = "standalone")
  public void asyncStreamInterruptTest() throws Exception {
    final CountDownLatch l = new CountDownLatch(1);

    final AtomicReference<HttpHeaders> responseHeaders = new AtomicReference<>();
    final AtomicBoolean bodyReceived = new AtomicBoolean(false);
    final AtomicReference<Throwable> throwable = new AtomicReference<>();
    try (AsyncHttpClient c = asyncHttpClient()) {
      c.preparePost(getTargetUrl()) //
          .setHeader("Content-Type", "application/x-www-form-urlencoded") //
          .addFormParam("param_1", "value_1") //
          .execute(
              new AsyncHandlerAdapter() {

                @Override
                public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                  responseHeaders.set(content.getHeaders());
                  return State.ABORT;
                }

                @Override
                public State onBodyPartReceived(final HttpResponseBodyPart content)
                    throws Exception {
                  bodyReceived.set(true);
                  return State.ABORT;
                }

                @Override
                public void onThrowable(Throwable t) {
                  throwable.set(t);
                  l.countDown();
                }
              });

      l.await(5, TimeUnit.SECONDS);
      assertTrue(!bodyReceived.get(), "Interrupted not working");
      HttpHeaders h = responseHeaders.get();
      assertNotNull(h, "Should receive non null headers");
      assertEquals(
          h.get(HttpHeaders.Names.CONTENT_TYPE).toLowerCase(Locale.ENGLISH),
          TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH),
          "Unexpected content-type");
      assertNull(throwable.get(), "Should get an exception");
    }
  }
  @Test(groups = "online")
  public void asyncStream302RedirectWithBody() throws Exception {
    final AtomicReference<Integer> statusCode = new AtomicReference<>(0);
    final AtomicReference<HttpHeaders> responseHeaders = new AtomicReference<>();
    try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) {
      Future<String> f =
          c.prepareGet("http://google.com/")
              .execute(
                  new AsyncHandlerAdapter() {

                    public State onStatusReceived(HttpResponseStatus status) throws Exception {
                      statusCode.set(status.getStatusCode());
                      return State.CONTINUE;
                    }

                    @Override
                    public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                      responseHeaders.set(content.getHeaders());
                      return State.CONTINUE;
                    }

                    @Override
                    public String onCompleted() throws Exception {
                      return null;
                    }
                  });

      f.get(20, TimeUnit.SECONDS);
      assertTrue(statusCode.get() != 302);
      HttpHeaders h = responseHeaders.get();
      assertNotNull(h);
      assertEquals(h.get("server"), "gws");
      // This assertion below is not an invariant, since implicitly contains locale-dependant
      // settings
      // and fails when run in country having own localized Google site and it's locale relies on
      // something
      // other than ISO-8859-1.
      // In Hungary for example, http://google.com/ redirects to http://www.google.hu/, a localized
      // Google site, that uses ISO-8892-2 encoding (default for HU). Similar is true for other
      // non-ISO-8859-1 using countries that have "localized" google, like google.hr, google.rs,
      // google.cz, google.sk etc.
      //
      // assertEquals(h.get(HttpHeaders.Names.CONTENT_TYPE), "text/html; charset=ISO-8859-1");
    }
  }
  @Test(groups = "standalone")
  public void closeConnectionTest() throws Exception {
    try (AsyncHttpClient c = asyncHttpClient()) {
      Response r =
          c.prepareGet(getTargetUrl())
              .execute(
                  new AsyncHandler<Response>() {

                    private Response.ResponseBuilder builder = new Response.ResponseBuilder();

                    public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                      builder.accumulate(content);
                      return State.CONTINUE;
                    }

                    public void onThrowable(Throwable t) {}

                    public State onBodyPartReceived(HttpResponseBodyPart content) throws Exception {
                      builder.accumulate(content);

                      if (content.isLast()) {
                        content.markUnderlyingConnectionAsToBeClosed();
                      }
                      return State.CONTINUE;
                    }

                    public State onStatusReceived(HttpResponseStatus responseStatus)
                        throws Exception {
                      builder.accumulate(responseStatus);

                      return State.CONTINUE;
                    }

                    public Response onCompleted() throws Exception {
                      return builder.build();
                    }
                  })
              .get();

      assertNotNull(r);
      assertEquals(r.getStatusCode(), 200);
    }
  }
  // @Test(groups = "standalone")
  public void redirected302InvalidTest() throws Exception {
    isSet.getAndSet(false);
    Exception e = null;

    try (AsyncHttpClient c = asyncHttpClient()) {
      c.preparePost(getTargetUrl())
          .setFollowRedirect(true)
          .setHeader("X-redirect", String.format("http://localhost:%d/", port2))
          .execute()
          .get();
    } catch (ExecutionException ex) {
      e = ex;
    }

    assertNotNull(e);
    Throwable cause = e.getCause();
    assertTrue(cause instanceof ConnectException);
    assertTrue(cause.getMessage().contains(":" + port2));
  }
  @Test(groups = "standalone")
  public void asyncStreamGETTest() throws Exception {
    final CountDownLatch l = new CountDownLatch(1);
    final AtomicReference<HttpHeaders> responseHeaders = new AtomicReference<>();
    final AtomicReference<Throwable> throwable = new AtomicReference<>();
    try (AsyncHttpClient c = asyncHttpClient()) {
      c.prepareGet(getTargetUrl())
          .execute(
              new AsyncHandlerAdapter() {

                @Override
                public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                  try {
                    responseHeaders.set(content.getHeaders());
                    return State.ABORT;
                  } finally {
                    l.countDown();
                  }
                }

                @Override
                public void onThrowable(Throwable t) {
                  try {
                    throwable.set(t);
                  } finally {
                    l.countDown();
                  }
                }
              });

      if (!l.await(5, TimeUnit.SECONDS)) {
        fail("Timeout out");
      }

      HttpHeaders h = responseHeaders.get();
      assertNotNull(h, "No response headers");
      assertEquals(
          h.get(HttpHeaders.Names.CONTENT_TYPE),
          TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET,
          "Unexpected content-type");
      assertNull(throwable.get(), "Unexpected exception");
    }
  }
  @Test(groups = "online", enabled = false)
  public void testAHC62Com() throws Exception {
    try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) {
      Response response =
          c.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js")
              .execute(
                  new AsyncHandler<Response>() {

                    private Response.ResponseBuilder builder = new Response.ResponseBuilder();

                    public void onThrowable(Throwable t) {
                      t.printStackTrace();
                    }

                    public State onBodyPartReceived(HttpResponseBodyPart bodyPart)
                        throws Exception {
                      System.out.println(bodyPart.getBodyPartBytes().length);
                      builder.accumulate(bodyPart);

                      return State.CONTINUE;
                    }

                    public State onStatusReceived(HttpResponseStatus responseStatus)
                        throws Exception {
                      builder.accumulate(responseStatus);
                      return State.CONTINUE;
                    }

                    public State onHeadersReceived(HttpResponseHeaders headers) throws Exception {
                      builder.accumulate(headers);
                      return State.CONTINUE;
                    }

                    public Response onCompleted() throws Exception {
                      return builder.build();
                    }
                  })
              .get(10, TimeUnit.SECONDS);
      assertNotNull(response);
      assertTrue(response.getResponseBody().length() >= 3870);
    }
  }
  // @Test(groups = "online")
  public void redirected302Test() throws Exception {
    isSet.getAndSet(false);
    try (AsyncHttpClient c = asyncHttpClient()) {
      Response response =
          c.prepareGet(getTargetUrl())
              .setFollowRedirect(true)
              .setHeader("X-redirect", "http://www.microsoft.com/")
              .execute()
              .get();

      assertNotNull(response);
      assertEquals(response.getStatusCode(), 200);

      String anyMicrosoftPage = "http://www.microsoft.com[^:]*:80";
      String baseUrl = getBaseUrl(response.getUri());

      assertTrue(
          baseUrl.matches(anyMicrosoftPage),
          "response does not show redirection to " + anyMicrosoftPage);
    }
  }
  @Test(groups = "online", enabled = false)
  public void invalidStreamTest2() throws Exception {
    AsyncHttpClientConfig config =
        config() //
            .setRequestTimeout(10000) //
            .setFollowRedirect(true) //
            .setKeepAlive(false) //
            .setMaxRedirects(6) //
            .build();

    try (AsyncHttpClient c = asyncHttpClient(config)) {
      Response response = c.prepareGet("http://bit.ly/aUjTtG").execute().get();
      if (response != null) {
        System.out.println(response);
      }
    } catch (Throwable t) {
      t.printStackTrace();
      assertNotNull(t.getCause());
      assertEquals(t.getCause().getMessage(), "invalid version format: ICY");
    }
  }
  @Test(groups = "standalone")
  public void asyncStreamPOSTTest() throws Exception {

    final AtomicReference<HttpHeaders> responseHeaders = new AtomicReference<>();

    try (AsyncHttpClient c = asyncHttpClient()) {
      Future<String> f =
          c.preparePost(getTargetUrl()) //
              .setHeader("Content-Type", "application/x-www-form-urlencoded") //
              .addFormParam("param_1", "value_1") //
              .execute(
                  new AsyncHandlerAdapter() {
                    private StringBuilder builder = new StringBuilder();

                    @Override
                    public State onHeadersReceived(HttpResponseHeaders content) throws Exception {
                      responseHeaders.set(content.getHeaders());
                      return State.CONTINUE;
                    }

                    @Override
                    public State onBodyPartReceived(HttpResponseBodyPart content) throws Exception {
                      builder.append(new String(content.getBodyPartBytes()));
                      return State.CONTINUE;
                    }

                    @Override
                    public String onCompleted() throws Exception {
                      return builder.toString().trim();
                    }
                  });

      String responseBody = f.get(10, TimeUnit.SECONDS);
      HttpHeaders h = responseHeaders.get();
      assertNotNull(h);
      assertEquals(
          h.get(HttpHeaders.Names.CONTENT_TYPE), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET);
      assertEquals(responseBody, RESPONSE);
    }
  }
  @Test(groups = "online")
  public void evilCoookieTest() throws Exception {
    try (AsyncHttpClient c = asyncHttpClient()) {
      RequestBuilder builder =
          get("http://localhost") //
              .setFollowRedirect(true) //
              .setUrl("http://www.google.com/") //
              .addHeader("Content-Type", "text/plain") //
              .addCookie(
                  new Cookie(
                      "evilcookie",
                      "test",
                      false,
                      ".google.com",
                      "/",
                      Long.MIN_VALUE,
                      false,
                      false));

      Response response = c.executeRequest(builder.build()).get();
      assertNotNull(response);
      assertEquals(response.getStatusCode(), 200);
    }
  }
  @Override
  public Cancellable getSocket(final AsyncHttpClientMiddleware.GetSocketData data) {
    final URI uri = data.request.getUri();
    final int port = getSchemePort(data.request.getUri());
    if (port == -1) {
      return null;
    }

    ConnectionInfo info = getConnectionInfo(uri.getScheme(), uri.getHost(), port);
    if (info.openCount >= maxConnectionCount) {
      // wait for a connection queue to free up
      SimpleCancellable queueCancel = new SimpleCancellable();
      info.queue.add(data);
      return queueCancel;
    }

    info.openCount++;

    final String lookup = computeLookup(uri, port, data.request);

    data.state.putBoolean(getClass().getCanonicalName() + ".owned", true);

    synchronized (this) {
      final HashSet<AsyncSocket> sockets = mSockets.get(lookup);
      if (sockets != null) {
        for (final AsyncSocket socket : sockets) {
          if (socket.isOpen()) {
            sockets.remove(socket);
            socket.setClosedCallback(null);

            mClient
                .getServer()
                .post(
                    new Runnable() {
                      @Override
                      public void run() {
                        data.request.logd("Reusing keep-alive socket");
                        data.connectCallback.onConnectCompleted(null, socket);
                      }
                    });

            // replace above code with immediate callback?
            //                        data.request.logd("Reusing keep-alive socket");
            //                        data.connectCallback.onConnectCompleted(null, socket);

            // just a noop/dummy, as this can't actually be cancelled.
            return new SimpleCancellable();
          }
        }
      }
    }

    if (!connectAllAddresses || proxyHost != null || data.request.getProxyHost() != null) {
      // just default to connecting to a single address
      data.request.logd("Connecting socket");
      String unresolvedHost;
      int unresolvedPort;
      if (data.request.getProxyHost() != null) {
        unresolvedHost = data.request.getProxyHost();
        unresolvedPort = data.request.getProxyPort();
        // set the host and port explicitly for proxied connections
        data.request
            .getHeaders()
            .getHeaders()
            .setStatusLine(data.request.getProxyRequestLine().toString());
      } else if (proxyHost != null) {
        unresolvedHost = proxyHost;
        unresolvedPort = proxyPort;
        // set the host and port explicitly for proxied connections
        data.request
            .getHeaders()
            .getHeaders()
            .setStatusLine(data.request.getProxyRequestLine().toString());
      } else {
        unresolvedHost = uri.getHost();
        unresolvedPort = port;
      }
      return mClient
          .getServer()
          .connectSocket(
              unresolvedHost, unresolvedPort, wrapCallback(data.connectCallback, uri, port));
    }

    // try to connect to everything...
    data.request.logv("Resolving domain and connecting to all available addresses");
    return mClient
        .getServer()
        .getAllByName(uri.getHost())
        .then(
            new TransformFuture<AsyncSocket, InetAddress[]>() {
              Exception lastException;

              @Override
              protected void error(Exception e) {
                super.error(e);
                data.connectCallback.onConnectCompleted(e, null);
              }

              @Override
              protected void transform(final InetAddress[] result) throws Exception {
                Continuation keepTrying =
                    new Continuation(
                        new CompletedCallback() {
                          @Override
                          public void onCompleted(Exception ex) {
                            // if it completed, that means that the connection failed
                            if (lastException == null)
                              lastException =
                                  new ConnectionFailedException(
                                      "Unable to connect to remote address");
                            setComplete(lastException);
                          }
                        });

                for (final InetAddress address : result) {
                  keepTrying.add(
                      new ContinuationCallback() {
                        @Override
                        public void onContinue(
                            Continuation continuation, final CompletedCallback next)
                            throws Exception {
                          mClient
                              .getServer()
                              .connectSocket(
                                  new InetSocketAddress(address, port),
                                  wrapCallback(
                                      new ConnectCallback() {
                                        @Override
                                        public void onConnectCompleted(
                                            Exception ex, AsyncSocket socket) {
                                          if (isDone()) {
                                            lastException =
                                                new Exception("internal error during connect");
                                            next.onCompleted(null);
                                            return;
                                          }

                                          // try the next address
                                          if (ex != null) {
                                            lastException = ex;
                                            next.onCompleted(null);
                                            return;
                                          }

                                          // if the socket is no longer needed, just hang onto it...
                                          if (isDone() || isCancelled()) {
                                            data.request.logd(
                                                "Recycling extra socket leftover from cancelled operation");
                                            idleSocket(socket);
                                            recycleSocket(socket, data.request);
                                            return;
                                          }

                                          if (setComplete(null, socket)) {
                                            data.connectCallback.onConnectCompleted(ex, socket);
                                          }
                                        }
                                      },
                                      uri,
                                      port));
                        }
                      });
                }

                keepTrying.start();
              }
            });
  }