OkHttp: Temporally support multiple h2-xx protocol on client side.

Since the user provided SSLSocketFactory (especially in Android) may already do the handshake when creates the SSLSocket, and it may choose a different protocol name other than the one OkHttp is using.

Resolves #293
This commit is contained in:
Xudong Ma 2015-04-11 10:59:00 +08:00
parent 1066222eba
commit 883eb62de4
2 changed files with 24 additions and 12 deletions

View File

@ -68,10 +68,11 @@ import javax.net.ssl.SSLEngine;
* endpoint. * endpoint.
*/ */
public class Http2Negotiator { public class Http2Negotiator {
// TODO(madongfly): Remove "h2-15" and "h2-16" at a right time. // TODO(madongfly): Remove "h2-xx" at a right time.
private static final List<String> SUPPORTED_PROTOCOLS = Collections.unmodifiableList( private static final List<String> SUPPORTED_PROTOCOLS = Collections.unmodifiableList(
Arrays.asList( Arrays.asList(
Http2OrHttpChooser.SelectedProtocol.HTTP_2.protocolName(), Http2OrHttpChooser.SelectedProtocol.HTTP_2.protocolName(),
"h2-14",
"h2-15", "h2-15",
"h2-16")); "h2-16"));

View File

@ -42,6 +42,7 @@ import java.net.ProxySelector;
import java.net.Socket; import java.net.Socket;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
@ -52,6 +53,10 @@ import javax.net.ssl.SSLSocketFactory;
*/ */
public final class OkHttpTlsUpgrader { public final class OkHttpTlsUpgrader {
// TODO(madongfly): We should only support "h2" at a right time.
private static final List<String> SUPPORTED_HTTP2_PROTOCOLS = Collections.unmodifiableList(
Arrays.asList("h2", "h2-14", "h2-15", "h2-16"));
// A dummy address used to bypass null check. // A dummy address used to bypass null check.
private static final InetSocketAddress DUMMY_INET_SOCKET_ADDRESS = private static final InetSocketAddress DUMMY_INET_SOCKET_ADDRESS =
InetSocketAddress.createUnresolved("fake", 73); InetSocketAddress.createUnresolved("fake", 73);
@ -69,20 +74,26 @@ public final class OkHttpTlsUpgrader {
spec.apply(sslSocket, getOkHttpRoute(host, port, spec)); spec.apply(sslSocket, getOkHttpRoute(host, port, spec));
Platform platform = Platform.get(); Platform platform = Platform.get();
// It's possible that the user provided SSLSocketFactory has already done the handshake
// when creates the SSLSocket.
String negotiatedProtocol = platform.getSelectedProtocol(sslSocket);
if (negotiatedProtocol == null) {
try { try {
// Force handshake. // Force handshake.
sslSocket.startHandshake(); sslSocket.startHandshake();
String negotiatedProtocol = platform.getSelectedProtocol(sslSocket); negotiatedProtocol = platform.getSelectedProtocol(sslSocket);
if (negotiatedProtocol == null) { if (negotiatedProtocol == null) {
throw new RuntimeException("protocol negotiation failed"); throw new RuntimeException("protocol negotiation failed");
} }
Preconditions.checkState(Protocol.HTTP_2.equals(Protocol.get(negotiatedProtocol)),
"negotiated protocol is %s instead of %s.",
negotiatedProtocol, Protocol.HTTP_2.toString());
} finally { } finally {
platform.afterHandshake(sslSocket); platform.afterHandshake(sslSocket);
} }
}
Preconditions.checkState(SUPPORTED_HTTP2_PROTOCOLS.contains(negotiatedProtocol),
"negotiated protocol %s is unsupported", negotiatedProtocol);
return sslSocket; return sslSocket;
} }