1
0
mirror of https://github.com/square/okhttp.git synced 2025-08-08 23:42:08 +03:00
Files
okhttp/okhttp-android-support/src/test/java/okhttp3/internal/huc/JavaApiConverterTest.java
jwilson bab8943f2b Promote sent and received timestamps to fields on Response.
I'm currently keeping these as longs. That's easy an unambiguous, but it also
feels rather primitive.

This was more work than I expected, but it doesn't seem particularly risky.
It's also potentially more efficient, since there's fewer places where we're
converting from string to long and vice versa.

Closes: https://github.com/square/okhttp/issues/2035
2016-05-08 15:25:56 -04:00

693 lines
28 KiB
Java

/*
* 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<String, List<String>> getHeaders() throws IOException {
Map<String, List<String>> 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<String, List<String>> getHeaders() throws IOException {
Map<String, List<String>> 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<Certificate> localCertificates = Arrays.<Certificate>asList(LOCAL_CERT);
final Principal serverPrincipal = SERVER_CERT.getSubjectX500Principal();
final List<Certificate> serverCertificates = Arrays.<Certificate>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<String, List<String>> getHeaders() throws IOException {
Map<String, List<String>> 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<Certificate> getLocalCertificateChain() {
return localCertificates;
}
@Override public List<Certificate> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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.<Certificate>asList(SERVER_CERT), Arrays.<Certificate>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<String, List<String>> 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<String, List<String>> 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.<Certificate>asList(SERVER_CERT), Arrays.<Certificate>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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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.<String, List<String>>emptyMap());
fail();
} catch (IOException expected) {
}
}
private static <T> 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 <T> Set<T> newSet(T... elements) {
return newSet(Arrays.asList(elements));
}
private static <T> Set<T> newSet(List<T> 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");
}
}