Skip to content

Commit

Permalink
Adjust new 2.1 APIs.
Browse files Browse the repository at this point in the history
ConnectionConfiguration was missing a Builder. We had slightly
misleading docs in OkHttpClient.setFollowRedirects().

All the other new docs look pretty reasonable.
  • Loading branch information
squarejesse committed Nov 5, 2014
1 parent cd56d89 commit 92b6f57
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 63 deletions.
173 changes: 116 additions & 57 deletions okhttp/src/main/java/com/squareup/okhttp/ConnectionConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,53 +27,52 @@
* when negotiating a secure connection.
*/
public final class ConnectionConfiguration {
/**
* This is a subset of the cipher suites supported in Chrome 37, current as of 2014-10-5. All of
* these suites are available on Android L; earlier releases support a subset of these suites.
* https://github.com/square/okhttp/issues/330
*/
private static final String[] CIPHER_SUITES = new String[] {
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2B Android L
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2F Android L
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9E Android L
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", // 0xC0,0x0A Android 4.0
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", // 0xC0,0x09 Android 4.0
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 0xC0,0x13 Android 4.0
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 0xC0,0x14 Android 4.0
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", // 0xC0,0x07 Android 4.0
"TLS_ECDHE_RSA_WITH_RC4_128_SHA", // 0xC0,0x11 Android 4.0
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x33 Android 2.3
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA", // 0x00,0x32 Android 2.3
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x39 Android 2.3
"TLS_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9C Android L
"TLS_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x2F Android 2.3
"TLS_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x35 Android 2.3
"SSL_RSA_WITH_3DES_EDE_CBC_SHA", // 0x00,0x0A Android 2.3 (Deprecated in L)
"SSL_RSA_WITH_RC4_128_SHA", // 0x00,0x05 Android 2.3
"SSL_RSA_WITH_RC4_128_MD5" // 0x00,0x04 Android 2.3 (Deprecated in L)
};

private static final String TLS_1_2 = "TLSv1.2"; // 2008.
private static final String TLS_1_1 = "TLSv1.1"; // 2006.
private static final String TLS_1_0 = "TLSv1"; // 1999.
private static final String SSL_3_0 = "SSLv3"; // 1996.

/** A modern TLS configuration with extensions like SNI and ALPN available. */
public static final ConnectionConfiguration MODERN_TLS = new ConnectionConfiguration(
true, CIPHER_SUITES, new String[] { TLS_1_2, TLS_1_1, TLS_1_0, SSL_3_0 }, true);
public static final ConnectionConfiguration MODERN_TLS = new Builder(true)
.cipherSuites(
// This is a subset of the cipher suites supported in Chrome 37, current as of 2014-10-5.
// All of these suites are available on Android L; earlier releases support a subset of
// these suites. https://github.com/square/okhttp/issues/330
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2B Android L
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2F Android L
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9E Android L
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", // 0xC0,0x0A Android 4.0
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", // 0xC0,0x09 Android 4.0
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 0xC0,0x13 Android 4.0
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 0xC0,0x14 Android 4.0
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", // 0xC0,0x07 Android 4.0
"TLS_ECDHE_RSA_WITH_RC4_128_SHA", // 0xC0,0x11 Android 4.0
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x33 Android 2.3
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA", // 0x00,0x32 Android 2.3
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x39 Android 2.3
"TLS_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9C Android L
"TLS_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x2F Android 2.3
"TLS_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x35 Android 2.3
"SSL_RSA_WITH_3DES_EDE_CBC_SHA", // 0x00,0x0A Android 2.3 (Deprecated in L)
"SSL_RSA_WITH_RC4_128_SHA", // 0x00,0x05 Android 2.3
"SSL_RSA_WITH_RC4_128_MD5" // 0x00,0x04 Android 2.3 (Deprecated in L)
)
.tlsVersions(TLS_1_2, TLS_1_1, TLS_1_0, SSL_3_0)
.supportsTlsExtensions(true)
.build();

/** A backwards-compatible fallback configuration for interop with obsolete servers. */
public static final ConnectionConfiguration COMPATIBLE_TLS = new ConnectionConfiguration(
true, CIPHER_SUITES, new String[] { SSL_3_0 }, true);
public static final ConnectionConfiguration COMPATIBLE_TLS = new Builder(MODERN_TLS)
.tlsVersions(SSL_3_0)
.build();

/** Unencrypted, unauthenticated connections for {@code http:} URLs. */
public static final ConnectionConfiguration CLEARTEXT = new ConnectionConfiguration(
false, new String[0], new String[0], false);
public static final ConnectionConfiguration CLEARTEXT = new Builder(false).build();

private final boolean tls;
final boolean tls;
private final String[] cipherSuites;
private final String[] tlsVersions;
private final boolean supportsTlsExtensions;
final boolean supportsTlsExtensions;

/**
* Caches the subset of this configuration that's supported by the host
Expand All @@ -82,19 +81,11 @@ public final class ConnectionConfiguration {
*/
private ConnectionConfiguration supportedConfiguration;

private ConnectionConfiguration(boolean tls, String[] cipherSuites, String[] tlsVersions,
boolean supportsTlsExtensions) {
this.tls = tls;
this.cipherSuites = cipherSuites;
this.tlsVersions = tlsVersions;
this.supportsTlsExtensions = supportsTlsExtensions;

if (tls && (cipherSuites.length == 0 || tlsVersions.length == 0)) {
throw new IllegalArgumentException("Unexpected configuration: " + this);
}
if (!tls && (cipherSuites.length != 0 || tlsVersions.length != 0 || supportsTlsExtensions)) {
throw new IllegalArgumentException("Unexpected configuration: " + this);
}
private ConnectionConfiguration(Builder builder) {
this.tls = builder.tls;
this.cipherSuites = builder.cipherSuites;
this.tlsVersions = builder.tlsVersions;
this.supportsTlsExtensions = builder.supportsTlsExtensions;
}

public boolean isTls() {
Expand All @@ -114,7 +105,7 @@ public boolean supportsTlsExtensions() {
}

/** Applies this configuration to {@code sslSocket} for {@code route}. */
public void apply(SSLSocket sslSocket, Route route) {
void apply(SSLSocket sslSocket, Route route) {
ConnectionConfiguration configurationToApply = supportedConfiguration;
if (configurationToApply == null) {
configurationToApply = supportedConfiguration(sslSocket);
Expand All @@ -139,17 +130,85 @@ private ConnectionConfiguration supportedConfiguration(SSLSocket sslSocket) {
Arrays.asList(sslSocket.getSupportedCipherSuites()));
List<String> supportedTlsVersions = Util.intersect(Arrays.asList(tlsVersions),
Arrays.asList(sslSocket.getSupportedProtocols()));
return new ConnectionConfiguration(tls,
supportedCipherSuites.toArray(new String[supportedCipherSuites.size()]),
supportedTlsVersions.toArray(new String[supportedTlsVersions.size()]),
supportsTlsExtensions);
return new Builder(this)
.cipherSuites(supportedCipherSuites.toArray(new String[supportedCipherSuites.size()]))
.tlsVersions(supportedTlsVersions.toArray(new String[supportedTlsVersions.size()]))
.build();
}

@Override public boolean equals(Object other) {
if (!(other instanceof ConnectionConfiguration)) return false;

ConnectionConfiguration that = (ConnectionConfiguration) other;
if (this.tls != that.tls) return false;

if (tls) {
if (!Arrays.equals(this.cipherSuites, that.cipherSuites)) return false;
if (!Arrays.equals(this.tlsVersions, that.tlsVersions)) return false;
if (this.supportsTlsExtensions != that.supportsTlsExtensions) return false;
}

return true;
}

@Override public int hashCode() {
int result = 17;
if (tls) {
result = 31 * result + Arrays.hashCode(cipherSuites);
result = 31 * result + Arrays.hashCode(tlsVersions);
result = 31 * result + (supportsTlsExtensions ? 0 : 1);
}
return result;
}

@Override public String toString() {
return "ConnectionConfiguration(tls=" + tls
+ ", cipherSuites=" + Arrays.toString(cipherSuites)
+ ", tlsVersions=" + Arrays.toString(tlsVersions)
+ ", supportsTlsExtensions=" + supportsTlsExtensions
+ ")";
if (tls) {
return "ConnectionConfiguration(cipherSuites=" + Arrays.toString(cipherSuites)
+ ", tlsVersions=" + Arrays.toString(tlsVersions)
+ ", supportsTlsExtensions=" + supportsTlsExtensions
+ ")";
} else {
return "ConnectionConfiguration()";
}
}

public static final class Builder {
private boolean tls;
private String[] cipherSuites;
private String[] tlsVersions;
private boolean supportsTlsExtensions;

private Builder(boolean tls) {
this.tls = tls;
}

public Builder(ConnectionConfiguration connectionConfiguration) {
this.tls = connectionConfiguration.tls;
this.cipherSuites = connectionConfiguration.cipherSuites;
this.tlsVersions = connectionConfiguration.tlsVersions;
this.supportsTlsExtensions = connectionConfiguration.supportsTlsExtensions;
}

public Builder cipherSuites(String... cipherSuites) {
if (!tls) throw new IllegalStateException("no cipher suites for cleartext connections");
this.cipherSuites = cipherSuites.clone(); // Defensive copy.
return this;
}

public Builder tlsVersions(String... tlsVersions) {
if (!tls) throw new IllegalStateException("no TLS versions for cleartext connections");
this.tlsVersions = tlsVersions.clone(); // Defensive copy.
return this;
}

public Builder supportsTlsExtensions(boolean supportsTlsExtensions) {
if (!tls) throw new IllegalStateException("no TLS extensions for cleartext connections");
this.supportsTlsExtensions = supportsTlsExtensions;
return this;
}

public ConnectionConfiguration build() {
return new ConnectionConfiguration(this);
}
}
}
7 changes: 1 addition & 6 deletions okhttp/src/main/java/com/squareup/okhttp/OkHttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -406,12 +406,7 @@ public final boolean getFollowSslRedirects() {
return followSslRedirects;
}

/**
* Configure this client to follow redirects.
*
* <p>If unset, redirects will not be followed. This is the equivalent as the
* built-in {@code HttpURLConnection}'s default.
*/
/** Configure this client to follow redirects. If unset, redirects be followed. */
public final void setFollowRedirects(boolean followRedirects) {
this.followRedirects = followRedirects;
}
Expand Down

0 comments on commit 92b6f57

Please sign in to comment.