1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-17 08:42:25 +03:00

Merge pull request #2185 from square/jwilson_0101_api_ergonomics

Detect API use errors earlier.
This commit is contained in:
Jake Wharton
2016-01-02 02:13:16 -05:00
6 changed files with 77 additions and 18 deletions

View File

@@ -633,7 +633,7 @@ public final class JavaApiConverter {
if (position < 0) {
throw new IllegalArgumentException("Invalid header index: " + position);
}
if (position == 0) {
if (position == 0 || position > response.headers().size()) {
return null;
}
return response.headers().name(position - 1);
@@ -648,6 +648,9 @@ public final class JavaApiConverter {
if (position == 0) {
return StatusLine.get(response).toString();
}
if (position > response.headers().size()) {
return null;
}
return response.headers().value(position - 1);
}

View File

@@ -590,8 +590,7 @@ public final class URLConnectionTest {
assertEquals(1, server.takeRequest().getSequenceNumber());
}
@Test public void connectViaHttpsReusingConnectionsDifferentFactories()
throws IOException, InterruptedException {
@Test public void connectViaHttpsReusingConnectionsDifferentFactories() throws Exception {
server.useHttps(sslContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
server.enqueue(new MockResponse().setBody("another response via HTTPS"));
@@ -604,8 +603,11 @@ public final class URLConnectionTest {
HttpURLConnection connection1 = urlFactory.open(server.url("/").url());
assertContent("this response comes via HTTPS", connection1);
SSLContext sslContext2 = SSLContext.getInstance("TLS");
sslContext2.init(null, null, null);
SSLSocketFactory sslSocketFactory2 = sslContext2.getSocketFactory();
urlFactory.setClient(urlFactory.client().newBuilder()
.sslSocketFactory(null)
.sslSocketFactory(sslSocketFactory2)
.build());
HttpURLConnection connection2 = urlFactory.open(server.url("/").url());
try {

View File

@@ -302,4 +302,36 @@ public final class HeadersTest {
assertEquals(2, headerMap.get("cache-control").size());
assertEquals(1, headerMap.get("user-agent").size());
}
@Test public void nameIndexesAreStrict() {
Headers headers = Headers.of("a", "b", "c", "d");
try {
headers.name(-1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
assertEquals("a", headers.name(0));
assertEquals("c", headers.name(1));
try {
headers.name(2);
fail();
} catch (IndexOutOfBoundsException expected) {
}
}
@Test public void valueIndexesAreStrict() {
Headers headers = Headers.of("a", "b", "c", "d");
try {
headers.value(-1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
assertEquals("b", headers.value(0));
assertEquals("d", headers.value(1));
try {
headers.value(2);
fail();
} catch (IndexOutOfBoundsException expected) {
}
}
}

View File

@@ -181,7 +181,9 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
*/
@Override public final String getHeaderField(int position) {
try {
return getHeaders().value(position);
Headers headers = getHeaders();
if (position < 0 || position >= headers.size()) return null;
return headers.value(position);
} catch (IOException e) {
return null;
}
@@ -203,7 +205,9 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
@Override public final String getHeaderFieldKey(int position) {
try {
return getHeaders().name(position);
Headers headers = getHeaders();
if (position < 0 || position >= headers.size()) return null;
return headers.name(position);
} catch (IOException e) {
return null;
}

View File

@@ -73,22 +73,14 @@ public final class Headers {
return namesAndValues.length / 2;
}
/** Returns the field at {@code position} or null if that is out of range. */
/** Returns the field at {@code position}. */
public String name(int index) {
int nameIndex = index * 2;
if (nameIndex < 0 || nameIndex >= namesAndValues.length) {
return null;
}
return namesAndValues[nameIndex];
return namesAndValues[index * 2];
}
/** Returns the value at {@code index} or null if that is out of range. */
/** Returns the value at {@code index}. */
public String value(int index) {
int valueIndex = index * 2 + 1;
if (valueIndex < 0 || valueIndex >= namesAndValues.length) {
return null;
}
return namesAndValues[valueIndex];
return namesAndValues[index * 2 + 1];
}
/** Returns an immutable case-insensitive set of header names. */

View File

@@ -451,6 +451,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* <p>If unset, {@linkplain CookieJar#NO_COOKIES no cookies} will be accepted nor provided.
*/
public Builder cookieJar(CookieJar cookieJar) {
if (cookieJar == null) throw new NullPointerException("cookieJar == null");
this.cookieJar = cookieJar;
return this;
}
@@ -473,6 +474,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* <p>If unset, the {@link Dns#SYSTEM system-wide default} DNS will be used.
*/
public Builder dns(Dns dns) {
if (dns == null) throw new NullPointerException("dns == null");
this.dns = dns;
return this;
}
@@ -486,6 +488,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* be used.
*/
public Builder socketFactory(SocketFactory socketFactory) {
if (socketFactory == null) throw new NullPointerException("socketFactory == null");
this.socketFactory = socketFactory;
return this;
}
@@ -496,6 +499,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* <p>If unset, a lazily created SSL socket factory will be used.
*/
public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) {
if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null");
this.sslSocketFactory = sslSocketFactory;
return this;
}
@@ -507,6 +511,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* <p>If unset, a default hostname verifier will be used.
*/
public Builder hostnameVerifier(HostnameVerifier hostnameVerifier) {
if (hostnameVerifier == null) throw new NullPointerException("hostnameVerifier == null");
this.hostnameVerifier = hostnameVerifier;
return this;
}
@@ -517,6 +522,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* Pinning certificates avoids the need to trust certificate authorities.
*/
public Builder certificatePinner(CertificatePinner certificatePinner) {
if (certificatePinner == null) throw new NullPointerException("certificatePinner == null");
this.certificatePinner = certificatePinner;
return this;
}
@@ -528,6 +534,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* <p>If unset, the {@linkplain Authenticator#NONE no authentication will be attempted}.
*/
public Builder authenticator(Authenticator authenticator) {
if (authenticator == null) throw new NullPointerException("authenticator == null");
this.authenticator = authenticator;
return this;
}
@@ -539,6 +546,7 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
* <p>If unset, the {@linkplain Authenticator#NONE no authentication will be attempted}.
*/
public Builder proxyAuthenticator(Authenticator proxyAuthenticator) {
if (proxyAuthenticator == null) throw new NullPointerException("proxyAuthenticator == null");
this.proxyAuthenticator = proxyAuthenticator;
return this;
}
@@ -652,11 +660,29 @@ public final class OkHttpClient implements Cloneable, Call.Factory {
return this;
}
/**
* Returns a modifiable list of interceptors that observe the full span of each call: from
* before the connection is established (if any) until after the response source is selected
* (either the origin server, cache, or both).
*/
public List<Interceptor> interceptors() {
return interceptors;
}
public Builder addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
return this;
}
/**
* Returns a modifiable list of interceptors that observe a single network request and response.
* These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error
* for a network interceptor to short-circuit or repeat a network request.
*/
public List<Interceptor> networkInterceptors() {
return networkInterceptors;
}
public Builder addNetworkInterceptor(Interceptor interceptor) {
networkInterceptors.add(interceptor);
return this;