1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-12 10:23:16 +03:00

Add ALPN support; Configure maven to use ALPN on OpenJDK 8.

This commit is contained in:
Adrian Cole
2014-04-28 09:35:04 -07:00
parent 743ae0cbba
commit a5b7c3b2f3
14 changed files with 249 additions and 151 deletions

View File

@@ -8,3 +8,4 @@ before_install:
jdk:
- oraclejdk7
- oraclejdk8

View File

@@ -34,8 +34,8 @@ Testing
### On the Desktop
Run OkHttp tests on the desktop with Maven. Running SPDY tests on the desktop uses
[Jetty-NPN][3] which requires OpenJDK 7.
Run OkHttp tests on the desktop with Maven. Running HTTP/2 and SPDY tests on the desktop uses
[Jetty-NPN][3] when running OpenJDK 7 or [Jetty-ALPN][4] when OpenJDK 8.
```
mvn clean test
@@ -46,7 +46,7 @@ mvn clean test
OkHttp's test suite creates an in-process HTTPS server. Prior to Android 2.3, SSL server sockets
were broken, and so HTTPS tests will time out when run on such devices.
Test on a USB-attached Android using [Vogar][4]. Unfortunately `dx` requires that you build with
Test on a USB-attached Android using [Vogar][5]. Unfortunately `dx` requires that you build with
Java 6, otherwise the test class will be silently omitted from the `.dex` file.
```
@@ -69,7 +69,7 @@ MockWebServer coupling with OkHttp is essential for proper testing of SPDY and H
### Download
Download [the latest JAR][5] or grab via Maven:
Download [the latest JAR][6] or grab via Maven:
```xml
<dependency>
@@ -102,5 +102,6 @@ License
[1]: http://square.github.io/okhttp
[2]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.squareup.okhttp&a=okhttp&v=LATEST
[3]: https://github.com/jetty-project/jetty-npn
[4]: https://code.google.com/p/vogar/
[5]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.squareup.okhttp&a=mockwebserver&v=LATEST
[4]: https://github.com/jetty-project/jetty-alpn
[5]: https://code.google.com/p/vogar/
[6]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.squareup.okhttp&a=mockwebserver&v=LATEST

View File

@@ -38,11 +38,6 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.mortbay.jetty.npn</groupId>
<artifactId>npn-boot</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
@@ -71,28 +66,70 @@
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<arguments>
<argument>-Xms512m</argument>
<argument>-Xmx512m</argument>
<commandlineArgs>-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar</commandlineArgs>
<argument>-classpath</argument>
<classpath/>
<argument>com.squareup.okhttp.benchmarks.Benchmark</argument>
</arguments>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<arguments>
<argument>-Xms512m</argument>
<argument>-Xmx512m</argument>
<commandlineArgs>-Xbootclasspath/p:${bootclasspath}</commandlineArgs>
<argument>-classpath</argument>
<classpath/>
<argument>com.squareup.okhttp.benchmarks.Benchmark</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>npn-when-jdk7</id>
<activation>
<jdk>1.7</jdk>
</activation>
<dependencies>
<dependency>
<groupId>org.mortbay.jetty.npn</groupId>
<artifactId>npn-boot</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>alpn-when-jdk8</id>
<activation>
<jdk>1.8</jdk>
</activation>
<dependencies>
<dependency>
<groupId>org.mortbay.jetty.alpn</groupId>
<artifactId>alpn-boot</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!-- Fails on caliper's ASM on OpenJDK 8. -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<executions>
<execution>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -22,11 +22,6 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.mortbay.jetty.npn</groupId>
<artifactId>npn-boot</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@@ -110,7 +110,7 @@ public final class MockWebServer {
private int port = -1;
private boolean protocolNegotiationEnabled = true;
private List<Protocol> npnProtocols
private List<Protocol> protocols
= Util.immutableList(Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1);
public int getPort() {
@@ -209,7 +209,7 @@ public final class MockWebServer {
if (protocols.contains(null)) {
throw new IllegalArgumentException("protocols must not contain null");
}
this.npnProtocols = protocols;
this.protocols = protocols;
}
/**
@@ -351,7 +351,7 @@ public final class MockWebServer {
openClientSockets.put(socket, true);
if (protocolNegotiationEnabled) {
Platform.get().setProtocols(sslSocket, npnProtocols);
Platform.get().setProtocols(sslSocket, protocols);
}
sslSocket.startHandshake();

View File

@@ -22,11 +22,6 @@
<artifactId>okhttp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty.npn</groupId>
<artifactId>npn-boot</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@@ -92,12 +92,12 @@ public final class CallTest {
}
@Test public void get_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
get();
}
@Test public void get_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
get();
}
@@ -123,12 +123,12 @@ public final class CallTest {
}
@Test public void head_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
head();
}
@Test public void head_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
head();
}
@@ -153,12 +153,12 @@ public final class CallTest {
}
@Test public void post_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
post();
}
@Test public void post_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
post();
}
@@ -183,12 +183,12 @@ public final class CallTest {
}
@Test public void postZeroLength_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
postZeroLength();
}
@Test public void postZerolength_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
postZeroLength();
}
@@ -213,12 +213,12 @@ public final class CallTest {
}
@Test public void delete_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
delete();
}
@Test public void delete_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
delete();
}
@@ -243,12 +243,12 @@ public final class CallTest {
}
@Test public void put_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
put();
}
@Test public void put_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
put();
}
@@ -273,12 +273,12 @@ public final class CallTest {
}
@Test public void patch_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
patch();
}
@Test public void patch_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
patch();
}
@@ -914,12 +914,12 @@ public final class CallTest {
}
@Test public void canceledBeforeIOSignalsOnFailure_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
canceledBeforeIOSignalsOnFailure();
}
@Test public void canceledBeforeIOSignalsOnFailure_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
canceledBeforeIOSignalsOnFailure();
}
@@ -940,12 +940,12 @@ public final class CallTest {
}
@Test public void canceledBeforeResponseReadSignalsOnFailure_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
canceledBeforeResponseReadSignalsOnFailure();
}
@Test public void canceledBeforeResponseReadSignalsOnFailure_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
canceledBeforeResponseReadSignalsOnFailure();
}
@@ -989,13 +989,13 @@ public final class CallTest {
@Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_HTTP_2()
throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce();
}
@Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_SPDY_3()
throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce();
}
@@ -1006,9 +1006,9 @@ public final class CallTest {
/**
* Tests that use this will fail unless boot classpath is set. Ex. {@code
* -Xbootclasspath/p:/tmp/npn-boot-1.1.7.v20140316.jar}
* -Xbootclasspath/p:/tmp/alpn-boot-8.0.0.v20140317}
*/
private void enableNpn(Protocol protocol) {
private void enableProtocol(Protocol protocol) {
client.setSslSocketFactory(sslContext.getSocketFactory());
client.setHostnameVerifier(new RecordingHostnameVerifier());
client.setProtocols(Arrays.asList(protocol, Protocol.HTTP_1_1));

View File

@@ -647,10 +647,10 @@ public final class URLConnectionTest {
assertContent("def", client.open(server.getUrl("/")));
RecordedRequest request1 = server.takeRequest();
assertEquals("TLSv1", request1.getSslProtocol()); // OkHttp's current best TLS version.
assertTrue(request1.getSslProtocol().startsWith("TLSv1")); // v1.2 on OpenJDK 8.
RecordedRequest request2 = server.takeRequest();
assertEquals("TLSv1", request2.getSslProtocol()); // OkHttp's current best TLS version.
assertTrue(request2.getSslProtocol().startsWith("TLSv1")); // v1.2 on OpenJDK 8.
}
/**
@@ -2745,19 +2745,19 @@ public final class URLConnectionTest {
assertTrue(call, call.contains("challenges=[Bearer realm=\"oauthed\"]"));
}
@Test public void npnSetsProtocolHeader_SPDY_3() throws Exception {
npnSetsProtocolHeader(Protocol.SPDY_3);
@Test public void setsNegotiatedProtocolHeader_SPDY_3() throws Exception {
setsNegotiatedProtocolHeader(Protocol.SPDY_3);
}
@Test public void npnSetsProtocolHeader_HTTP_2() throws Exception {
npnSetsProtocolHeader(Protocol.HTTP_2);
@Test public void setsNegotiatedProtocolHeader_HTTP_2() throws Exception {
setsNegotiatedProtocolHeader(Protocol.HTTP_2);
}
private void npnSetsProtocolHeader(Protocol protocol) throws IOException {
enableNpn(protocol);
private void setsNegotiatedProtocolHeader(Protocol protocol) throws IOException {
enableProtocol(protocol);
server.enqueue(new MockResponse().setBody("A"));
server.play();
client.setProtocols(Arrays.asList(Protocol.HTTP_1_1, protocol));
client.setProtocols(Arrays.asList(protocol, Protocol.HTTP_1_1));
connection = client.open(server.getUrl("/"));
List<String> protocolValues = connection.getHeaderFields().get(SELECTED_PROTOCOL);
assertEquals(Arrays.asList(protocol.toString()), protocolValues);
@@ -2786,12 +2786,12 @@ public final class URLConnectionTest {
}
@Test public void zeroLengthPost_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
zeroLengthPost();
}
@Test public void zeroLengthPost_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
zeroLengthPost();
}
@@ -2801,12 +2801,12 @@ public final class URLConnectionTest {
}
@Test public void zeroLengthPut_SPDY_3() throws Exception {
enableNpn(Protocol.SPDY_3);
enableProtocol(Protocol.SPDY_3);
zeroLengthPut();
}
@Test public void zeroLengthPut_HTTP_2() throws Exception {
enableNpn(Protocol.HTTP_2);
enableProtocol(Protocol.HTTP_2);
zeroLengthPut();
}
@@ -3113,9 +3113,9 @@ public final class URLConnectionTest {
/**
* Tests that use this will fail unless boot classpath is set. Ex. {@code
* -Xbootclasspath/p:/tmp/npn-boot-1.1.7.v20140316.jar}
* -Xbootclasspath/p:/tmp/alpn-boot-8.0.0.v20140317}
*/
private void enableNpn(Protocol protocol) {
private void enableProtocol(Protocol protocol) {
client.setSslSocketFactory(sslContext.getSocketFactory());
client.setHostnameVerifier(new RecordingHostnameVerifier());
client.setProtocols(Arrays.asList(protocol, Protocol.HTTP_1_1));

View File

@@ -51,8 +51,8 @@ import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
* <ul>
* <li>Server Name Indication (SNI) enables one IP address to negotiate secure
* connections for multiple domain names.
* <li>Next Protocol Negotiation (NPN) enables the HTTPS port (443) to be used
* for both HTTP and SPDY protocols.
* <li>Application Layer Protocol Negotiation (ALPN) enables the HTTPS port
* (443) to be used for different HTTP and SPDY protocols.
* </ul>
* Unfortunately, older HTTPS servers refuse to connect when such options are
* presented. Rather than avoiding these options entirely, this class allows a

View File

@@ -321,19 +321,17 @@ public final class OkHttpClient implements URLStreamHandlerFactory, Cloneable {
* <ul>
* <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a>
* <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">spdy/3.1</a>
* <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-09">HTTP-draft-09/2.0</a>
* <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-10">h2-10</a>
* </ul>
*
* <p><strong>This is an evolving set.</strong> Future releases may drop
* support for transitional protocols (like spdy/3.1), in favor of their
* successors (spdy/4 or hTTP/2). The http/1.1 transport will never be
* dropped.
* support for transitional protocols (like h2-10), in favor of their
* successors (h2). The http/1.1 transport will never be dropped.
*
* <p>If multiple protocols are specified, <a
* href="https://technotes.googlecode.com/git/nextprotoneg.html">NPN</a> will
* be used to negotiate a transport. Future releases may use another mechanism
* (such as <a href="http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02">ALPN</a>)
* to negotiate a transport.
* href="https://technotes.googlecode.com/git/nextprotoneg.html">NPN</a> or
* <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg">ALPN</a>
* will be used to negotiate a transport.
*
* @param protocols the protocols to use, in order of preference. The list
* must contain {@link Protocol#HTTP_1_1}. It must not contain null.

View File

@@ -20,7 +20,8 @@ import java.io.IOException;
/**
* Protocols that OkHttp implements for <a
* href="http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04">NPN</a> and
* <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg">ALPN</a>.
* <a href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg">ALPN</a>
* selection.
*
* <h3>Protocol vs Scheme</h3>
* Despite its name, {@link java.net.URL#getProtocol()} returns the

View File

@@ -45,12 +45,13 @@ import okio.Buffer;
*
* <p>NPN (Next Protocol Negotiation) was developed for SPDY. It is widely
* available and we support it on both Android (4.1+) and OpenJDK 7 (via the
* Jetty NPN-boot library). NPN is not yet available on Java 8.
* Jetty Alpn-boot library). NPN is not yet available on OpenJDK 8.
*
* <p>ALPN (Application Layer Protocol Negotiation) is the successor to NPN. It
* has some technical advantages over NPN. ALPN first arrived in Android 4.4,
* but that release suffers a <a href="http://goo.gl/y5izPP">concurrency bug</a>
* so we don't use it. ALPN will be supported in the future.
* so we don't use it. ALPN is supported on OpenJDK 7 and 8 (via the Jetty
* ALPN-boot library).
*
* <p>On platforms that support both extensions, OkHttp will use both,
* preferring ALPN's result. Future versions of OkHttp will drop support for
@@ -148,21 +149,24 @@ public class Platform {
// This isn't Android 2.3 or better.
}
// Attempt to find the Jetty's NPN extension for OpenJDK.
try {
String npnClassName = "org.eclipse.jetty.npn.NextProtoNego";
Class<?> nextProtoNegoClass = Class.forName(npnClassName);
Class<?> providerClass = Class.forName(npnClassName + "$Provider");
Class<?> clientProviderClass = Class.forName(npnClassName + "$ClientProvider");
Class<?> serverProviderClass = Class.forName(npnClassName + "$ServerProvider");
Method putMethod = nextProtoNegoClass.getMethod("put", SSLSocket.class, providerClass);
Method getMethod = nextProtoNegoClass.getMethod("get", SSLSocket.class);
return new JdkWithJettyNpnPlatform(
try { // to find the Jetty's ALPN or NPN extension for OpenJDK.
String negoClassName = "org.eclipse.jetty.alpn.ALPN";
Class<?> negoClass;
try {
negoClass = Class.forName(negoClassName);
} catch (ClassNotFoundException ignored) { // ALPN isn't on the classpath.
negoClassName = "org.eclipse.jetty.npn.NextProtoNego";
negoClass = Class.forName(negoClassName);
}
Class<?> providerClass = Class.forName(negoClassName + "$Provider");
Class<?> clientProviderClass = Class.forName(negoClassName + "$ClientProvider");
Class<?> serverProviderClass = Class.forName(negoClassName + "$ServerProvider");
Method putMethod = negoClass.getMethod("put", SSLSocket.class, providerClass);
Method getMethod = negoClass.getMethod("get", SSLSocket.class);
return new JdkWithJettyBootPlatform(
putMethod, getMethod, clientProviderClass, serverProviderClass);
} catch (ClassNotFoundException ignored) {
// NPN isn't on the classpath.
} catch (NoSuchMethodException ignored) {
// The NPN version isn't what we expect.
} catch (ClassNotFoundException ignored) { // NPN isn't on the classpath.
} catch (NoSuchMethodException ignored) { // The ALPN or NPN version isn't what we expect.
}
return new Platform();
@@ -247,15 +251,18 @@ public class Platform {
}
}
/** OpenJDK 7 plus {@code org.mortbay.jetty.npn/npn-boot} on the boot class path. */
private static class JdkWithJettyNpnPlatform extends Platform {
/**
* OpenJDK 7+ with {@code org.mortbay.jetty.npn/npn-boot} or
* {@code org.mortbay.jetty.alpn/alpn-boot} in the boot class path.
*/
private static class JdkWithJettyBootPlatform extends Platform {
private final Method getMethod;
private final Method putMethod;
private final Class<?> clientProviderClass;
private final Class<?> serverProviderClass;
public JdkWithJettyNpnPlatform(Method putMethod, Method getMethod, Class<?> clientProviderClass,
Class<?> serverProviderClass) {
public JdkWithJettyBootPlatform(Method putMethod, Method getMethod,
Class<?> clientProviderClass, Class<?> serverProviderClass) {
this.putMethod = putMethod;
this.getMethod = getMethod;
this.clientProviderClass = clientProviderClass;
@@ -267,11 +274,11 @@ public class Platform {
List<String> names = new ArrayList<String>(protocols.size());
for (int i = 0, size = protocols.size(); i < size; i++) {
Protocol protocol = protocols.get(i);
if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for NPN.
if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for NPN or ALPN.
names.add(protocol.toString());
}
Object provider = Proxy.newProxyInstance(Platform.class.getClassLoader(),
new Class[] { clientProviderClass, serverProviderClass }, new JettyNpnProvider(names));
new Class[] { clientProviderClass, serverProviderClass }, new JettyNegoProvider(names));
putMethod.invoke(null, socket, provider);
} catch (InvocationTargetException e) {
throw new AssertionError(e);
@@ -282,12 +289,12 @@ public class Platform {
@Override public String getSelectedProtocol(SSLSocket socket) {
try {
JettyNpnProvider provider =
(JettyNpnProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket));
JettyNegoProvider provider =
(JettyNegoProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket));
if (!provider.unsupported && provider.selected == null) {
Logger logger = Logger.getLogger("com.squareup.okhttp.OkHttpClient");
logger.log(Level.INFO,
"NPN callback dropped so SPDY is disabled. Is npn-boot on the boot class path?");
logger.log(Level.INFO, "NPN/ALPN callback dropped: SPDY and HTTP/2 are disabled. "
+ "Is npn-boot or alpn-boot on the boot class path?");
return null;
}
return provider.unsupported ? null : provider.selected;
@@ -300,18 +307,18 @@ public class Platform {
}
/**
* Handle the methods of NextProtoNego's ClientProvider and ServerProvider
* Handle the methods of NPN or ALPN's ClientProvider and ServerProvider
* without a compile-time dependency on those interfaces.
*/
private static class JettyNpnProvider implements InvocationHandler {
private static class JettyNegoProvider implements InvocationHandler {
/** This peer's supported protocols. */
private final List<String> protocols;
/** Set when remote peer notifies NPN is unsupported. */
/** Set when remote peer notifies NPN or ALPN is unsupported. */
private boolean unsupported;
/** The protocol the client selected. */
/** The protocol the client (NPN) or server (ALPN) selected. */
private String selected;
public JettyNpnProvider(List<String> protocols) {
public JettyNegoProvider(List<String> protocols) {
this.protocols = protocols;
}
@@ -322,27 +329,25 @@ public class Platform {
args = Util.EMPTY_STRING_ARRAY;
}
if (methodName.equals("supports") && boolean.class == returnType) {
return true; // Client supports NPN.
return true; // NPN or ALPN is supported.
} else if (methodName.equals("unsupported") && void.class == returnType) {
this.unsupported = true; // Remote peer doesn't support NPN.
this.unsupported = true; // Peer doesn't support NPN or ALPN.
return null;
} else if (methodName.equals("protocols") && args.length == 0) {
return protocols; // Server advertises these protocols.
} else if (methodName.equals("selectProtocol") // Called when client.
&& String.class == returnType
&& args.length == 1
&& (args[0] == null || args[0] instanceof List)) {
List<String> serverProtocols = (List) args[0];
// Pick the first protocol the server advertises and client knows.
for (int i = 0, size = serverProtocols.size(); i < size; i++) {
if (protocols.contains(serverProtocols.get(i))) {
return selected = serverProtocols.get(i);
return protocols; // Server (NPN) or Client (ALPN) advertises these protocols.
} else if ((methodName.equals("selectProtocol") || methodName.equals("select"))
&& String.class == returnType && args.length == 1 && args[0] instanceof List) {
List<String> peerProtocols = (List) args[0];
// Pick the first known protocol the peer advertises.
for (int i = 0, size = peerProtocols.size(); i < size; i++) {
if (protocols.contains(peerProtocols.get(i))) {
return selected = peerProtocols.get(i);
}
}
// On no intersection, try client's first protocol.
return selected = protocols.get(0);
} else if (methodName.equals("protocolSelected") && args.length == 1) {
this.selected = (String) args[0]; // Client selected this protocol.
return selected = protocols.get(0); // On no intersection, try peer's first protocol.
} else if ((methodName.equals("protocolSelected") || methodName.equals("selected"))
&& args.length == 1) {
this.selected = (String) args[0]; // Client (NPN) or Server (ALPN) selected this protocol.
return null;
} else {
return method.invoke(this, args);

83
pom.xml
View File

@@ -36,6 +36,8 @@
<okio.version>0.8.0</okio.version>
<!-- Targetted to jdk7u60-b13; Oracle jdk7u55-b13. -->
<npn.version>1.1.7.v20140316</npn.version>
<!-- Targetted to OpenJDK 8 b132 -->
<alpn.version>8.0.0.v20140317</alpn.version>
<bouncycastle.version>1.48</bouncycastle.version>
<gson.version>2.2.3</gson.version>
<apache.http.version>4.2.2</apache.http.version>
@@ -72,15 +74,20 @@
<artifactId>okio</artifactId>
<version>${okio.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty.npn</groupId>
<artifactId>npn-boot</artifactId>
<version>${npn.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<groupId>org.mortbay.jetty.alpn</groupId>
<artifactId>alpn-boot</artifactId>
<version>${alpn.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
@@ -126,15 +133,12 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<argLine>-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar</argLine>
</configuration>
<version>2.17</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.16</version>
<version>2.17</version>
</dependency>
</dependencies>
</plugin>
@@ -185,7 +189,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.10</version>
<version>1.11</version>
<executions>
<execution>
<phase>test</phase>
@@ -204,5 +208,66 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>npn-when-jdk7</id>
<activation>
<jdk>1.7</jdk>
</activation>
<properties>
<bootclasspath>${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar</bootclasspath>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xbootclasspath/p:${bootclasspath}</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.mortbay.jetty.npn</groupId>
<artifactId>npn-boot</artifactId>
<version>${npn.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
<profile>
<id>alpn-when-jdk8</id>
<activation>
<jdk>1.8</jdk>
</activation>
<properties>
<bootclasspath>${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar</bootclasspath>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xbootclasspath/p:${bootclasspath}</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.mortbay.jetty.alpn</groupId>
<artifactId>alpn-boot</artifactId>
<version>${alpn.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
</project>

View File

@@ -58,7 +58,7 @@
common connection problems. If your service has multiple IP addresses OkHttp will
attempt alternate addresses if the first connect fails. This is necessary for IPv4+IPv6
and for services hosted in redundant data centers. OkHttp initiates new connections
with modern TLS features (SNI, NPN), and falls back to SSLv3 if the handshake
with modern TLS features (SNI, ALPN), and falls back to SSLv3 if the handshake
fails.</p>
<p>You can try OkHttp without rewriting your network code. The core module implements