@Test
  public void testRequestFilterCanModifyHttpsRequestBody() throws IOException {
    final String originalText = "original body";
    final String newText = "modified body";

    mockServer
        .when(
            request().withMethod("PUT").withPath("/modifyrequest").withBody(newText),
            Times.exactly(1))
        .respond(response().withStatusCode(200).withBody("success"));

    proxy = new BrowserMobProxyServer();
    proxy.setTrustAllServers(true);
    proxy.start();

    proxy.addRequestFilter(
        new RequestFilter() {
          @Override
          public HttpResponse filterRequest(
              HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
            if (contents.isText()) {
              if (contents.getTextContents().equals(originalText)) {
                contents.setTextContents(newText);
              }
            }

            return null;
          }
        });

    try (CloseableHttpClient httpClient =
        NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
      HttpPut request = new HttpPut("https://localhost:" + mockServerPort + "/modifyrequest");
      request.setEntity(new StringEntity(originalText));
      CloseableHttpResponse response = httpClient.execute(request);
      String responseBody =
          NewProxyServerTestUtil.toStringAndClose(response.getEntity().getContent());

      assertEquals(
          "Expected server to return a 200", 200, response.getStatusLine().getStatusCode());
      assertEquals("Did not receive expected response from mock server", "success", responseBody);
    }
  }
  @Test
  public void testResponseFilterCanModifyHttpsTextContents() throws IOException {
    final String originalText = "The quick brown fox jumps over the lazy dog";
    final String newText = "The quick brown fox jumped.";

    mockServer
        .when(request().withMethod("GET").withPath("/modifyresponse"), Times.exactly(1))
        .respond(
            response()
                .withStatusCode(200)
                .withHeader(new Header(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=utf-8"))
                .withBody(originalText));

    proxy = new BrowserMobProxyServer();
    proxy.setTrustAllServers(true);
    proxy.start();

    proxy.addResponseFilter(
        new ResponseFilter() {
          @Override
          public void filterResponse(
              HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
            if (contents.isText()) {
              if (contents.getTextContents().equals(originalText)) {
                contents.setTextContents(newText);
              }
            }
          }
        });

    try (CloseableHttpClient httpClient =
        NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
      HttpGet request = new HttpGet("https://localhost:" + mockServerPort + "/modifyresponse");
      request.addHeader("Accept-Encoding", "gzip");
      CloseableHttpResponse response = httpClient.execute(request);
      String responseBody =
          NewProxyServerTestUtil.toStringAndClose(response.getEntity().getContent());

      assertEquals(
          "Expected server to return a 200", 200, response.getStatusLine().getStatusCode());
      assertEquals("Did not receive expected response from mock server", newText, responseBody);
    }
  }
  @Test
  public void testHttpsResponseFilterUrlReflectsModifications() throws IOException {
    mockServer
        .when(request().withMethod("GET").withPath("/urlreflectsmodifications"), Times.exactly(1))
        .respond(response().withStatusCode(200).withBody("success"));

    proxy = new BrowserMobProxyServer();
    proxy.setTrustAllServers(true);
    proxy.start();

    final AtomicReference<String> requestFilterOriginalUrl = new AtomicReference<>();
    final AtomicReference<String> requestFilterUrl = new AtomicReference<>();

    proxy.addRequestFilter(
        new RequestFilter() {
          @Override
          public HttpResponse filterRequest(
              HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
            requestFilterOriginalUrl.set(messageInfo.getOriginalUrl());
            requestFilterUrl.set(messageInfo.getUrl());
            return null;
          }
        });

    // request filters get added to the beginning of the filter chain, so add this uri-modifying
    // request filter after
    // adding the capturing request filter above.
    proxy.addRequestFilter(
        new RequestFilter() {
          @Override
          public HttpResponse filterRequest(
              HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
            if (request.getUri().endsWith("/originalurl")) {
              String newUrl =
                  request.getUri().replaceAll("originalurl", "urlreflectsmodifications");
              request.setUri(newUrl);
            }
            return null;
          }
        });

    final AtomicReference<String> responseFilterOriginalUrl = new AtomicReference<>();
    final AtomicReference<String> responseFilterUrl = new AtomicReference<>();

    proxy.addResponseFilter(
        new ResponseFilter() {
          @Override
          public void filterResponse(
              HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
            responseFilterOriginalUrl.set(messageInfo.getOriginalUrl());
            responseFilterUrl.set(messageInfo.getUrl());
          }
        });

    try (CloseableHttpClient httpClient =
        NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
      String originalRequestUrl = "https://localhost:" + mockServerPort + "/originalurl";
      String modifiedRequestUrl =
          "https://localhost:" + mockServerPort + "/urlreflectsmodifications";
      CloseableHttpResponse response = httpClient.execute(new HttpGet(originalRequestUrl));

      assertEquals(
          "Expected server to return a 200", 200, response.getStatusLine().getStatusCode());
      assertEquals(
          "Expected originalUrl in request filter to match actual request URL",
          originalRequestUrl,
          requestFilterOriginalUrl.get());
      assertEquals(
          "Expected url in request filter to match modified request URL",
          modifiedRequestUrl,
          requestFilterUrl.get());

      assertEquals(
          "Expected originalUrl in response filter to match actual request URL",
          originalRequestUrl,
          responseFilterOriginalUrl.get());
      assertEquals(
          "Expected url in response filter to match modified request URL",
          modifiedRequestUrl,
          responseFilterUrl.get());
    }
  }
  @Test
  public void testHttpsResponseFilterMessageInfoPopulated() throws IOException {
    mockServer
        .when(
            request()
                .withMethod("GET")
                .withPath("/httpmessageinfopopulated")
                .withQueryStringParameter("param1", "value1"),
            Times.exactly(1))
        .respond(response().withStatusCode(200).withBody("success"));

    proxy = new BrowserMobProxyServer();
    proxy.setTrustAllServers(true);
    proxy.start();

    final AtomicReference<ChannelHandlerContext> requestCtx = new AtomicReference<>();
    final AtomicReference<HttpRequest> requestOriginalRequest = new AtomicReference<>();
    final AtomicBoolean requestIsHttps = new AtomicBoolean(false);
    final AtomicReference<String> requestOriginalUrl = new AtomicReference<>();

    proxy.addRequestFilter(
        new RequestFilter() {
          @Override
          public HttpResponse filterRequest(
              HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
            requestCtx.set(messageInfo.getChannelHandlerContext());
            requestOriginalRequest.set(messageInfo.getOriginalRequest());
            requestIsHttps.set(messageInfo.isHttps());
            requestOriginalUrl.set(messageInfo.getOriginalUrl());
            return null;
          }
        });

    final AtomicReference<ChannelHandlerContext> responseCtx = new AtomicReference<>();
    final AtomicReference<HttpRequest> responseOriginalRequest = new AtomicReference<>();
    final AtomicBoolean responseIsHttps = new AtomicBoolean(false);
    final AtomicReference<String> responseOriginalUrl = new AtomicReference<>();

    proxy.addResponseFilter(
        new ResponseFilter() {
          @Override
          public void filterResponse(
              HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
            responseCtx.set(messageInfo.getChannelHandlerContext());
            responseOriginalRequest.set(messageInfo.getOriginalRequest());
            responseIsHttps.set(messageInfo.isHttps());
            responseOriginalUrl.set(messageInfo.getOriginalUrl());
          }
        });

    try (CloseableHttpClient httpClient =
        NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
      String requestUrl =
          "https://localhost:" + mockServerPort + "/httpmessageinfopopulated?param1=value1";
      CloseableHttpResponse response = httpClient.execute(new HttpGet(requestUrl));

      assertEquals(
          "Expected server to return a 200", 200, response.getStatusLine().getStatusCode());

      assertNotNull(
          "Expected ChannelHandlerContext to be populated in request filter", requestCtx.get());
      assertNotNull(
          "Expected originalRequest to be populated in request filter",
          requestOriginalRequest.get());
      assertTrue("Expected isHttps to return true in request filter", requestIsHttps.get());
      assertEquals(
          "Expected originalUrl in request filter to match actual request URL",
          requestUrl,
          requestOriginalUrl.get());

      assertNotNull(
          "Expected ChannelHandlerContext to be populated in response filter", responseCtx.get());
      assertNotNull(
          "Expected originalRequest to be populated in response filter",
          responseOriginalRequest.get());
      assertTrue("Expected isHttps to return true in response filter", responseIsHttps.get());
      assertEquals(
          "Expected originalUrl in response filter to match actual request URL",
          requestUrl,
          responseOriginalUrl.get());
    }
  }