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.
*/
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(
Arrays.asList(
Http2OrHttpChooser.SelectedProtocol.HTTP_2.protocolName(),
"h2-14",
"h2-15",
"h2-16"));

View File

@ -42,6 +42,7 @@ import java.net.ProxySelector;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
@ -52,6 +53,10 @@ import javax.net.ssl.SSLSocketFactory;
*/
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.
private static final InetSocketAddress DUMMY_INET_SOCKET_ADDRESS =
InetSocketAddress.createUnresolved("fake", 73);
@ -69,21 +74,27 @@ public final class OkHttpTlsUpgrader {
spec.apply(sslSocket, getOkHttpRoute(host, port, spec));
Platform platform = Platform.get();
try {
// Force handshake.
sslSocket.startHandshake();
// 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) {
String negotiatedProtocol = platform.getSelectedProtocol(sslSocket);
if (negotiatedProtocol == null) {
throw new RuntimeException("protocol negotiation failed");
try {
// Force handshake.
sslSocket.startHandshake();
negotiatedProtocol = platform.getSelectedProtocol(sslSocket);
if (negotiatedProtocol == null) {
throw new RuntimeException("protocol negotiation failed");
}
} finally {
platform.afterHandshake(sslSocket);
}
Preconditions.checkState(Protocol.HTTP_2.equals(Protocol.get(negotiatedProtocol)),
"negotiated protocol is %s instead of %s.",
negotiatedProtocol, Protocol.HTTP_2.toString());
} finally {
platform.afterHandshake(sslSocket);
}
Preconditions.checkState(SUPPORTED_HTTP2_PROTOCOLS.contains(negotiatedProtocol),
"negotiated protocol %s is unsupported", negotiatedProtocol);
return sslSocket;
}