mirror of
https://github.com/square/okhttp.git
synced 2025-08-08 23:42:08 +03:00
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
693 lines
28 KiB
Java
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");
|
|
}
|
|
}
|