diff --git a/src/test/java/org/opensearch/security/InitializationIntegrationTests.java b/src/test/java/org/opensearch/security/InitializationIntegrationTests.java index ef8ef9bf86..17ced9e325 100644 --- a/src/test/java/org/opensearch/security/InitializationIntegrationTests.java +++ b/src/test/java/org/opensearch/security/InitializationIntegrationTests.java @@ -33,6 +33,8 @@ import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.HttpVersion; +import org.apache.hc.core5.http2.HttpVersionPolicy; import org.junit.Assert; import org.junit.Test; @@ -120,6 +122,8 @@ public void testWhoAmI() throws Exception { try (RestHighLevelClient restHighLevelClient = getRestClient(clusterInfo, "spock-keystore.jks", "truststore.jks")) { Response whoAmIRes = restHighLevelClient.getLowLevelClient().performRequest(new Request("GET", "/_plugins/_security/whoami")); Assert.assertEquals(whoAmIRes.getStatusLine().getStatusCode(), 200); + // Should be using HTTP/2 by default + Assert.assertEquals(whoAmIRes.getStatusLine().getProtocolVersion(), HttpVersion.HTTP_2); JsonNode whoAmIResNode = DefaultObjectMapper.objectMapper.readTree(whoAmIRes.getEntity().getContent()); String whoAmIResponsePayload = whoAmIResNode.toPrettyString(); Assert.assertEquals(whoAmIResponsePayload, "CN=spock,OU=client,O=client,L=Test,C=DE", whoAmIResNode.get("dn").asText()); @@ -127,7 +131,30 @@ public void testWhoAmI() throws Exception { Assert.assertFalse(whoAmIResponsePayload, whoAmIResNode.get("is_node_certificate_request").asBoolean()); } } - + + @Test + public void testWhoAmIForceHttp1() throws Exception { + final Settings settings = Settings.builder() + .put("plugins.security.ssl.http.enabled",true) + .put("plugins.security.ssl.http.keystore_filepath", FileHelper.getAbsoluteFilePathFromClassPath("node-0-keystore.jks")) + .put("plugins.security.ssl.http.truststore_filepath", FileHelper.getAbsoluteFilePathFromClassPath("truststore.jks")) + .build(); + setup(Settings.EMPTY, new DynamicSecurityConfig().setSecurityInternalUsers("internal_empty.yml") + .setSecurityRoles("roles_deny.yml"), settings, true); + + try (RestHighLevelClient restHighLevelClient = getRestClient(clusterInfo, "spock-keystore.jks", "truststore.jks", HttpVersionPolicy.FORCE_HTTP_1)) { + Response whoAmIRes = restHighLevelClient.getLowLevelClient().performRequest(new Request("GET", "/_plugins/_security/whoami")); + Assert.assertEquals(whoAmIRes.getStatusLine().getStatusCode(), 200); + // The HTTP/1.1 is forced and should be used instead + Assert.assertEquals(whoAmIRes.getStatusLine().getProtocolVersion(), HttpVersion.HTTP_1_1); + JsonNode whoAmIResNode = DefaultObjectMapper.objectMapper.readTree(whoAmIRes.getEntity().getContent()); + String whoAmIResponsePayload = whoAmIResNode.toPrettyString(); + Assert.assertEquals(whoAmIResponsePayload, "CN=spock,OU=client,O=client,L=Test,C=DE", whoAmIResNode.get("dn").asText()); + Assert.assertFalse(whoAmIResponsePayload, whoAmIResNode.get("is_admin").asBoolean()); + Assert.assertFalse(whoAmIResponsePayload, whoAmIResNode.get("is_node_certificate_request").asBoolean()); + } + } + @Test public void testConfigHotReload() throws Exception { @@ -234,5 +261,4 @@ public void testDiscoveryWithoutInitialization() throws Exception { Assert.assertEquals(clusterInfo.numNodes, clusterHelper.nodeClient().admin().cluster().health(new ClusterHealthRequest().waitForGreenStatus()).actionGet().getNumberOfNodes()); Assert.assertEquals(ClusterHealthStatus.GREEN, clusterHelper.nodeClient().admin().cluster().health(new ClusterHealthRequest().waitForGreenStatus()).actionGet().getStatus()); } - } diff --git a/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java index 30e3e53436..1a99e8cdb0 100644 --- a/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/integration/BasicAuditlogTest.java @@ -133,7 +133,7 @@ public void testSSLPlainText() throws Exception { final RuntimeException ex = Assert.assertThrows(RuntimeException.class, () -> nonSslRestHelper().executeGetRequest("_search", encodeBasicHeader("admin", "admin"))); Assert.assertEquals("org.apache.hc.core5.http.NoHttpResponseException", ex.getCause().getClass().getName()); - }, 2); + }, 1); /* no retry on NotSslRecordException exceptions */ // All of the messages should be the same as the http client is attempting multiple times. messages.stream().forEach((message) -> { diff --git a/src/test/java/org/opensearch/security/dlic/dlsfls/DlsFlsCrossClusterSearchTest.java b/src/test/java/org/opensearch/security/dlic/dlsfls/DlsFlsCrossClusterSearchTest.java index 4e8351d7b3..8fcd85f873 100644 --- a/src/test/java/org/opensearch/security/dlic/dlsfls/DlsFlsCrossClusterSearchTest.java +++ b/src/test/java/org/opensearch/security/dlic/dlsfls/DlsFlsCrossClusterSearchTest.java @@ -125,7 +125,8 @@ public void testCcs() throws Exception { Assert.assertTrue(ccs.getBody().contains("salary1")); Assert.assertFalse(ccs.getBody().contains("secret1")); Assert.assertFalse(ccs.getBody().contains("AnotherSecredField")); - Assert.assertFalse(ccs.getBody().contains("xxx1")); Assert.assertEquals(ccs.getHeaders().toString(), 1, ccs.getHeaders().size()); + Assert.assertFalse(ccs.getBody().contains("xxx1")); + Assert.assertEquals(ccs.getHeaders().toString(), 2, ccs.getHeaders().size()); } @Test @@ -183,7 +184,7 @@ public void testCcsDifferentConfig() throws Exception { Assert.assertTrue(ccs.getBody().contains("__fn__crl2")); Assert.assertFalse(ccs.getBody().contains("secret1")); Assert.assertFalse(ccs.getBody().contains("AnotherSecredField")); - Assert.assertEquals(ccs.getHeaders().toString(), 1, ccs.getHeaders().size()); + Assert.assertEquals(ccs.getHeaders().toString(), 2, ccs.getHeaders().size()); } @Test @@ -265,6 +266,6 @@ public void testCcsDifferentConfigBoth() throws Exception { Assert.assertFalse(ccs.getBody().contains("secret1")); Assert.assertFalse(ccs.getBody().contains("AnotherSecredField")); Assert.assertTrue(ccs.getBody().contains("someoneelse")); - Assert.assertEquals(ccs.getHeaders().toString(), 1, ccs.getHeaders().size()); + Assert.assertEquals(ccs.getHeaders().toString(), 2, ccs.getHeaders().size()); } } diff --git a/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java b/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java index 18bbef8fef..554500257b 100644 --- a/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java +++ b/src/test/java/org/opensearch/security/dlic/dlsfls/DlsTest.java @@ -100,7 +100,7 @@ public void testDls() throws Exception { Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executeGetRequest("/deals/_search?pretty", encodeBasicHeader("dept_manager", "password"))).getStatusCode()); Assert.assertTrue(res.getBody().contains("\"value\" : 1,\n \"relation")); Assert.assertTrue(res.getBody().contains("\"failed\" : 0")); - Assert.assertEquals(res.getHeaders().toString(), 1, res.getHeaders().size()); + Assert.assertEquals(res.getHeaders().toString(), 2, res.getHeaders().size()); Assert.assertEquals(HttpStatus.SC_OK, (res = rh.executeGetRequest("/deals/_search?pretty", encodeBasicHeader("admin", "admin"))).getStatusCode()); Assert.assertTrue(res.getBody().contains("\"value\" : 2,\n \"relation")); diff --git a/src/test/java/org/opensearch/security/sanity/tests/SecurityRestTestCase.java b/src/test/java/org/opensearch/security/sanity/tests/SecurityRestTestCase.java index 258c18b384..51c4ddb984 100644 --- a/src/test/java/org/opensearch/security/sanity/tests/SecurityRestTestCase.java +++ b/src/test/java/org/opensearch/security/sanity/tests/SecurityRestTestCase.java @@ -77,14 +77,20 @@ protected RestClient buildClient(Settings settings, HttpHost[] hosts) throws IOE // create adminDN (super-admin) client File file = new File(getClass().getClassLoader().getResource(CERT_FILE_DIRECTORY).getFile()); Path configPath = PathUtils.get(file.toURI()).getParent().toAbsolutePath(); - return new SecureRestClientBuilder(settings, configPath).setSocketTimeout(60000).build(); + return new SecureRestClientBuilder(settings, configPath) + .setSocketTimeout(60000) + .setConnectionRequestTimeout(180000) + .build(); } // create client with passed user String userName = System.getProperty("user"); String password = System.getProperty("password"); - return new SecureRestClientBuilder(hosts, isHttps(), userName, password).setSocketTimeout(60000).build(); + return new SecureRestClientBuilder(hosts, isHttps(), userName, password) + .setSocketTimeout(60000) + .setConnectionRequestTimeout(180000) + .build(); } else { RestClientBuilder builder = RestClient.builder(hosts); diff --git a/src/test/java/org/opensearch/security/test/AbstractSecurityUnitTest.java b/src/test/java/org/opensearch/security/test/AbstractSecurityUnitTest.java index 592433d5e9..72b05abb91 100644 --- a/src/test/java/org/opensearch/security/test/AbstractSecurityUnitTest.java +++ b/src/test/java/org/opensearch/security/test/AbstractSecurityUnitTest.java @@ -55,6 +55,7 @@ import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.http2.HttpVersionPolicy; import org.apache.hc.core5.reactor.ssl.TlsDetails; import org.apache.hc.core5.ssl.SSLContextBuilder; import org.apache.hc.core5.ssl.SSLContexts; @@ -144,6 +145,10 @@ public static Header encodeBasicHeader(final String username, final String passw } protected RestHighLevelClient getRestClient(ClusterInfo info, String keyStoreName, String trustStoreName) { + return getRestClient(info, keyStoreName, trustStoreName, null); + } + + protected RestHighLevelClient getRestClient(ClusterInfo info, String keyStoreName, String trustStoreName, HttpVersionPolicy httpVersionPolicy) { final String prefix = getResourceFolder()==null?"":getResourceFolder()+"/"; try { @@ -183,6 +188,9 @@ public TlsDetails create(final SSLEngine sslEngine) { .setTlsStrategy(tlsStrategy) .build(); builder.setConnectionManager(cm); + if (httpVersionPolicy != null) { + builder.setVersionPolicy(httpVersionPolicy); + } return builder; }); return new RestHighLevelClient(restClientBuilder); diff --git a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java index 30b549dfa1..ff9a5b536b 100644 --- a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java +++ b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java @@ -28,24 +28,27 @@ import java.io.FileInputStream; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Scanner; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import com.fasterxml.jackson.databind.JsonNode; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.auth.AuthScope; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.classic.methods.HttpDelete; @@ -56,22 +59,32 @@ import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.classic.methods.HttpPut; import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; -import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.client5.http.nio.AsyncClientConnectionManager; +import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.concurrent.FutureCallback; +import org.apache.hc.core5.function.Factory; +import org.apache.hc.core5.http.ConnectionClosedException; +import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.HttpHeaders; -import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.http.HttpVersion; +import org.apache.hc.core5.http.NoHttpResponseException; +import org.apache.hc.core5.http.ProtocolVersion; +import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.reactor.ssl.TlsDetails; import org.apache.hc.core5.ssl.SSLContextBuilder; import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.util.Timeout; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -108,24 +121,50 @@ public RestHelper(ClusterInfo clusterInfo, boolean enableHTTPClientSSL, boolean } public String executeSimpleRequest(final String request) throws Exception { - CloseableHttpClient httpClient = null; - CloseableHttpResponse response = null; + CloseableHttpAsyncClient httpClient = null; try { httpClient = getHTTPClient(); - response = httpClient.execute(new HttpGet(getRequestUri(request))); + httpClient.start(); + + final CompletableFuture future = new CompletableFuture<>(); + final SimpleHttpRequest simpleRequest = SimpleRequestBuilder.copy(new HttpGet(getRequestUri(request))).build(); + httpClient.execute(simpleRequest, new FutureCallback() { + @Override + public void completed(SimpleHttpResponse result) { + future.complete(result); + } + + @Override + public void failed(Exception ex) { + future.completeExceptionally(ex); + } + + @Override + public void cancelled() { + future.cancel(true); + } + }); + final SimpleHttpResponse response = future.join(); if (response.getCode() >= 300) { throw new Exception("Statuscode " + response.getCode()); } - return IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); - } finally { - - if (response != null) { - response.close(); + if (enableHTTPClientSSL && !response.getVersion().equals(HttpVersion.HTTP_2)) { + throw new IllegalStateException("HTTP/2 expected for HTTPS communication but " + response.getVersion() + " was used"); } + return response.getBodyText(); + } catch (final CompletionException e) { + final Throwable cause = e.getCause(); + // Make it compatible with DefaultHttpResponseParser::createConnectionClosedException() + if (cause instanceof ConnectionClosedException) { + throw new NoHttpResponseException(cause.getMessage(), cause); + } else { + throw (Exception)cause; + } + } finally { if (httpClient != null) { httpClient.close(); } @@ -145,7 +184,7 @@ public HttpResponse[] executeMultipleAsyncPutRequest(final int numOfRequests, fi } public HttpResponse executeGetRequest(final String request, Header... header) { - return executeRequest(new HttpGet(getRequestUri(request)), header); + return executeRequest(new HttpGet(getRequestUri(request)), header); } public HttpResponse executeGetRequest(final String request, String body, Header... header) { @@ -156,12 +195,12 @@ public HttpResponse executeGetRequest(final String request, String body, Header. } public HttpResponse executeHeadRequest(final String request, Header... header) { - return executeRequest(new HttpHead(getRequestUri(request)), header); - } + return executeRequest(new HttpHead(getRequestUri(request)), header); + } public HttpResponse executeOptionsRequest(final String request) { - return executeRequest(new HttpOptions(getRequestUri(request))); - } + return executeRequest(new HttpOptions(getRequestUri(request))); + } public HttpResponse executePutRequest(final String request, String body, Header... header) { HttpPut uriRequest = new HttpPut(getRequestUri(request)); @@ -192,20 +231,21 @@ public HttpResponse executePostRequest(final String request, String body, Header return executeRequest(uriRequest, header); } - public HttpResponse executePatchRequest(final String request, String body, Header... header) { - HttpPatch uriRequest = new HttpPatch(getRequestUri(request)); - if (body != null && !body.isEmpty()) { - uriRequest.setEntity(createStringEntity(body)); - } - return executeRequest(uriRequest, header); - } + public HttpResponse executePatchRequest(final String request, String body, Header... header) { + HttpPatch uriRequest = new HttpPatch(getRequestUri(request)); + if (body != null && !body.isEmpty()) { + uriRequest.setEntity(createStringEntity(body)); + } + return executeRequest(uriRequest, header); + } public HttpResponse executeRequest(HttpUriRequest uriRequest, Header... header) { - CloseableHttpClient httpClient = null; + CloseableHttpAsyncClient httpClient = null; try { httpClient = getHTTPClient(); + httpClient.start(); if (header != null && header.length > 0) { for (int i = 0; i < header.length; i++) { @@ -215,11 +255,49 @@ public HttpResponse executeRequest(HttpUriRequest uriRequest, Header... header) } if (!uriRequest.containsHeader("Content-Type")) { - uriRequest.addHeader("Content-Type","application/json"); + uriRequest.addHeader("Content-Type","application/json"); + } + + final CompletableFuture future = new CompletableFuture<>(); + final SimpleHttpRequest simpleRequest = SimpleRequestBuilder.copy(uriRequest).build(); + if (uriRequest.getEntity() != null) { + simpleRequest.setBody(EntityUtils.toByteArray(uriRequest.getEntity()), + ContentType.parse(uriRequest.getEntity().getContentType())); } - HttpResponse res = new HttpResponse(httpClient.execute(uriRequest)); + httpClient.execute(simpleRequest, new FutureCallback() { + @Override + public void completed(SimpleHttpResponse result) { + future.complete(result); + } + + @Override + public void failed(Exception ex) { + future.completeExceptionally(ex); + } + + @Override + public void cancelled() { + future.cancel(true); + } + }); + + final HttpResponse res = new HttpResponse(future.join()); + if (enableHTTPClientSSL && !res.getProtocolVersion().equals(HttpVersion.HTTP_2)) { + throw new IllegalStateException("HTTP/2 expected for HTTPS communication but " + res.getProtocolVersion() + " was used"); + } + log.debug(res.getBody()); return res; + } catch (final CompletionException e) { + final Throwable cause = e.getCause(); + // Make it compatible with DefaultHttpResponseParser::createConnectionClosedException() + if (cause instanceof ConnectionClosedException) { + throw new RuntimeException(new NoHttpResponseException(cause.getMessage(), cause)); + } else if (cause instanceof RuntimeException) { + throw (RuntimeException)cause; + } else { + throw new RuntimeException(cause); + } } catch (final Exception e) { throw new RuntimeException(e); } finally { @@ -248,9 +326,9 @@ protected final String getRequestUri(String request) { return getHttpServerUri() + "/" + StringUtils.strip(request, "/"); } - protected final CloseableHttpClient getHTTPClient() throws Exception { + protected final CloseableHttpAsyncClient getHTTPClient() throws Exception { - final HttpClientBuilder hcb = HttpClients.custom(); + final HttpAsyncClientBuilder hcb = HttpAsyncClients.custom(); if (sendHTTPClientCredentials) { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("sarek", "sarek".toCharArray()); @@ -264,11 +342,11 @@ protected final CloseableHttpClient getHTTPClient() throws Exception { log.debug("Configure HTTP client with SSL"); if(prefix != null && !keystore.contains("/")) { - keystore = prefix+"/"+keystore; + keystore = prefix+"/"+keystore; } - final String keyStorePath = FileHelper.getAbsoluteFilePathFromClassPath(keystore).toFile().getParent(); - + final String keyStorePath = FileHelper.getAbsoluteFilePathFromClassPath(keystore).toFile().getParent(); + final KeyStore myTrustStore = KeyStore.getInstance("JKS"); myTrustStore.load(new FileInputStream(keyStorePath+"/truststore.jks"), "changeit".toCharArray()); @@ -296,40 +374,54 @@ protected final CloseableHttpClient getHTTPClient() throws Exception { protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" }; } - final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, protocols, null, - NoopHostnameVerifier.INSTANCE); + final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder + .create() + .setSslContext(sslContext) + .setTlsVersions(protocols) + .setHostnameVerifier(NoopHostnameVerifier.INSTANCE) + // See please https://issues.apache.org/jira/browse/HTTPCLIENT-2219 + .setTlsDetailsFactory(new Factory() { + @Override + public TlsDetails create(final SSLEngine sslEngine) { + return new TlsDetails(sslEngine.getSession(), sslEngine.getApplicationProtocol()); + } + }) + .build(); - final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() - .setSSLSocketFactory(sslsf) - .setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(60, TimeUnit.SECONDS).build()) + final AsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create() + .setTlsStrategy(tlsStrategy) .build(); + hcb.setConnectionManager(cm); } - return hcb.build(); + final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom() + .setResponseTimeout(Timeout.ofSeconds(60)); + + return hcb.setDefaultRequestConfig(requestConfigBuilder.build()).disableAutomaticRetries().build(); } public static class HttpResponse { - private final CloseableHttpResponse inner; + private final SimpleHttpResponse inner; private final String body; private final Header[] header; private final int statusCode; private final String statusReason; + private final ProtocolVersion protocolVersion; - public HttpResponse(CloseableHttpResponse inner) throws IllegalStateException, IOException { + public HttpResponse(SimpleHttpResponse inner) throws IllegalStateException, IOException { super(); this.inner = inner; - final HttpEntity entity = inner.getEntity(); - if(entity == null) { //head request does not have a entity - this.body = ""; + if(inner.getBody() == null) { //head request does not have a entity + this.body = ""; } else { - this.body = IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8); + this.body = inner.getBodyText(); } this.header = inner.getHeaders(); this.statusCode = inner.getCode(); this.statusReason = inner.getReasonPhrase(); - inner.close(); + this.protocolVersion = inner.getVersion(); } public String getContentType() { @@ -348,7 +440,7 @@ public boolean isJsonContentType() { return ct.contains("application/json"); } - public CloseableHttpResponse getInner() { + public SimpleHttpResponse getInner() { return inner; } @@ -372,20 +464,14 @@ public List
getHeaders() { return header==null?Collections.emptyList():Arrays.asList(header); } - @Override - public String toString() { - return "HttpResponse [inner=" + inner + ", body=" + body + ", header=" + Arrays.toString(header) + ", statusCode=" + statusCode - + ", statusReason=" + statusReason + "]"; - } - - private static void findArrayAccessor(String input) { - final Pattern r = Pattern.compile("(.+?)\\[(\\d+)\\]"); - final Matcher m = r.matcher(input); - if(m.find()) { - System.out.println("'" + input + "'\t Name was: " + m.group(1) + ",\t index position: " + m.group(2)); - } else { - System.out.println("'" + input + "'\t No Match"); - } + public ProtocolVersion getProtocolVersion() { + return protocolVersion; + } + + @Override + public String toString() { + return "HttpResponse [inner=" + inner + ", body=" + body + ", header=" + Arrays.toString(header) + ", statusCode=" + statusCode + + ", statusReason=" + statusReason + "]"; } /**