RealConnection.java 源代码
package com.mbridge.msdk.thrid.okhttp.internal.connection;
import com.efs.sdk.base.Constants;
import com.mbridge.msdk.thrid.okhttp.Address;
import com.mbridge.msdk.thrid.okhttp.Call;
import com.mbridge.msdk.thrid.okhttp.CertificatePinner;
import com.mbridge.msdk.thrid.okhttp.Connection;
import com.mbridge.msdk.thrid.okhttp.ConnectionPool;
import com.mbridge.msdk.thrid.okhttp.ConnectionSpec;
import com.mbridge.msdk.thrid.okhttp.EventListener;
import com.mbridge.msdk.thrid.okhttp.Handshake;
import com.mbridge.msdk.thrid.okhttp.HttpUrl;
import com.mbridge.msdk.thrid.okhttp.Interceptor;
import com.mbridge.msdk.thrid.okhttp.OkHttpClient;
import com.mbridge.msdk.thrid.okhttp.Protocol;
import com.mbridge.msdk.thrid.okhttp.Request;
import com.mbridge.msdk.thrid.okhttp.Response;
import com.mbridge.msdk.thrid.okhttp.Route;
import com.mbridge.msdk.thrid.okhttp.internal.Internal;
import com.mbridge.msdk.thrid.okhttp.internal.Util;
import com.mbridge.msdk.thrid.okhttp.internal.Version;
import com.mbridge.msdk.thrid.okhttp.internal.http.HttpCodec;
import com.mbridge.msdk.thrid.okhttp.internal.http.HttpHeaders;
import com.mbridge.msdk.thrid.okhttp.internal.http1.Http1Codec;
import com.mbridge.msdk.thrid.okhttp.internal.http2.ErrorCode;
import com.mbridge.msdk.thrid.okhttp.internal.http2.Http2Codec;
import com.mbridge.msdk.thrid.okhttp.internal.http2.Http2Connection;
import com.mbridge.msdk.thrid.okhttp.internal.http2.Http2Stream;
import com.mbridge.msdk.thrid.okhttp.internal.platform.Platform;
import com.mbridge.msdk.thrid.okhttp.internal.tls.OkHostnameVerifier;
import com.mbridge.msdk.thrid.okhttp.internal.ws.RealWebSocket;
import com.mbridge.msdk.thrid.okio.BufferedSink;
import com.mbridge.msdk.thrid.okio.BufferedSource;
import com.mbridge.msdk.thrid.okio.Okio;
import com.mbridge.msdk.thrid.okio.Source;
import com.mbridge.msdk.thrid.okio.Timeout;
import com.x8zs.plugin.apache.http.HttpStatus;
import com.x8zs.plugin.apache.http.auth.AUTH;
import com.x8zs.plugin.apache.http.protocol.HTTP;
import java.io.IOException;
import java.lang.ref.Reference;
import java.net.ConnectException;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownServiceException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
public final class RealConnection extends Http2Connection.Listener implements Connection {
private static final int MAX_TUNNEL_ATTEMPTS = 21;
private static final String NPE_THROW_WITH_NULL = "throw with null exception";
private final ConnectionPool connectionPool;
private Handshake handshake;
private Http2Connection http2Connection;
public boolean noNewStreams;
private Protocol protocol;
private Socket rawSocket;
private final Route route;
private BufferedSink sink;
private Socket socket;
private BufferedSource source;
public int successCount;
public int allocationLimit = 1;
public final List<Reference<StreamAllocation>> allocations = new ArrayList();
public long idleAtNanos = Long.MAX_VALUE;
public RealConnection(ConnectionPool connectionPool, Route route) {
this.connectionPool = connectionPool;
this.route = route;
}
private void connectSocket(int i6, int i7, Call call, EventListener eventListener) throws IOException {
Socket createSocket;
Proxy proxy = this.route.proxy();
Address address = this.route.address();
if (proxy.type() != Proxy.Type.DIRECT && proxy.type() != Proxy.Type.HTTP) {
createSocket = new Socket(proxy);
} else {
createSocket = address.socketFactory().createSocket();
}
this.rawSocket = createSocket;
eventListener.connectStart(call, this.route.socketAddress(), proxy);
this.rawSocket.setSoTimeout(i7);
try {
Platform.get().connectSocket(this.rawSocket, this.route.socketAddress(), i6);
try {
this.source = Okio.buffer(Okio.source(this.rawSocket));
this.sink = Okio.buffer(Okio.sink(this.rawSocket));
} catch (NullPointerException e6) {
if (!NPE_THROW_WITH_NULL.equals(e6.getMessage())) {
} else {
throw new IOException(e6);
}
}
} catch (ConnectException e7) {
ConnectException connectException = new ConnectException("Failed to connect to " + this.route.socketAddress());
connectException.initCause(e7);
throw connectException;
}
}
private void connectTls(ConnectionSpecSelector connectionSpecSelector) throws IOException {
SSLSocket sSLSocket;
Protocol protocol;
Address address = this.route.address();
SSLSocket sSLSocket2 = null;
String str = null;
try {
try {
sSLSocket = (SSLSocket) address.sslSocketFactory().createSocket(this.rawSocket, address.url().host(), address.url().port(), true);
} catch (AssertionError e6) {
e = e6;
}
} catch (Throwable th) {
th = th;
}
try {
ConnectionSpec configureSecureSocket = connectionSpecSelector.configureSecureSocket(sSLSocket);
if (configureSecureSocket.supportsTlsExtensions()) {
Platform.get().configureTlsExtensions(sSLSocket, address.url().host(), address.protocols());
}
sSLSocket.startHandshake();
SSLSession session = sSLSocket.getSession();
Handshake handshake = Handshake.get(session);
if (!address.hostnameVerifier().verify(address.url().host(), session)) {
List<Certificate> peerCertificates = handshake.peerCertificates();
if (!peerCertificates.isEmpty()) {
X509Certificate x509Certificate = (X509Certificate) peerCertificates.get(0);
throw new SSLPeerUnverifiedException("Hostname " + address.url().host() + " not verified:\n certificate: " + CertificatePinner.pin(x509Certificate) + "\n DN: " + x509Certificate.getSubjectDN().getName() + "\n subjectAltNames: " + OkHostnameVerifier.allSubjectAltNames(x509Certificate));
}
throw new SSLPeerUnverifiedException("Hostname " + address.url().host() + " not verified (no certificates)");
}
address.certificatePinner().check(address.url().host(), handshake.peerCertificates());
if (configureSecureSocket.supportsTlsExtensions()) {
str = Platform.get().getSelectedProtocol(sSLSocket);
}
this.socket = sSLSocket;
this.source = Okio.buffer(Okio.source(sSLSocket));
this.sink = Okio.buffer(Okio.sink(this.socket));
this.handshake = handshake;
if (str != null) {
protocol = Protocol.get(str);
} else {
protocol = Protocol.HTTP_1_1;
}
this.protocol = protocol;
Platform.get().afterHandshake(sSLSocket);
} catch (AssertionError e7) {
e = e7;
if (Util.isAndroidGetsocknameError(e)) {
throw new IOException(e);
}
throw e;
} catch (Throwable th2) {
th = th2;
sSLSocket2 = sSLSocket;
if (sSLSocket2 != null) {
Platform.get().afterHandshake(sSLSocket2);
}
Util.closeQuietly((Socket) sSLSocket2);
throw th;
}
}
private void connectTunnel(int i6, int i7, int i8, Call call, EventListener eventListener) throws IOException {
Request createTunnelRequest = createTunnelRequest();
HttpUrl url = createTunnelRequest.url();
for (int i9 = 0; i9 < 21; i9++) {
connectSocket(i6, i7, call, eventListener);
createTunnelRequest = createTunnel(i7, i8, createTunnelRequest, url);
if (createTunnelRequest != null) {
Util.closeQuietly(this.rawSocket);
this.rawSocket = null;
this.sink = null;
this.source = null;
eventListener.connectEnd(call, this.route.socketAddress(), this.route.proxy(), null);
} else {
return;
}
}
}
private Request createTunnel(int i6, int i7, Request request, HttpUrl httpUrl) throws IOException {
String str = "CONNECT " + Util.hostHeader(httpUrl, true) + " HTTP/1.1";
while (true) {
Http1Codec http1Codec = new Http1Codec(null, null, this.source, this.sink);
TimeUnit timeUnit = TimeUnit.MILLISECONDS;
this.source.timeout().timeout(i6, timeUnit);
this.sink.timeout().timeout(i7, timeUnit);
http1Codec.writeRequest(request.headers(), str);
http1Codec.finishRequest();
Response build = http1Codec.readResponseHeaders(false).request(request).build();
long contentLength = HttpHeaders.contentLength(build);
if (contentLength == -1) {
contentLength = 0;
}
Source newFixedLengthSource = http1Codec.newFixedLengthSource(contentLength);
Util.skipAll(newFixedLengthSource, Integer.MAX_VALUE, timeUnit);
newFixedLengthSource.close();
int code = build.code();
if (code != 200) {
if (code == 407) {
Request authenticate = this.route.address().proxyAuthenticator().authenticate(this.route, build);
if (authenticate != null) {
if ("close".equalsIgnoreCase(build.header(HTTP.CONN_DIRECTIVE))) {
return authenticate;
}
request = authenticate;
} else {
throw new IOException("Failed to authenticate with proxy");
}
} else {
throw new IOException("Unexpected response code for CONNECT: " + build.code());
}
} else {
if (this.source.buffer().exhausted() && this.sink.buffer().exhausted()) {
return null;
}
throw new IOException("TLS tunnel buffered too many bytes!");
}
}
}
private Request createTunnelRequest() throws IOException {
Request build = new Request.Builder().url(this.route.address().url()).method("CONNECT", null).header(HTTP.TARGET_HOST, Util.hostHeader(this.route.address().url(), true)).header("Proxy-Connection", "Keep-Alive").header("User-Agent", Version.userAgent()).build();
Request authenticate = this.route.address().proxyAuthenticator().authenticate(this.route, new Response.Builder().request(build).protocol(Protocol.HTTP_1_1).code(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED).message("Preemptive Authenticate").body(Util.EMPTY_RESPONSE).sentRequestAtMillis(-1L).receivedResponseAtMillis(-1L).header(AUTH.PROXY_AUTH, "OkHttp-Preemptive").build());
if (authenticate != null) {
return authenticate;
}
return build;
}
private void establishProtocol(ConnectionSpecSelector connectionSpecSelector, int i6, Call call, EventListener eventListener) throws IOException {
if (this.route.address().sslSocketFactory() == null) {
List<Protocol> protocols = this.route.address().protocols();
Protocol protocol = Protocol.H2_PRIOR_KNOWLEDGE;
if (protocols.contains(protocol)) {
this.socket = this.rawSocket;
this.protocol = protocol;
startHttp2(i6);
return;
} else {
this.socket = this.rawSocket;
this.protocol = Protocol.HTTP_1_1;
return;
}
}
eventListener.secureConnectStart(call);
connectTls(connectionSpecSelector);
eventListener.secureConnectEnd(call, this.handshake);
if (this.protocol == Protocol.HTTP_2) {
startHttp2(i6);
}
}
private void startHttp2(int i6) throws IOException {
this.socket.setSoTimeout(0);
Http2Connection build = new Http2Connection.Builder(true).socket(this.socket, this.route.address().url().host(), this.source, this.sink).listener(this).pingIntervalMillis(i6).build();
this.http2Connection = build;
build.start();
}
public static RealConnection testConnection(ConnectionPool connectionPool, Route route, Socket socket, long j6) {
RealConnection realConnection = new RealConnection(connectionPool, route);
realConnection.socket = socket;
realConnection.idleAtNanos = j6;
return realConnection;
}
public void cancel() {
Util.closeQuietly(this.rawSocket);
}
public void connect(int i6, int i7, int i8, int i9, boolean z6, Call call, EventListener eventListener) {
if (this.protocol == null) {
List<ConnectionSpec> connectionSpecs = this.route.address().connectionSpecs();
ConnectionSpecSelector connectionSpecSelector = new ConnectionSpecSelector(connectionSpecs);
if (this.route.address().sslSocketFactory() == null) {
if (connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) {
String host = this.route.address().url().host();
if (!Platform.get().isCleartextTrafficPermitted(host)) {
throw new RouteException(new UnknownServiceException("CLEARTEXT communication to " + host + " not permitted by network security policy"));
}
} else {
throw new RouteException(new UnknownServiceException("CLEARTEXT communication not enabled for client"));
}
} else if (this.route.address().protocols().contains(Protocol.H2_PRIOR_KNOWLEDGE)) {
throw new RouteException(new UnknownServiceException("H2_PRIOR_KNOWLEDGE cannot be used with HTTPS"));
}
RouteException routeException = null;
do {
try {
} catch (IOException e6) {
e = e6;
}
try {
if (this.route.requiresTunnel()) {
connectTunnel(i6, i7, i8, call, eventListener);
if (this.rawSocket == null) {
if (!this.route.requiresTunnel() && this.rawSocket == null) {
throw new RouteException(new ProtocolException("Too many tunnel connections attempted: 21"));
}
if (this.http2Connection == null) {
synchronized (this.connectionPool) {
this.allocationLimit = this.http2Connection.maxConcurrentStreams();
}
return;
}
return;
}
} else {
try {
connectSocket(i6, i7, call, eventListener);
} catch (IOException e7) {
e = e7;
Util.closeQuietly(this.socket);
Util.closeQuietly(this.rawSocket);
this.socket = null;
this.rawSocket = null;
this.source = null;
this.sink = null;
this.handshake = null;
this.protocol = null;
this.http2Connection = null;
eventListener.connectFailed(call, this.route.socketAddress(), this.route.proxy(), null, e);
if (routeException != null) {
routeException = new RouteException(e);
} else {
routeException.addConnectException(e);
}
if (z6) {
throw routeException;
}
}
}
establishProtocol(connectionSpecSelector, i9, call, eventListener);
eventListener.connectEnd(call, this.route.socketAddress(), this.route.proxy(), this.protocol);
if (!this.route.requiresTunnel()) {
}
if (this.http2Connection == null) {
}
} catch (IOException e8) {
e = e8;
Util.closeQuietly(this.socket);
Util.closeQuietly(this.rawSocket);
this.socket = null;
this.rawSocket = null;
this.source = null;
this.sink = null;
this.handshake = null;
this.protocol = null;
this.http2Connection = null;
eventListener.connectFailed(call, this.route.socketAddress(), this.route.proxy(), null, e);
if (routeException != null) {
}
if (z6) {
}
}
} while (connectionSpecSelector.connectionFailed(e));
throw routeException;
}
throw new IllegalStateException("already connected");
}
@Override
public Handshake handshake() {
return this.handshake;
}
public boolean isEligible(Address address, @Nullable Route route) {
if (this.allocations.size() >= this.allocationLimit || this.noNewStreams || !Internal.instance.equalsNonHost(this.route.address(), address)) {
return false;
}
if (address.url().host().equals(route().address().url().host())) {
return true;
}
if (this.http2Connection == null || route == null || route.proxy().type() != Proxy.Type.DIRECT || this.route.proxy().type() != Proxy.Type.DIRECT || !this.route.socketAddress().equals(route.socketAddress()) || route.address().hostnameVerifier() != OkHostnameVerifier.INSTANCE || !supportsUrl(address.url())) {
return false;
}
try {
address.certificatePinner().check(address.url().host(), handshake().peerCertificates());
return true;
} catch (SSLPeerUnverifiedException unused) {
return false;
}
}
public boolean isHealthy(boolean z6) {
if (this.socket.isClosed() || this.socket.isInputShutdown() || this.socket.isOutputShutdown()) {
return false;
}
Http2Connection http2Connection = this.http2Connection;
if (http2Connection != null) {
return http2Connection.isHealthy(System.nanoTime());
}
if (z6) {
try {
int soTimeout = this.socket.getSoTimeout();
try {
this.socket.setSoTimeout(1);
if (this.source.exhausted()) {
return false;
}
return true;
} finally {
this.socket.setSoTimeout(soTimeout);
}
} catch (SocketTimeoutException unused) {
} catch (IOException unused2) {
return false;
}
}
return true;
}
public boolean isMultiplexed() {
if (this.http2Connection != null) {
return true;
}
return false;
}
public HttpCodec newCodec(OkHttpClient okHttpClient, Interceptor.Chain chain, StreamAllocation streamAllocation) throws SocketException {
if (this.http2Connection != null) {
return new Http2Codec(okHttpClient, chain, streamAllocation, this.http2Connection);
}
this.socket.setSoTimeout(chain.readTimeoutMillis());
Timeout timeout = this.source.timeout();
long readTimeoutMillis = chain.readTimeoutMillis();
TimeUnit timeUnit = TimeUnit.MILLISECONDS;
timeout.timeout(readTimeoutMillis, timeUnit);
this.sink.timeout().timeout(chain.writeTimeoutMillis(), timeUnit);
return new Http1Codec(okHttpClient, streamAllocation, this.source, this.sink);
}
public RealWebSocket.Streams newWebSocketStreams(final StreamAllocation streamAllocation) {
return new RealWebSocket.Streams(true, this.source, this.sink) {
@Override
public void close() throws IOException {
StreamAllocation streamAllocation2 = streamAllocation;
streamAllocation2.streamFinished(true, streamAllocation2.codec(), -1L, null);
}
};
}
@Override
public void onSettings(Http2Connection http2Connection) {
synchronized (this.connectionPool) {
this.allocationLimit = http2Connection.maxConcurrentStreams();
}
}
@Override
public void onStream(Http2Stream http2Stream) throws IOException {
http2Stream.close(ErrorCode.REFUSED_STREAM);
}
@Override
public Protocol protocol() {
return this.protocol;
}
@Override
public Route route() {
return this.route;
}
@Override
public Socket socket() {
return this.socket;
}
public boolean supportsUrl(HttpUrl httpUrl) {
if (httpUrl.port() != this.route.address().url().port()) {
return false;
}
if (httpUrl.host().equals(this.route.address().url().host())) {
return true;
}
if (this.handshake == null || !OkHostnameVerifier.INSTANCE.verify(httpUrl.host(), (X509Certificate) this.handshake.peerCertificates().get(0))) {
return false;
}
return true;
}
public String toString() {
Object obj;
StringBuilder sb = new StringBuilder();
sb.append("Connection{");
sb.append(this.route.address().url().host());
sb.append(":");
sb.append(this.route.address().url().port());
sb.append(", proxy=");
sb.append(this.route.proxy());
sb.append(" hostAddress=");
sb.append(this.route.socketAddress());
sb.append(" cipherSuite=");
Handshake handshake = this.handshake;
if (handshake != null) {
obj = handshake.cipherSuite();
} else {
obj = Constants.CP_NONE;
}
sb.append(obj);
sb.append(" protocol=");
sb.append(this.protocol);
sb.append('}');
return sb.toString();
}
}