/* * Copyright (C) 2014 Square, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package okhttp3.internal.huc; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.CacheResponse; import java.net.HttpURLConnection; import java.net.SecureCacheResponse; import java.net.URI; import java.nio.charset.StandardCharsets; import java.security.Principal; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLPeerUnverifiedException; import okhttp3.CipherSuite; import okhttp3.Handshake; import okhttp3.Headers; import okhttp3.MediaType; import okhttp3.Protocol; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; import okhttp3.internal.Internal; import okhttp3.internal.Util; import okhttp3.mockwebserver.MockWebServer; import okio.Buffer; import okio.BufferedSource; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class JavaApiConverterTest { // $ openssl req -x509 -nodes -days 36500 -subj '/CN=localhost' -config ./cert.cnf \ // -newkey rsa:512 -out cert.pem private static final X509Certificate LOCAL_CERT = certificate("" + "-----BEGIN CERTIFICATE-----\n" + "MIIBWDCCAQKgAwIBAgIJANS1EtICX2AZMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV\n" + "BAMTCWxvY2FsaG9zdDAgFw0xMjAxMDIxOTA4NThaGA8yMTExMTIwOTE5MDg1OFow\n" + "FDESMBAGA1UEAxMJbG9jYWxob3N0MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPpt\n" + "atK8r4/hf4hSIs0os/BSlQLbRBaK9AfBReM4QdAklcQqe6CHsStKfI8pp0zs7Ptg\n" + "PmMdpbttL0O7mUboBC8CAwEAAaM1MDMwMQYDVR0RBCowKIIVbG9jYWxob3N0Lmxv\n" + "Y2FsZG9tYWlugglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQEFBQADQQD0ntfL\n" + "DCzOCv9Ma6Lv5o5jcYWVxvBSTsnt22hsJpWD1K7iY9lbkLwl0ivn73pG2evsAn9G\n" + "X8YKH52fnHsCrhSD\n" + "-----END CERTIFICATE-----"); // openssl req -x509 -nodes -days 36500 -subj '/CN=*.0.0.1' -newkey rsa:512 -out cert.pem private static final X509Certificate SERVER_CERT = certificate("" + "-----BEGIN CERTIFICATE-----\n" + "MIIBkjCCATygAwIBAgIJAMdemqOwd/BEMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV\n" + "BAMUByouMC4wLjEwIBcNMTAxMjIwMTY0NDI1WhgPMjExMDExMjYxNjQ0MjVaMBIx\n" + "EDAOBgNVBAMUByouMC4wLjEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAqY8c9Qrt\n" + "YPWCvb7lclI+aDHM6fgbJcHsS9Zg8nUOh5dWrS7AgeA25wyaokFl4plBbbHQe2j+\n" + "cCjsRiJIcQo9HwIDAQABo3MwcTAdBgNVHQ4EFgQUJ436TZPJvwCBKklZZqIvt1Yt\n" + "JjEwQgYDVR0jBDswOYAUJ436TZPJvwCBKklZZqIvt1YtJjGhFqQUMBIxEDAOBgNV\n" + "BAMUByouMC4wLjGCCQDHXpqjsHfwRDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB\n" + "BQUAA0EAk9i88xdjWoewqvE+iMC9tD2obMchgFDaHH0ogxxiRaIKeEly3g0uGxIt\n" + "fl2WRY8hb4x+zRrwsFaLEpdEvqcjOQ==\n" + "-----END CERTIFICATE-----"); @Rule public MockWebServer server = new MockWebServer(); @Before public void setUp() throws Exception { Internal.initializeInstanceForTests(); } @Test public void createOkResponseForCacheGet() throws Exception { final String statusLine = "HTTP/1.1 200 Fantastic"; URI uri = new URI("http://foo/bar"); Request request = new Request.Builder().url(uri.toURL()).build(); CacheResponse cacheResponse = new CacheResponse() { @Override public Map> getHeaders() throws IOException { Map> headers = new HashMap<>(); headers.put(null, Collections.singletonList(statusLine)); headers.put("xyzzy", Arrays.asList("bar", "baz")); return headers; } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("HelloWorld".getBytes(StandardCharsets.UTF_8)); } }; Response response = JavaApiConverter.createOkResponseForCacheGet(request, cacheResponse); Request cacheRequest = response.request(); assertEquals(request.url(), cacheRequest.url()); assertEquals(request.method(), cacheRequest.method()); assertEquals(0, request.headers().size()); assertEquals(Protocol.HTTP_1_1, response.protocol()); assertEquals(200, response.code()); assertEquals("Fantastic", response.message()); Headers okResponseHeaders = response.headers(); assertEquals("baz", okResponseHeaders.get("xyzzy")); assertEquals("HelloWorld", response.body().string()); assertNull(response.handshake()); } /** Test for https://code.google.com/p/android/issues/detail?id=160522 */ @Test public void createOkResponseForCacheGet_withMissingStatusLine() throws Exception { URI uri = new URI("http://foo/bar"); Request request = new Request.Builder().url(uri.toURL()).build(); CacheResponse cacheResponse = new CacheResponse() { @Override public Map> getHeaders() throws IOException { Map> headers = new HashMap<>(); // Headers is deliberately missing an entry with a null key. headers.put("xyzzy", Arrays.asList("bar", "baz")); return headers; } @Override public InputStream getBody() throws IOException { return null; // Should never be called } }; try { JavaApiConverter.createOkResponseForCacheGet(request, cacheResponse); fail(); } catch (IOException expected) { } } @Test public void createOkResponseForCacheGet_secure() throws Exception { final String statusLine = "HTTP/1.1 200 Fantastic"; final Principal localPrincipal = LOCAL_CERT.getSubjectX500Principal(); final List localCertificates = Arrays.asList(LOCAL_CERT); final Principal serverPrincipal = SERVER_CERT.getSubjectX500Principal(); final List serverCertificates = Arrays.asList(SERVER_CERT); URI uri = new URI("https://foo/bar"); Request request = new Request.Builder().url(uri.toURL()).build(); SecureCacheResponse cacheResponse = new SecureCacheResponse() { @Override public Map> getHeaders() throws IOException { Map> headers = new HashMap<>(); headers.put(null, Collections.singletonList(statusLine)); headers.put("xyzzy", Arrays.asList("bar", "baz")); return headers; } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("HelloWorld".getBytes(StandardCharsets.UTF_8)); } @Override public String getCipherSuite() { return "SSL_RSA_WITH_NULL_MD5"; } @Override public List getLocalCertificateChain() { return localCertificates; } @Override public List getServerCertificateChain() throws SSLPeerUnverifiedException { return serverCertificates; } @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { return serverPrincipal; } @Override public Principal getLocalPrincipal() { return localPrincipal; } }; Response response = JavaApiConverter.createOkResponseForCacheGet(request, cacheResponse); Request cacheRequest = response.request(); assertEquals(request.url(), cacheRequest.url()); assertEquals(request.method(), cacheRequest.method()); assertEquals(0, request.headers().size()); assertEquals(Protocol.HTTP_1_1, response.protocol()); assertEquals(200, response.code()); assertEquals("Fantastic", response.message()); Headers okResponseHeaders = response.headers(); assertEquals("baz", okResponseHeaders.get("xyzzy")); assertEquals("HelloWorld", response.body().string()); Handshake handshake = response.handshake(); assertNotNull(handshake); assertNotNullAndEquals(CipherSuite.TLS_RSA_WITH_NULL_MD5, handshake.cipherSuite()); assertEquals(localPrincipal, handshake.localPrincipal()); assertEquals(serverPrincipal, handshake.peerPrincipal()); assertEquals(serverCertificates, handshake.peerCertificates()); assertEquals(localCertificates, handshake.localCertificates()); } @Test public void createOkRequest_nullRequestHeaders() throws Exception { URI uri = new URI("http://foo/bar"); Map> javaRequestHeaders = null; Request request = JavaApiConverter.createOkRequest(uri, "POST", javaRequestHeaders); assertFalse(request.isHttps()); assertEquals(uri, request.url().uri()); Headers okRequestHeaders = request.headers(); assertEquals(0, okRequestHeaders.size()); assertEquals("POST", request.method()); } @Test public void createOkRequest_nonNullRequestHeaders() throws Exception { URI uri = new URI("https://foo/bar"); Map> javaRequestHeaders = new HashMap<>(); javaRequestHeaders.put("Foo", Arrays.asList("Bar")); Request request = JavaApiConverter.createOkRequest(uri, "POST", javaRequestHeaders); assertTrue(request.isHttps()); assertEquals(uri, request.url().uri()); Headers okRequestHeaders = request.headers(); assertEquals(1, okRequestHeaders.size()); assertEquals("Bar", okRequestHeaders.get("Foo")); assertEquals("POST", request.method()); } // Older versions of OkHttp would store the "request line" as a header with a // null key. To support the Android usecase where an old version of OkHttp uses // a newer, Android-bundled, version of HttpResponseCache the null key must be // explicitly ignored. @Test public void createOkRequest_nullRequestHeaderKey() throws Exception { URI uri = new URI("https://foo/bar"); Map> javaRequestHeaders = new HashMap<>(); javaRequestHeaders.put(null, Arrays.asList("GET / HTTP 1.1")); javaRequestHeaders.put("Foo", Arrays.asList("Bar")); Request request = JavaApiConverter.createOkRequest(uri, "POST", javaRequestHeaders); assertTrue(request.isHttps()); assertEquals(uri, request.url().uri()); Headers okRequestHeaders = request.headers(); assertEquals(1, okRequestHeaders.size()); assertEquals("Bar", okRequestHeaders.get("Foo")); assertEquals("POST", request.method()); } @Test public void createJavaUrlConnection_requestChangesForbidden() throws Exception { Response okResponse = createArbitraryOkResponse(); HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); // Check an arbitrary (not complete) set of methods that can be used to modify the // request. try { httpUrlConnection.setRequestProperty("key", "value"); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.setFixedLengthStreamingMode(1234); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.setRequestMethod("PUT"); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.getHeaderFields().put("key", Collections.singletonList("value")); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.getOutputStream(); fail(); } catch (UnsupportedOperationException expected) { } } @Test public void createJavaUrlConnection_connectionChangesForbidden() throws Exception { Response okResponse = createArbitraryOkResponse(); HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); try { httpUrlConnection.connect(); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.disconnect(); fail(); } catch (UnsupportedOperationException expected) { } } @Test public void createJavaUrlConnection_responseChangesForbidden() throws Exception { Response okResponse = createArbitraryOkResponse(); HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); // Check an arbitrary (not complete) set of methods that can be used to access the response // body. InputStream is = httpUrlConnection.getInputStream(); try { is.read(); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.getContent(); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.setFixedLengthStreamingMode(1234); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.setRequestMethod("PUT"); fail(); } catch (UnsupportedOperationException expected) { } try { httpUrlConnection.getHeaderFields().put("key", Collections.singletonList("value")); fail(); } catch (UnsupportedOperationException expected) { } } @Test public void createJavaUrlConnection_responseHeadersOk() throws Exception { ResponseBody responseBody = createResponseBody("BodyText"); Response okResponse = new Response.Builder() .request(createArbitraryOkRequest()) .protocol(Protocol.HTTP_1_1) .code(200) .message("Fantastic") .addHeader("A", "c") .addHeader("B", "d") .addHeader("A", "e") .addHeader("Content-Length", Long.toString(responseBody.contentLength())) .body(responseBody) .build(); HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); assertEquals(200, httpUrlConnection.getResponseCode()); assertEquals("Fantastic", httpUrlConnection.getResponseMessage()); assertEquals(responseBody.contentLength(), httpUrlConnection.getContentLength()); // Check retrieval by string key. assertEquals("HTTP/1.1 200 Fantastic", httpUrlConnection.getHeaderField(null)); assertEquals("e", httpUrlConnection.getHeaderField("A")); // The RI and OkHttp supports case-insensitive matching for this method. assertEquals("e", httpUrlConnection.getHeaderField("a")); // Check retrieval using a Map. Map> responseHeaders = httpUrlConnection.getHeaderFields(); assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), responseHeaders.get(null)); assertEquals(newSet("c", "e"), newSet(responseHeaders.get("A"))); // OkHttp supports case-insensitive matching here. The RI does not. assertEquals(newSet("c", "e"), newSet(responseHeaders.get("a"))); // Check the Map iterator contains the expected mappings. assertHeadersContainsMapping(responseHeaders, null, "HTTP/1.1 200 Fantastic"); assertHeadersContainsMapping(responseHeaders, "A", "c", "e"); assertHeadersContainsMapping(responseHeaders, "B", "d"); // Check immutability of the headers Map. try { responseHeaders.put("N", Arrays.asList("o")); fail("Modified an unmodifiable view."); } catch (UnsupportedOperationException expected) { } try { responseHeaders.get("A").add("f"); fail("Modified an unmodifiable view."); } catch (UnsupportedOperationException expected) { } // Check retrieval of headers by index. assertEquals(null, httpUrlConnection.getHeaderFieldKey(0)); assertEquals("HTTP/1.1 200 Fantastic", httpUrlConnection.getHeaderField(0)); // After header zero there may be additional entries provided at the beginning or end by the // implementation. It's probably important that the relative ordering of the headers is // preserved, particularly if there are multiple value for the same key. int i = 1; while (!httpUrlConnection.getHeaderFieldKey(i).equals("A")) { i++; } // Check the ordering of the headers set by app code. assertResponseHeaderAtIndex(httpUrlConnection, i++, "A", "c"); assertResponseHeaderAtIndex(httpUrlConnection, i++, "B", "d"); assertResponseHeaderAtIndex(httpUrlConnection, i++, "A", "e"); // There may be some additional headers provided by the implementation. while (httpUrlConnection.getHeaderField(i) != null) { assertNotNull(httpUrlConnection.getHeaderFieldKey(i)); i++; } // Confirm the correct behavior when the index is out-of-range. assertNull(httpUrlConnection.getHeaderFieldKey(i)); } private static void assertResponseHeaderAtIndex(HttpURLConnection httpUrlConnection, int headerIndex, String expectedKey, String expectedValue) { assertEquals(expectedKey, httpUrlConnection.getHeaderFieldKey(headerIndex)); assertEquals(expectedValue, httpUrlConnection.getHeaderField(headerIndex)); } private void assertHeadersContainsMapping(Map> headers, String expectedKey, String... expectedValues) { assertTrue(headers.containsKey(expectedKey)); assertEquals(newSet(expectedValues), newSet(headers.get(expectedKey))); } @Test public void createJavaUrlConnection_accessibleRequestInfo_GET() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .get() .build(); Response okResponse = createArbitraryOkResponse(okRequest); HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); assertEquals("GET", httpUrlConnection.getRequestMethod()); assertTrue(httpUrlConnection.getDoInput()); assertFalse(httpUrlConnection.getDoOutput()); } @Test public void createJavaUrlConnection_accessibleRequestInfo_POST() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .post(createRequestBody("PostBody")) .build(); Response okResponse = createArbitraryOkResponse(okRequest); HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); assertEquals("POST", httpUrlConnection.getRequestMethod()); assertTrue(httpUrlConnection.getDoInput()); assertTrue(httpUrlConnection.getDoOutput()); } @Test public void createJavaUrlConnection_https_extraHttpsMethods() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .get() .url("https://secure/request") .build(); Handshake handshake = Handshake.get(null, CipherSuite.TLS_RSA_WITH_NULL_MD5, Arrays.asList(SERVER_CERT), Arrays.asList(LOCAL_CERT)); Response okResponse = createArbitraryOkResponse(okRequest).newBuilder() .handshake(handshake) .build(); HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); assertEquals("SSL_RSA_WITH_NULL_MD5", httpsUrlConnection.getCipherSuite()); assertEquals(SERVER_CERT.getSubjectX500Principal(), httpsUrlConnection.getPeerPrincipal()); assertArrayEquals(new Certificate[] {LOCAL_CERT}, httpsUrlConnection.getLocalCertificates()); assertArrayEquals(new Certificate[] {SERVER_CERT}, httpsUrlConnection.getServerCertificates()); assertEquals(LOCAL_CERT.getSubjectX500Principal(), httpsUrlConnection.getLocalPrincipal()); } @Test public void createJavaUrlConnection_https_forbiddenFields() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .url("https://secure/request") .build(); Response okResponse = createArbitraryOkResponse(okRequest); HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) JavaApiConverter.createJavaUrlConnectionForCachePut(okResponse); try { httpsUrlConnection.getHostnameVerifier(); fail(); } catch (UnsupportedOperationException expected) { } try { httpsUrlConnection.getSSLSocketFactory(); fail(); } catch (UnsupportedOperationException expected) { } } @Test public void createJavaCacheResponse_httpGet() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .url("http://insecure/request") .get() .build(); Response okResponse = createArbitraryOkResponse(okRequest).newBuilder() .protocol(Protocol.HTTP_1_1) .code(200) .message("Fantastic") .addHeader("key1", "value1_1") .addHeader("key2", "value2") .addHeader("key1", "value1_2") .body(null) .build(); CacheResponse javaCacheResponse = JavaApiConverter.createJavaCacheResponse(okResponse); assertFalse(javaCacheResponse instanceof SecureCacheResponse); Map> javaHeaders = javaCacheResponse.getHeaders(); assertEquals(Arrays.asList("value1_1", "value1_2"), javaHeaders.get("key1")); assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), javaHeaders.get(null)); assertNull(javaCacheResponse.getBody()); } @Test public void createJavaCacheResponse_httpPost() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .url("http://insecure/request") .post(createRequestBody("RequestBody")) .build(); ResponseBody responseBody = createResponseBody("ResponseBody"); Response okResponse = createArbitraryOkResponse(okRequest).newBuilder() .protocol(Protocol.HTTP_1_1) .code(200) .message("Fantastic") .addHeader("key1", "value1_1") .addHeader("key2", "value2") .addHeader("key1", "value1_2") .body(responseBody) .build(); CacheResponse javaCacheResponse = JavaApiConverter.createJavaCacheResponse(okResponse); assertFalse(javaCacheResponse instanceof SecureCacheResponse); Map> javaHeaders = javaCacheResponse.getHeaders(); assertEquals(Arrays.asList("value1_1", "value1_2"), javaHeaders.get("key1")); assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), javaHeaders.get(null)); assertEquals("ResponseBody", readAll(javaCacheResponse.getBody())); } @Test public void createJavaCacheResponse_httpsPost() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .url("https://secure/request") .post(createRequestBody("RequestBody")) .build(); ResponseBody responseBody = createResponseBody("ResponseBody"); Handshake handshake = Handshake.get(null, CipherSuite.TLS_RSA_WITH_NULL_MD5, Arrays.asList(SERVER_CERT), Arrays.asList(LOCAL_CERT)); Response okResponse = createArbitraryOkResponse(okRequest).newBuilder() .protocol(Protocol.HTTP_1_1) .code(200) .message("Fantastic") .addHeader("key1", "value1_1") .addHeader("key2", "value2") .addHeader("key1", "value1_2") .body(responseBody) .handshake(handshake) .build(); SecureCacheResponse javaCacheResponse = (SecureCacheResponse) JavaApiConverter.createJavaCacheResponse(okResponse); Map> javaHeaders = javaCacheResponse.getHeaders(); assertEquals(Arrays.asList("value1_1", "value1_2"), javaHeaders.get("key1")); assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), javaHeaders.get(null)); assertEquals("ResponseBody", readAll(javaCacheResponse.getBody())); assertEquals(handshake.cipherSuite().javaName(), javaCacheResponse.getCipherSuite()); assertEquals(handshake.localCertificates(), javaCacheResponse.getLocalCertificateChain()); assertEquals(handshake.peerCertificates(), javaCacheResponse.getServerCertificateChain()); assertEquals(handshake.localPrincipal(), javaCacheResponse.getLocalPrincipal()); assertEquals(handshake.peerPrincipal(), javaCacheResponse.getPeerPrincipal()); } @Test public void extractJavaHeaders() throws Exception { Request okRequest = createArbitraryOkRequest().newBuilder() .addHeader("key1", "value1_1") .addHeader("key2", "value2") .addHeader("key1", "value1_2") .build(); Map> javaHeaders = JavaApiConverter.extractJavaHeaders(okRequest); assertEquals(Arrays.asList("value1_1", "value1_2"), javaHeaders.get("key1")); assertEquals(Arrays.asList("value2"), javaHeaders.get("key2")); } @Test public void extractOkHeaders() { Map> javaResponseHeaders = new HashMap<>(); javaResponseHeaders.put(null, Arrays.asList("StatusLine")); javaResponseHeaders.put("key1", Arrays.asList("value1_1", "value1_2")); javaResponseHeaders.put("key2", Arrays.asList("value2")); Headers okHeaders = JavaApiConverter.extractOkHeaders(javaResponseHeaders, null); assertEquals(3, okHeaders.size()); // null entry should be stripped out assertEquals(Arrays.asList("value1_1", "value1_2"), okHeaders.values("key1")); assertEquals(Arrays.asList("value2"), okHeaders.values("key2")); } @Test public void extractStatusLine() throws Exception { Map> javaResponseHeaders = new HashMap<>(); javaResponseHeaders.put(null, Arrays.asList("StatusLine")); javaResponseHeaders.put("key1", Arrays.asList("value1_1", "value1_2")); javaResponseHeaders.put("key2", Arrays.asList("value2")); assertEquals("StatusLine", JavaApiConverter.extractStatusLine(javaResponseHeaders)); try { JavaApiConverter.extractStatusLine(Collections.>emptyMap()); fail(); } catch (IOException expected) { } } private static void assertNotNullAndEquals(T expected, T actual) { assertNotNull(actual); assertEquals(expected, actual); } private static X509Certificate certificate(String certificate) { try { return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate( new ByteArrayInputStream(certificate.getBytes(Util.UTF_8))); } catch (CertificateException e) { fail(); return null; } } @SafeVarargs private static Set newSet(T... elements) { return newSet(Arrays.asList(elements)); } private static Set newSet(List elements) { return new LinkedHashSet<>(elements); } private static Request createArbitraryOkRequest() { return new Request.Builder().url("http://arbitrary/url").build(); } private static Response createArbitraryOkResponse(Request request) { return new Response.Builder() .request(request) .protocol(Protocol.HTTP_1_1) .code(200) .message("Arbitrary") .build(); } private static Response createArbitraryOkResponse() { return createArbitraryOkResponse(createArbitraryOkRequest()); } private static RequestBody createRequestBody(String bodyText) { return RequestBody.create(MediaType.parse("text/plain"), bodyText); } private static ResponseBody createResponseBody(String bodyText) { final Buffer source = new Buffer().writeUtf8(bodyText); final long contentLength = source.size(); return new ResponseBody() { @Override public MediaType contentType() { return MediaType.parse("text/plain; charset=utf-8"); } @Override public long contentLength() { return contentLength; } @Override public BufferedSource source() { return source; } }; } private String readAll(InputStream in) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int value; while ((value = in.read()) != -1) { buffer.write(value); } in.close(); return buffer.toString("UTF-8"); } }