@Test
  public void testHttpPostIdentity() throws Exception {
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {

            if (request instanceof HttpEntityEnclosingRequest) {
              final HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
              final byte[] data = EntityUtils.toByteArray(incoming);
              final ByteArrayEntity outgoing = new ByteArrayEntity(data);
              response.setEntity(outgoing);
            } else {
              final StringEntity outgoing = new StringEntity("No content");
              response.setEntity(outgoing);
            }
          }
        });

    this.server.start();

    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      if (!conn.isOpen()) {
        client.connect(host, conn);
      }

      final BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
      post.setEntity(null);

      this.client =
          new HttpClient(
              new ImmutableHttpProcessor(
                  new HttpRequestInterceptor[] {
                    new HttpRequestInterceptor() {

                      public void process(final HttpRequest request, final HttpContext context)
                          throws HttpException, IOException {
                        request.addHeader(HTTP.TRANSFER_ENCODING, "identity");
                      }
                    },
                    new RequestTargetHost(),
                    new RequestConnControl(),
                    new RequestUserAgent(),
                    new RequestExpectContinue(true)
                  }));

      final HttpResponse response = this.client.execute(post, host, conn);
      Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
    } finally {
      conn.close();
      this.server.shutdown();
    }
  }
  @Test
  public void testNoContentResponse() throws Exception {

    final int reqNo = 20;

    // Initialize the server-side request handler
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {
            response.setStatusCode(HttpStatus.SC_NO_CONTENT);
          }
        });

    this.server.start();

    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      for (int r = 0; r < reqNo; r++) {
        if (!conn.isOpen()) {
          client.connect(host, conn);
        }

        final BasicHttpRequest get = new BasicHttpRequest("GET", "/?" + r);
        final HttpResponse response = this.client.execute(get, host, conn);
        Assert.assertNull(response.getEntity());
        if (!this.client.keepAlive(response)) {
          conn.close();
          Assert.fail("Connection expected to be re-usable");
        }
      }

      // Verify the connection metrics
      final HttpConnectionMetrics cm = conn.getMetrics();
      Assert.assertEquals(reqNo, cm.getRequestCount());
      Assert.assertEquals(reqNo, cm.getResponseCount());

    } finally {
      conn.close();
      this.server.shutdown();
    }
  }
  @Test
  public void testHttpPostNoEntity() throws Exception {
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {

            if (request instanceof HttpEntityEnclosingRequest) {
              final HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
              final byte[] data = EntityUtils.toByteArray(incoming);
              final ByteArrayEntity outgoing = new ByteArrayEntity(data);
              response.setEntity(outgoing);
            } else {
              final StringEntity outgoing = new StringEntity("No content");
              response.setEntity(outgoing);
            }
          }
        });

    this.server.start();

    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      if (!conn.isOpen()) {
        client.connect(host, conn);
      }

      final BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
      post.setEntity(null);

      final HttpResponse response = this.client.execute(post, host, conn);
      Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
      final byte[] received = EntityUtils.toByteArray(response.getEntity());
      Assert.assertEquals(0, received.length);
    } finally {
      conn.close();
      this.server.shutdown();
    }
  }
  @Test
  public void testHttpContent() throws Exception {

    final String[] patterns = {
      "0123456789ABCDEF",
      "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that-"
          + "yadayada-blahblah-this-and-that-yadayada-blahblah-this-and-that"
    };

    // Initialize the server-side request handler
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {

            if (request instanceof HttpEntityEnclosingRequest) {
              int n = 1;
              String s = request.getRequestLine().getUri();
              if (s.startsWith("/?n=")) {
                s = s.substring(4);
                try {
                  n = Integer.parseInt(s);
                  if (n <= 0) {
                    throw new HttpException(
                        "Invalid request: " + "number of repetitions cannot be negative or zero");
                  }
                } catch (final NumberFormatException ex) {
                  throw new HttpException("Invalid request: " + "number of repetitions is invalid");
                }
              }

              final HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
              final String line = EntityUtils.toString(incoming);
              final ContentType contentType = ContentType.getOrDefault(incoming);
              Charset charset = contentType.getCharset();
              if (charset == null) {
                charset = HTTP.DEF_CONTENT_CHARSET;
              }
              final RepeatingEntity outgoing = new RepeatingEntity(line, charset, n);
              outgoing.setChunked(n % 2 == 0);
              response.setEntity(outgoing);
            } else {
              throw new HttpException("Invalid request: POST request expected");
            }
          }
        });

    this.server.start();
    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      for (final String pattern : patterns) {
        for (int n = 1000; n < 1020; n++) {
          if (!conn.isOpen()) {
            client.connect(host, conn);
          }

          final BasicHttpEntityEnclosingRequest post =
              new BasicHttpEntityEnclosingRequest("POST", "/?n=" + n);
          final StringEntity outgoing = new StringEntity(pattern);
          outgoing.setChunked(n % 2 == 0);
          post.setEntity(outgoing);

          final HttpResponse response = this.client.execute(post, host, conn);
          final HttpEntity incoming = response.getEntity();
          Assert.assertNotNull(incoming);
          final InputStream instream = incoming.getContent();
          final ContentType contentType = ContentType.getOrDefault(incoming);
          Charset charset = contentType.getCharset();
          if (charset == null) {
            charset = HTTP.DEF_CONTENT_CHARSET;
          }
          Assert.assertNotNull(instream);
          final BufferedReader reader =
              new BufferedReader(new InputStreamReader(instream, charset));

          String line;
          int count = 0;
          while ((line = reader.readLine()) != null) {
            Assert.assertEquals(pattern, line);
            count++;
          }
          Assert.assertEquals(n, count);
          if (!this.client.keepAlive(response)) {
            conn.close();
          }
        }
      }
    } finally {
      conn.close();
      this.server.shutdown();
    }
  }
  /**
   * This test case executes a series of simple POST requests that do not meet the target server
   * expectations.
   */
  @Test
  public void testHttpPostsWithExpectationVerification() throws Exception {

    final int reqNo = 3;

    // Initialize the server-side request handler
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {

            final StringEntity outgoing = new StringEntity("No content");
            response.setEntity(outgoing);
          }
        });

    this.server.setExpectationVerifier(
        new HttpExpectationVerifier() {

          public void verify(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException {
            final Header someheader = request.getFirstHeader("Secret");
            if (someheader != null) {
              int secretNumber;
              try {
                secretNumber = Integer.parseInt(someheader.getValue());
              } catch (final NumberFormatException ex) {
                response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
                return;
              }
              if (secretNumber < 2) {
                response.setStatusCode(HttpStatus.SC_EXPECTATION_FAILED);
                final ByteArrayEntity outgoing =
                    new ByteArrayEntity(EncodingUtils.getAsciiBytes("Wrong secret number"));
                response.setEntity(outgoing);
              }
            }
          }
        });

    this.server.start();

    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      for (int r = 0; r < reqNo; r++) {
        if (!conn.isOpen()) {
          client.connect(host, conn);
        }

        final BasicHttpEntityEnclosingRequest post =
            new BasicHttpEntityEnclosingRequest("POST", "/");
        post.addHeader("Secret", Integer.toString(r));
        final ByteArrayEntity outgoing =
            new ByteArrayEntity(EncodingUtils.getAsciiBytes("No content " + r));
        post.setEntity(outgoing);

        final HttpResponse response = this.client.execute(post, host, conn);

        final HttpEntity entity = response.getEntity();
        Assert.assertNotNull(entity);
        EntityUtils.consume(entity);

        if (r < 2) {
          Assert.assertEquals(
              HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode());
        } else {
          Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
        }

        if (!this.client.keepAlive(response)) {
          conn.close();
        }
      }
      // Verify the connection metrics
      final HttpConnectionMetrics cm = conn.getMetrics();
      Assert.assertEquals(reqNo, cm.getRequestCount());
      Assert.assertEquals(reqNo, cm.getResponseCount());
    } finally {
      conn.close();
      this.server.shutdown();
    }
  }
  /**
   * This test case executes a series of simple POST requests using the 'expect: continue'
   * handshake.
   */
  @Test
  public void testHttpPostsWithExpectContinue() throws Exception {

    final int reqNo = 20;

    final Random rnd = new Random();

    // Prepare some random data
    final List<byte[]> testData = new ArrayList<byte[]>(reqNo);
    for (int i = 0; i < reqNo; i++) {
      final int size = rnd.nextInt(5000);
      final byte[] data = new byte[size];
      rnd.nextBytes(data);
      testData.add(data);
    }

    // Initialize the server-side request handler
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {

            if (request instanceof HttpEntityEnclosingRequest) {
              final HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
              final byte[] data = EntityUtils.toByteArray(incoming);

              final ByteArrayEntity outgoing = new ByteArrayEntity(data);
              outgoing.setChunked(true);
              response.setEntity(outgoing);
            } else {
              final StringEntity outgoing = new StringEntity("No content");
              response.setEntity(outgoing);
            }
          }
        });

    this.server.start();

    // Activate 'expect: continue' handshake
    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      for (int r = 0; r < reqNo; r++) {
        if (!conn.isOpen()) {
          client.connect(host, conn);
        }

        final BasicHttpEntityEnclosingRequest post =
            new BasicHttpEntityEnclosingRequest("POST", "/");
        final byte[] data = testData.get(r);
        final ByteArrayEntity outgoing = new ByteArrayEntity(data);
        outgoing.setChunked(true);
        post.setEntity(outgoing);

        final HttpResponse response = this.client.execute(post, host, conn);
        final byte[] received = EntityUtils.toByteArray(response.getEntity());
        final byte[] expected = testData.get(r);

        Assert.assertEquals(expected.length, received.length);
        for (int i = 0; i < expected.length; i++) {
          Assert.assertEquals(expected[i], received[i]);
        }
        if (!this.client.keepAlive(response)) {
          conn.close();
        }
      }

      // Verify the connection metrics
      final HttpConnectionMetrics cm = conn.getMetrics();
      Assert.assertEquals(reqNo, cm.getRequestCount());
      Assert.assertEquals(reqNo, cm.getResponseCount());
    } finally {
      conn.close();
      this.server.shutdown();
    }
  }
  /** This test case executes a series of simple GET requests */
  @Test
  public void testSimpleBasicHttpRequests() throws Exception {

    final int reqNo = 20;

    final Random rnd = new Random();

    // Prepare some random data
    final List<byte[]> testData = new ArrayList<byte[]>(reqNo);
    for (int i = 0; i < reqNo; i++) {
      final int size = rnd.nextInt(5000);
      final byte[] data = new byte[size];
      rnd.nextBytes(data);
      testData.add(data);
    }

    // Initialize the server-side request handler
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {

            String s = request.getRequestLine().getUri();
            if (s.startsWith("/?")) {
              s = s.substring(2);
            }
            final int index = Integer.parseInt(s);
            final byte[] data = testData.get(index);
            final ByteArrayEntity entity = new ByteArrayEntity(data);
            response.setEntity(entity);
          }
        });

    this.server.start();

    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      for (int r = 0; r < reqNo; r++) {
        if (!conn.isOpen()) {
          client.connect(host, conn);
        }

        final BasicHttpRequest get = new BasicHttpRequest("GET", "/?" + r);
        final HttpResponse response = this.client.execute(get, host, conn);
        final byte[] received = EntityUtils.toByteArray(response.getEntity());
        final byte[] expected = testData.get(r);

        Assert.assertEquals(expected.length, received.length);
        for (int i = 0; i < expected.length; i++) {
          Assert.assertEquals(expected[i], received[i]);
        }
        if (!this.client.keepAlive(response)) {
          conn.close();
        }
      }

      // Verify the connection metrics
      final HttpConnectionMetrics cm = conn.getMetrics();
      Assert.assertEquals(reqNo, cm.getRequestCount());
      Assert.assertEquals(reqNo, cm.getResponseCount());

    } finally {
      conn.close();
      this.server.shutdown();
    }
  }