From Russia v1.0版本的 MD5 值为:52aeb8738ddf971390ea1486e59c6ccd
以下内容为反编译后的 OkHttpClientTransport.java 源代码,内容仅作参考
package io.grpc.okhttp;
import com.google.android.gms.common.internal.ServiceSpecificExtraArgs;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.google.common.base.Supplier;
import com.google.common.net.HttpHeaders;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes;
import io.grpc.CallOptions;
import io.grpc.ClientStreamTracer;
import io.grpc.Grpc;
import io.grpc.HttpConnectProxiedSocketAddress;
import io.grpc.InternalChannelz;
import io.grpc.InternalLogId;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.SecurityLevel;
import io.grpc.Status;
import io.grpc.StatusException;
import io.grpc.internal.ClientStream;
import io.grpc.internal.ClientStreamListener;
import io.grpc.internal.ClientTransport;
import io.grpc.internal.ConnectionClientTransport;
import io.grpc.internal.GrpcAttributes;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.Http2Ping;
import io.grpc.internal.InUseStateAggregator;
import io.grpc.internal.KeepAliveManager;
import io.grpc.internal.ManagedClientTransport;
import io.grpc.internal.SerializingExecutor;
import io.grpc.internal.StatsTraceContext;
import io.grpc.internal.TransportTracer;
import io.grpc.okhttp.ExceptionHandlingFrameWriter;
import io.grpc.okhttp.OkHttpChannelBuilder;
import io.grpc.okhttp.OkHttpFrameLogger;
import io.grpc.okhttp.OutboundFlowController;
import io.grpc.okhttp.internal.ConnectionSpec;
import io.grpc.okhttp.internal.Credentials;
import io.grpc.okhttp.internal.StatusLine;
import io.grpc.okhttp.internal.framed.ErrorCode;
import io.grpc.okhttp.internal.framed.FrameReader;
import io.grpc.okhttp.internal.framed.FrameWriter;
import io.grpc.okhttp.internal.framed.Header;
import io.grpc.okhttp.internal.framed.HeadersMode;
import io.grpc.okhttp.internal.framed.Http2;
import io.grpc.okhttp.internal.framed.Settings;
import io.grpc.okhttp.internal.framed.Variant;
import io.grpc.okhttp.internal.proxy.HttpUrl;
import io.grpc.okhttp.internal.proxy.Request;
import io.perfmark.PerfMark;
import java.io.EOFException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.util.Collections;
import java.util.Deque;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import net.lingala.zip4j.util.InternalZipConstants;
import okio.Buffer;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.ByteString;
import okio.Okio;
import okio.Source;
import okio.Timeout;
import org.ini4j.Registry;
public class OkHttpClientTransport implements ConnectionClientTransport, ExceptionHandlingFrameWriter.TransportExceptionHandler, OutboundFlowController.Transport {
private static final Map<ErrorCode, Status> ERROR_CODE_TO_STATUS = buildErrorCodeToStatusMap();
private static final Logger log = Logger.getLogger(OkHttpClientTransport.class.getName());
private final InetSocketAddress address;
private Attributes attributes;
private ClientFrameHandler clientFrameHandler;
SettableFuture<Void> connectedFuture;
Runnable connectingCallback;
private final ConnectionSpec connectionSpec;
private int connectionUnacknowledgedBytesRead;
private final String defaultAuthority;
private boolean enableKeepAlive;
private final Executor executor;
private ExceptionHandlingFrameWriter frameWriter;
private boolean goAwaySent;
private Status goAwayStatus;
private boolean hasStream;
private HostnameVerifier hostnameVerifier;
private final InUseStateAggregator<OkHttpClientStream> inUseState;
private final int initialWindowSize;
private KeepAliveManager keepAliveManager;
private long keepAliveTimeNanos;
private long keepAliveTimeoutNanos;
private boolean keepAliveWithoutCalls;
private ManagedClientTransport.Listener listener;
private final Object lock;
private final InternalLogId logId;
private int maxConcurrentStreams;
private final int maxInboundMetadataSize;
private final int maxMessageSize;
private int nextStreamId;
private OutboundFlowController outboundFlow;
private final Deque<OkHttpClientStream> pendingStreams;
private Http2Ping ping;
@Nullable
final HttpConnectProxiedSocketAddress proxiedAddr;
int proxySocketTimeout;
private final Random random;
private final ScheduledExecutorService scheduler;
private InternalChannelz.Security securityInfo;
private final SerializingExecutor serializingExecutor;
private Socket socket;
private final SocketFactory socketFactory;
private SSLSocketFactory sslSocketFactory;
private boolean stopped;
private final Supplier<Stopwatch> stopwatchFactory;
private final Map<Integer, OkHttpClientStream> streams;
private final Runnable tooManyPingsRunnable;
private final TransportTracer transportTracer;
private final boolean useGetForSafeMethods;
private final String userAgent;
private final Variant variant;
static int access$2412(OkHttpClientTransport x0, int x1) {
int i = x0.connectionUnacknowledgedBytesRead + x1;
x0.connectionUnacknowledgedBytesRead = i;
return i;
}
@Override
public ClientStream newStream(MethodDescriptor methodDescriptor, Metadata metadata, CallOptions callOptions, ClientStreamTracer[] clientStreamTracerArr) {
return newStream((MethodDescriptor<?, ?>) methodDescriptor, metadata, callOptions, clientStreamTracerArr);
}
private static Map<ErrorCode, Status> buildErrorCodeToStatusMap() {
Map<ErrorCode, Status> errorToStatus = new EnumMap<>(ErrorCode.class);
errorToStatus.put(ErrorCode.NO_ERROR, Status.INTERNAL.withDescription("No error: A GRPC status of OK should have been sent"));
errorToStatus.put(ErrorCode.PROTOCOL_ERROR, Status.INTERNAL.withDescription("Protocol error"));
errorToStatus.put(ErrorCode.INTERNAL_ERROR, Status.INTERNAL.withDescription("Internal error"));
errorToStatus.put(ErrorCode.FLOW_CONTROL_ERROR, Status.INTERNAL.withDescription("Flow control error"));
errorToStatus.put(ErrorCode.STREAM_CLOSED, Status.INTERNAL.withDescription("Stream closed"));
errorToStatus.put(ErrorCode.FRAME_TOO_LARGE, Status.INTERNAL.withDescription("Frame too large"));
errorToStatus.put(ErrorCode.REFUSED_STREAM, Status.UNAVAILABLE.withDescription("Refused stream"));
errorToStatus.put(ErrorCode.CANCEL, Status.CANCELLED.withDescription("Cancelled"));
errorToStatus.put(ErrorCode.COMPRESSION_ERROR, Status.INTERNAL.withDescription("Compression error"));
errorToStatus.put(ErrorCode.CONNECT_ERROR, Status.INTERNAL.withDescription("Connect error"));
errorToStatus.put(ErrorCode.ENHANCE_YOUR_CALM, Status.RESOURCE_EXHAUSTED.withDescription("Enhance your calm"));
errorToStatus.put(ErrorCode.INADEQUATE_SECURITY, Status.PERMISSION_DENIED.withDescription("Inadequate security"));
return Collections.unmodifiableMap(errorToStatus);
}
public OkHttpClientTransport(OkHttpChannelBuilder.OkHttpTransportFactory transportFactory, InetSocketAddress address, String authority, @Nullable String userAgent, Attributes eagAttrs, @Nullable HttpConnectProxiedSocketAddress proxiedAddr, Runnable tooManyPingsRunnable) {
this(transportFactory, address, authority, userAgent, eagAttrs, GrpcUtil.STOPWATCH_SUPPLIER, new Http2(), proxiedAddr, tooManyPingsRunnable);
}
private OkHttpClientTransport(OkHttpChannelBuilder.OkHttpTransportFactory transportFactory, InetSocketAddress address, String authority, @Nullable String userAgent, Attributes eagAttrs, Supplier<Stopwatch> stopwatchFactory, Variant variant, @Nullable HttpConnectProxiedSocketAddress proxiedAddr, Runnable tooManyPingsRunnable) {
this.random = new Random();
this.lock = new Object();
this.streams = new HashMap();
this.maxConcurrentStreams = 0;
this.pendingStreams = new LinkedList();
this.inUseState = new InUseStateAggregator<OkHttpClientStream>() {
@Override
protected void handleInUse() {
OkHttpClientTransport.this.listener.transportInUse(true);
}
@Override
protected void handleNotInUse() {
OkHttpClientTransport.this.listener.transportInUse(false);
}
};
this.proxySocketTimeout = 30000;
this.address = (InetSocketAddress) Preconditions.checkNotNull(address, "address");
this.defaultAuthority = authority;
this.maxMessageSize = transportFactory.maxMessageSize;
this.initialWindowSize = transportFactory.flowControlWindow;
this.executor = (Executor) Preconditions.checkNotNull(transportFactory.executor, "executor");
this.serializingExecutor = new SerializingExecutor(transportFactory.executor);
this.scheduler = (ScheduledExecutorService) Preconditions.checkNotNull(transportFactory.scheduledExecutorService, "scheduledExecutorService");
this.nextStreamId = 3;
this.socketFactory = transportFactory.socketFactory == null ? SocketFactory.getDefault() : transportFactory.socketFactory;
this.sslSocketFactory = transportFactory.sslSocketFactory;
this.hostnameVerifier = transportFactory.hostnameVerifier;
this.connectionSpec = (ConnectionSpec) Preconditions.checkNotNull(transportFactory.connectionSpec, "connectionSpec");
this.stopwatchFactory = (Supplier) Preconditions.checkNotNull(stopwatchFactory, "stopwatchFactory");
this.variant = (Variant) Preconditions.checkNotNull(variant, "variant");
this.userAgent = GrpcUtil.getGrpcUserAgent("okhttp", userAgent);
this.proxiedAddr = proxiedAddr;
this.tooManyPingsRunnable = (Runnable) Preconditions.checkNotNull(tooManyPingsRunnable, "tooManyPingsRunnable");
this.maxInboundMetadataSize = transportFactory.maxInboundMetadataSize;
this.transportTracer = transportFactory.transportTracerFactory.create();
this.logId = InternalLogId.allocate(getClass(), address.toString());
this.attributes = Attributes.newBuilder().set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, eagAttrs).build();
this.useGetForSafeMethods = transportFactory.useGetForSafeMethods;
initTransportTracer();
}
OkHttpClientTransport(OkHttpChannelBuilder.OkHttpTransportFactory transportFactory, String userAgent, Supplier<Stopwatch> stopwatchFactory, Variant variant, @Nullable Runnable connectingCallback, SettableFuture<Void> connectedFuture, Runnable tooManyPingsRunnable) {
this(transportFactory, new InetSocketAddress("127.0.0.1", 80), "notarealauthority:80", userAgent, Attributes.EMPTY, stopwatchFactory, variant, null, tooManyPingsRunnable);
this.connectingCallback = connectingCallback;
this.connectedFuture = (SettableFuture) Preconditions.checkNotNull(connectedFuture, "connectedFuture");
}
public boolean isUsingPlaintext() {
return this.sslSocketFactory == null;
}
private void initTransportTracer() {
synchronized (this.lock) {
this.transportTracer.setFlowControlWindowReader(new TransportTracer.FlowControlReader() {
@Override
public TransportTracer.FlowControlWindows read() {
TransportTracer.FlowControlWindows flowControlWindows;
synchronized (OkHttpClientTransport.this.lock) {
long local = OkHttpClientTransport.this.outboundFlow == null ? -1L : OkHttpClientTransport.this.outboundFlow.windowUpdate(null, 0);
long remote = OkHttpClientTransport.this.initialWindowSize * 0.5f;
flowControlWindows = new TransportTracer.FlowControlWindows(local, remote);
}
return flowControlWindows;
}
});
}
}
public void enableKeepAlive(boolean enable, long keepAliveTimeNanos, long keepAliveTimeoutNanos, boolean keepAliveWithoutCalls) {
this.enableKeepAlive = enable;
this.keepAliveTimeNanos = keepAliveTimeNanos;
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
this.keepAliveWithoutCalls = keepAliveWithoutCalls;
}
@Override
public void ping(ClientTransport.PingCallback callback, Executor executor) {
Http2Ping p;
long data = 0;
synchronized (this.lock) {
Preconditions.checkState(this.frameWriter != null);
if (this.stopped) {
Http2Ping.notifyFailed(callback, executor, getPingFailure());
return;
}
Http2Ping p2 = this.ping;
if (p2 != null) {
p = null;
} else {
data = this.random.nextLong();
Stopwatch stopwatch = this.stopwatchFactory.get();
stopwatch.start();
Http2Ping p3 = new Http2Ping(data, stopwatch);
this.ping = p3;
this.transportTracer.reportKeepAliveSent();
p2 = p3;
p = 1;
}
if (p != null) {
this.frameWriter.ping(false, (int) (data >>> 32), (int) data);
}
p2.addCallback(callback, executor);
}
}
@Override
public OkHttpClientStream newStream(MethodDescriptor<?, ?> method, Metadata headers, CallOptions callOptions, ClientStreamTracer[] tracers) {
Preconditions.checkNotNull(method, "method");
Preconditions.checkNotNull(headers, "headers");
StatsTraceContext statsTraceContext = StatsTraceContext.newClientContext(tracers, getAttributes(), headers);
synchronized (this.lock) {
try {
try {
return new OkHttpClientStream(method, headers, this.frameWriter, this, this.outboundFlow, this.lock, this.maxMessageSize, this.initialWindowSize, this.defaultAuthority, this.userAgent, statsTraceContext, this.transportTracer, callOptions, this.useGetForSafeMethods);
} catch (Throwable th) {
th = th;
throw th;
}
} catch (Throwable th2) {
th = th2;
}
}
}
public void streamReadyToStart(OkHttpClientStream clientStream) {
if (this.goAwayStatus != null) {
clientStream.transportState().transportReportStatus(this.goAwayStatus, ClientStreamListener.RpcProgress.MISCARRIED, true, new Metadata());
} else if (this.streams.size() >= this.maxConcurrentStreams) {
this.pendingStreams.add(clientStream);
setInUse(clientStream);
} else {
startStream(clientStream);
}
}
private void startStream(OkHttpClientStream stream) {
Preconditions.checkState(stream.transportState().id() == -1, "StreamId already assigned");
this.streams.put(Integer.valueOf(this.nextStreamId), stream);
setInUse(stream);
stream.transportState().start(this.nextStreamId);
if ((stream.getType() != MethodDescriptor.MethodType.UNARY && stream.getType() != MethodDescriptor.MethodType.SERVER_STREAMING) || stream.useGet()) {
this.frameWriter.flush();
}
int i = this.nextStreamId;
if (i >= 2147483645) {
this.nextStreamId = Integer.MAX_VALUE;
startGoAway(Integer.MAX_VALUE, ErrorCode.NO_ERROR, Status.UNAVAILABLE.withDescription("Stream ids exhausted"));
} else {
this.nextStreamId = i + 2;
}
}
public boolean startPendingStreams() {
boolean hasStreamStarted = false;
while (!this.pendingStreams.isEmpty() && this.streams.size() < this.maxConcurrentStreams) {
OkHttpClientStream stream = this.pendingStreams.poll();
startStream(stream);
hasStreamStarted = true;
}
return hasStreamStarted;
}
public void removePendingStream(OkHttpClientStream pendingStream) {
this.pendingStreams.remove(pendingStream);
maybeClearInUse(pendingStream);
}
@Override
public Runnable start(ManagedClientTransport.Listener listener) {
this.listener = (ManagedClientTransport.Listener) Preconditions.checkNotNull(listener, ServiceSpecificExtraArgs.CastExtraArgs.LISTENER);
if (this.enableKeepAlive) {
KeepAliveManager keepAliveManager = new KeepAliveManager(new KeepAliveManager.ClientKeepAlivePinger(this), this.scheduler, this.keepAliveTimeNanos, this.keepAliveTimeoutNanos, this.keepAliveWithoutCalls);
this.keepAliveManager = keepAliveManager;
keepAliveManager.onTransportStarted();
}
final AsyncSink asyncSink = AsyncSink.sink(this.serializingExecutor, this, 10000);
FrameWriter rawFrameWriter = asyncSink.limitControlFramesWriter(this.variant.newWriter(Okio.buffer(asyncSink), true));
synchronized (this.lock) {
ExceptionHandlingFrameWriter exceptionHandlingFrameWriter = new ExceptionHandlingFrameWriter(this, rawFrameWriter);
this.frameWriter = exceptionHandlingFrameWriter;
this.outboundFlow = new OutboundFlowController(this, exceptionHandlingFrameWriter);
}
final CountDownLatch latch = new CountDownLatch(1);
this.serializingExecutor.execute(new Runnable() {
@Override
public void run() {
Socket sock;
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
BufferedSource source = Okio.buffer(new Source() {
@Override
public long read(Buffer sink, long byteCount) {
return -1L;
}
@Override
public Timeout timeout() {
return Timeout.NONE;
}
@Override
public void close() {
}
});
SSLSession sslSession = null;
try {
try {
try {
if (OkHttpClientTransport.this.proxiedAddr == null) {
sock = OkHttpClientTransport.this.socketFactory.createSocket(OkHttpClientTransport.this.address.getAddress(), OkHttpClientTransport.this.address.getPort());
} else {
if (!(OkHttpClientTransport.this.proxiedAddr.getProxyAddress() instanceof InetSocketAddress)) {
throw Status.INTERNAL.withDescription("Unsupported SocketAddress implementation " + OkHttpClientTransport.this.proxiedAddr.getProxyAddress().getClass()).asException();
}
OkHttpClientTransport okHttpClientTransport = OkHttpClientTransport.this;
sock = okHttpClientTransport.createHttpProxySocket(okHttpClientTransport.proxiedAddr.getTargetAddress(), (InetSocketAddress) OkHttpClientTransport.this.proxiedAddr.getProxyAddress(), OkHttpClientTransport.this.proxiedAddr.getUsername(), OkHttpClientTransport.this.proxiedAddr.getPassword());
}
if (OkHttpClientTransport.this.sslSocketFactory != null) {
SSLSocket sslSocket = OkHttpTlsUpgrader.upgrade(OkHttpClientTransport.this.sslSocketFactory, OkHttpClientTransport.this.hostnameVerifier, sock, OkHttpClientTransport.this.getOverridenHost(), OkHttpClientTransport.this.getOverridenPort(), OkHttpClientTransport.this.connectionSpec);
sslSession = sslSocket.getSession();
sock = sslSocket;
}
sock.setTcpNoDelay(true);
BufferedSource source2 = Okio.buffer(Okio.source(sock));
asyncSink.becomeConnected(Okio.sink(sock), sock);
OkHttpClientTransport okHttpClientTransport2 = OkHttpClientTransport.this;
okHttpClientTransport2.attributes = okHttpClientTransport2.attributes.toBuilder().set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, sock.getRemoteSocketAddress()).set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, sock.getLocalSocketAddress()).set(Grpc.TRANSPORT_ATTR_SSL_SESSION, sslSession).set(GrpcAttributes.ATTR_SECURITY_LEVEL, sslSession == null ? SecurityLevel.NONE : SecurityLevel.PRIVACY_AND_INTEGRITY).build();
OkHttpClientTransport okHttpClientTransport3 = OkHttpClientTransport.this;
okHttpClientTransport3.clientFrameHandler = new ClientFrameHandler(okHttpClientTransport3.variant.newReader(source2, true));
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientTransport.this.socket = (Socket) Preconditions.checkNotNull(sock, "socket");
if (sslSession != null) {
OkHttpClientTransport.this.securityInfo = new InternalChannelz.Security(new InternalChannelz.Tls(sslSession));
}
}
} catch (StatusException e2) {
OkHttpClientTransport.this.startGoAway(0, ErrorCode.INTERNAL_ERROR, e2.getStatus());
OkHttpClientTransport okHttpClientTransport4 = OkHttpClientTransport.this;
okHttpClientTransport4.clientFrameHandler = new ClientFrameHandler(okHttpClientTransport4.variant.newReader(source, true));
}
} catch (Exception e3) {
OkHttpClientTransport.this.onException(e3);
OkHttpClientTransport okHttpClientTransport5 = OkHttpClientTransport.this;
okHttpClientTransport5.clientFrameHandler = new ClientFrameHandler(okHttpClientTransport5.variant.newReader(source, true));
}
} catch (Throwable th) {
OkHttpClientTransport okHttpClientTransport6 = OkHttpClientTransport.this;
okHttpClientTransport6.clientFrameHandler = new ClientFrameHandler(okHttpClientTransport6.variant.newReader(source, true));
throw th;
}
}
});
try {
sendConnectionPrefaceAndSettings();
latch.countDown();
this.serializingExecutor.execute(new Runnable() {
@Override
public void run() {
if (OkHttpClientTransport.this.connectingCallback != null) {
OkHttpClientTransport.this.connectingCallback.run();
}
OkHttpClientTransport.this.executor.execute(OkHttpClientTransport.this.clientFrameHandler);
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientTransport.this.maxConcurrentStreams = Integer.MAX_VALUE;
OkHttpClientTransport.this.startPendingStreams();
}
if (OkHttpClientTransport.this.connectedFuture != null) {
OkHttpClientTransport.this.connectedFuture.set(null);
}
}
});
return null;
} catch (Throwable th) {
latch.countDown();
throw th;
}
}
private void sendConnectionPrefaceAndSettings() {
synchronized (this.lock) {
this.frameWriter.connectionPreface();
Settings settings = new Settings();
OkHttpSettingsUtil.set(settings, 7, this.initialWindowSize);
this.frameWriter.settings(settings);
if (this.initialWindowSize > 65535) {
this.frameWriter.windowUpdate(0, r2 - 65535);
}
}
}
public Socket createHttpProxySocket(InetSocketAddress address, InetSocketAddress proxyAddress, String proxyUsername, String proxyPassword) throws StatusException {
Source source;
BufferedSink sink;
Socket sock = null;
try {
if (proxyAddress.getAddress() != null) {
sock = this.socketFactory.createSocket(proxyAddress.getAddress(), proxyAddress.getPort());
} else {
sock = this.socketFactory.createSocket(proxyAddress.getHostName(), proxyAddress.getPort());
}
sock.setTcpNoDelay(true);
sock.setSoTimeout(this.proxySocketTimeout);
source = Okio.source(sock);
sink = Okio.buffer(Okio.sink(sock));
} catch (IOException e) {
e = e;
}
try {
Request proxyRequest = createHttpProxyRequest(address, proxyUsername, proxyPassword);
HttpUrl url = proxyRequest.httpUrl();
String requestLine = String.format(Locale.US, "CONNECT %s:%d HTTP/1.1", url.host(), Integer.valueOf(url.port()));
sink.writeUtf8(requestLine).writeUtf8(Registry.LINE_SEPARATOR);
int size = proxyRequest.headers().size();
for (int i = 0; i < size; i++) {
sink.writeUtf8(proxyRequest.headers().name(i)).writeUtf8(": ").writeUtf8(proxyRequest.headers().value(i)).writeUtf8(Registry.LINE_SEPARATOR);
}
sink.writeUtf8(Registry.LINE_SEPARATOR);
sink.flush();
StatusLine statusLine = StatusLine.parse(readUtf8LineStrictUnbuffered(source));
do {
} while (!readUtf8LineStrictUnbuffered(source).equals(""));
if (statusLine.code < 200 || statusLine.code >= 300) {
Buffer body = new Buffer();
try {
sock.shutdownOutput();
source.read(body, com.brorders.launcher.other.Utils.KB);
} catch (IOException ex) {
body.writeUtf8("Unable to read body: " + ex.toString());
}
try {
sock.close();
} catch (IOException e2) {
}
String message = String.format(Locale.US, "Response returned from proxy was not successful (expected 2xx, got %d %s). Response body:\n%s", Integer.valueOf(statusLine.code), statusLine.message, body.readUtf8());
throw Status.UNAVAILABLE.withDescription(message).asException();
}
sock.setSoTimeout(0);
return sock;
} catch (IOException e3) {
e = e3;
if (sock != null) {
GrpcUtil.closeQuietly(sock);
}
throw Status.UNAVAILABLE.withDescription("Failed trying to connect with proxy").withCause(e).asException();
}
}
private Request createHttpProxyRequest(InetSocketAddress address, String proxyUsername, String proxyPassword) {
HttpUrl tunnelUrl = new HttpUrl.Builder().scheme("https").host(address.getHostName()).port(address.getPort()).build();
Request.Builder request = new Request.Builder().url(tunnelUrl).header(HttpHeaders.HOST, tunnelUrl.host() + ":" + tunnelUrl.port()).header("User-Agent", this.userAgent);
if (proxyUsername != null && proxyPassword != null) {
request.header(HttpHeaders.PROXY_AUTHORIZATION, Credentials.basic(proxyUsername, proxyPassword));
}
return request.build();
}
private static String readUtf8LineStrictUnbuffered(Source source) throws IOException {
Buffer buffer = new Buffer();
while (source.read(buffer, 1L) != -1) {
if (buffer.getByte(buffer.size() - 1) == 10) {
return buffer.readUtf8LineStrict();
}
}
throw new EOFException("\\n not found: " + buffer.readByteString().hex());
}
public String toString() {
return MoreObjects.toStringHelper(this).add("logId", this.logId.getId()).add("address", this.address).toString();
}
@Override
public InternalLogId getLogId() {
return this.logId;
}
String getOverridenHost() {
URI uri = GrpcUtil.authorityToUri(this.defaultAuthority);
if (uri.getHost() != null) {
return uri.getHost();
}
return this.defaultAuthority;
}
int getOverridenPort() {
URI uri = GrpcUtil.authorityToUri(this.defaultAuthority);
if (uri.getPort() != -1) {
return uri.getPort();
}
return this.address.getPort();
}
@Override
public void shutdown(Status reason) {
synchronized (this.lock) {
if (this.goAwayStatus != null) {
return;
}
this.goAwayStatus = reason;
this.listener.transportShutdown(reason);
stopIfNecessary();
}
}
@Override
public void shutdownNow(Status reason) {
shutdown(reason);
synchronized (this.lock) {
Iterator<Map.Entry<Integer, OkHttpClientStream>> it = this.streams.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, OkHttpClientStream> entry = it.next();
it.remove();
entry.getValue().transportState().transportReportStatus(reason, false, new Metadata());
maybeClearInUse(entry.getValue());
}
for (OkHttpClientStream stream : this.pendingStreams) {
stream.transportState().transportReportStatus(reason, ClientStreamListener.RpcProgress.MISCARRIED, true, new Metadata());
maybeClearInUse(stream);
}
this.pendingStreams.clear();
stopIfNecessary();
}
}
@Override
public Attributes getAttributes() {
return this.attributes;
}
@Override
public OutboundFlowController.StreamState[] getActiveStreams() {
OutboundFlowController.StreamState[] flowStreams;
synchronized (this.lock) {
flowStreams = new OutboundFlowController.StreamState[this.streams.size()];
int i = 0;
for (OkHttpClientStream stream : this.streams.values()) {
flowStreams[i] = stream.transportState().getOutboundFlowState();
i++;
}
}
return flowStreams;
}
ClientFrameHandler getHandler() {
return this.clientFrameHandler;
}
SocketFactory getSocketFactory() {
return this.socketFactory;
}
int getPendingStreamSize() {
int size;
synchronized (this.lock) {
size = this.pendingStreams.size();
}
return size;
}
void setNextStreamId(int nextStreamId) {
synchronized (this.lock) {
this.nextStreamId = nextStreamId;
}
}
@Override
public void onException(Throwable failureCause) {
Preconditions.checkNotNull(failureCause, "failureCause");
Status status = Status.UNAVAILABLE.withCause(failureCause);
startGoAway(0, ErrorCode.INTERNAL_ERROR, status);
}
public void onError(ErrorCode errorCode, String moreDetail) {
startGoAway(0, errorCode, toGrpcStatus(errorCode).augmentDescription(moreDetail));
}
public void startGoAway(int lastKnownStreamId, ErrorCode errorCode, Status status) {
synchronized (this.lock) {
if (this.goAwayStatus == null) {
this.goAwayStatus = status;
this.listener.transportShutdown(status);
}
if (errorCode != null && !this.goAwaySent) {
this.goAwaySent = true;
this.frameWriter.goAway(0, errorCode, new byte[0]);
}
Iterator<Map.Entry<Integer, OkHttpClientStream>> it = this.streams.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, OkHttpClientStream> entry = it.next();
if (entry.getKey().intValue() > lastKnownStreamId) {
it.remove();
entry.getValue().transportState().transportReportStatus(status, ClientStreamListener.RpcProgress.REFUSED, false, new Metadata());
maybeClearInUse(entry.getValue());
}
}
for (OkHttpClientStream stream : this.pendingStreams) {
stream.transportState().transportReportStatus(status, ClientStreamListener.RpcProgress.MISCARRIED, true, new Metadata());
maybeClearInUse(stream);
}
this.pendingStreams.clear();
stopIfNecessary();
}
}
public void finishStream(int streamId, @Nullable Status status, ClientStreamListener.RpcProgress rpcProgress, boolean stopDelivery, @Nullable ErrorCode errorCode, @Nullable Metadata trailers) {
synchronized (this.lock) {
OkHttpClientStream stream = this.streams.remove(Integer.valueOf(streamId));
if (stream != null) {
if (errorCode != null) {
this.frameWriter.rstStream(streamId, ErrorCode.CANCEL);
}
if (status != null) {
stream.transportState().transportReportStatus(status, rpcProgress, stopDelivery, trailers != null ? trailers : new Metadata());
}
if (!startPendingStreams()) {
stopIfNecessary();
maybeClearInUse(stream);
}
}
}
}
private void stopIfNecessary() {
if (this.goAwayStatus == null || !this.streams.isEmpty() || !this.pendingStreams.isEmpty() || this.stopped) {
return;
}
this.stopped = true;
KeepAliveManager keepAliveManager = this.keepAliveManager;
if (keepAliveManager != null) {
keepAliveManager.onTransportTermination();
}
Http2Ping http2Ping = this.ping;
if (http2Ping != null) {
http2Ping.failed(getPingFailure());
this.ping = null;
}
if (!this.goAwaySent) {
this.goAwaySent = true;
this.frameWriter.goAway(0, ErrorCode.NO_ERROR, new byte[0]);
}
this.frameWriter.close();
}
private void maybeClearInUse(OkHttpClientStream stream) {
if (this.hasStream && this.pendingStreams.isEmpty() && this.streams.isEmpty()) {
this.hasStream = false;
KeepAliveManager keepAliveManager = this.keepAliveManager;
if (keepAliveManager != null) {
keepAliveManager.onTransportIdle();
}
}
if (stream.shouldBeCountedForInUse()) {
this.inUseState.updateObjectInUse(stream, false);
}
}
private void setInUse(OkHttpClientStream stream) {
if (!this.hasStream) {
this.hasStream = true;
KeepAliveManager keepAliveManager = this.keepAliveManager;
if (keepAliveManager != null) {
keepAliveManager.onTransportActive();
}
}
if (stream.shouldBeCountedForInUse()) {
this.inUseState.updateObjectInUse(stream, true);
}
}
private Throwable getPingFailure() {
synchronized (this.lock) {
Status status = this.goAwayStatus;
if (status != null) {
return status.asException();
}
return Status.UNAVAILABLE.withDescription("Connection closed").asException();
}
}
boolean mayHaveCreatedStream(int streamId) {
boolean z;
synchronized (this.lock) {
z = true;
if (streamId >= this.nextStreamId || (streamId & 1) != 1) {
z = false;
}
}
return z;
}
OkHttpClientStream getStream(int streamId) {
OkHttpClientStream okHttpClientStream;
synchronized (this.lock) {
okHttpClientStream = this.streams.get(Integer.valueOf(streamId));
}
return okHttpClientStream;
}
static Status toGrpcStatus(ErrorCode code) {
Status status = ERROR_CODE_TO_STATUS.get(code);
if (status != null) {
return status;
}
return Status.UNKNOWN.withDescription("Unknown http2 error code: " + code.httpCode);
}
@Override
public ListenableFuture<InternalChannelz.SocketStats> getStats() {
SettableFuture<InternalChannelz.SocketStats> ret = SettableFuture.create();
synchronized (this.lock) {
if (this.socket == null) {
ret.set(new InternalChannelz.SocketStats(this.transportTracer.getStats(), null, null, new InternalChannelz.SocketOptions.Builder().build(), null));
} else {
ret.set(new InternalChannelz.SocketStats(this.transportTracer.getStats(), this.socket.getLocalSocketAddress(), this.socket.getRemoteSocketAddress(), Utils.getSocketOptions(this.socket), this.securityInfo));
}
}
return ret;
}
class ClientFrameHandler implements FrameReader.Handler, Runnable {
FrameReader frameReader;
private final OkHttpFrameLogger logger = new OkHttpFrameLogger(Level.FINE, (Class<?>) OkHttpClientTransport.class);
boolean firstSettings = true;
ClientFrameHandler(FrameReader frameReader) {
this.frameReader = frameReader;
}
@Override
public void run() {
Status status;
String threadName = Thread.currentThread().getName();
Thread.currentThread().setName("OkHttpClientTransport");
while (this.frameReader.nextFrame(this)) {
try {
if (OkHttpClientTransport.this.keepAliveManager != null) {
OkHttpClientTransport.this.keepAliveManager.onDataReceived();
}
} catch (Throwable t) {
try {
OkHttpClientTransport.this.startGoAway(0, ErrorCode.PROTOCOL_ERROR, Status.INTERNAL.withDescription("error in frame handler").withCause(t));
} finally {
try {
this.frameReader.close();
} catch (IOException ex) {
OkHttpClientTransport.log.log(Level.INFO, "Exception closing frame reader", (Throwable) ex);
}
OkHttpClientTransport.this.listener.transportTerminated();
Thread.currentThread().setName(threadName);
}
}
}
synchronized (OkHttpClientTransport.this.lock) {
status = OkHttpClientTransport.this.goAwayStatus;
}
if (status == null) {
status = Status.UNAVAILABLE.withDescription("End of stream or IOException");
}
OkHttpClientTransport.this.startGoAway(0, ErrorCode.INTERNAL_ERROR, status);
try {
this.frameReader.close();
} catch (IOException e) {
ex = e;
}
}
@Override
public void data(boolean inFinished, int streamId, BufferedSource in, int length) throws IOException {
this.logger.logData(OkHttpFrameLogger.Direction.INBOUND, streamId, in.getBuffer(), length, inFinished);
OkHttpClientStream stream = OkHttpClientTransport.this.getStream(streamId);
if (stream == null) {
if (OkHttpClientTransport.this.mayHaveCreatedStream(streamId)) {
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientTransport.this.frameWriter.rstStream(streamId, ErrorCode.STREAM_CLOSED);
}
in.skip(length);
} else {
OkHttpClientTransport.this.onError(ErrorCode.PROTOCOL_ERROR, "Received data for unknown stream: " + streamId);
return;
}
} else {
in.require(length);
Buffer buf = new Buffer();
buf.write(in.getBuffer(), length);
PerfMark.event("OkHttpClientTransport$ClientFrameHandler.data", stream.transportState().tag());
synchronized (OkHttpClientTransport.this.lock) {
stream.transportState().transportDataReceived(buf, inFinished);
}
}
OkHttpClientTransport.access$2412(OkHttpClientTransport.this, length);
if (OkHttpClientTransport.this.connectionUnacknowledgedBytesRead >= OkHttpClientTransport.this.initialWindowSize * 0.5f) {
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientTransport.this.frameWriter.windowUpdate(0, OkHttpClientTransport.this.connectionUnacknowledgedBytesRead);
}
OkHttpClientTransport.this.connectionUnacknowledgedBytesRead = 0;
}
}
@Override
public void headers(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, List<Header> headerBlock, HeadersMode headersMode) {
Status failedStatus;
int metadataSize;
this.logger.logHeaders(OkHttpFrameLogger.Direction.INBOUND, streamId, headerBlock, inFinished);
boolean unknownStream = false;
if (OkHttpClientTransport.this.maxInboundMetadataSize != Integer.MAX_VALUE && (metadataSize = headerBlockSize(headerBlock)) > OkHttpClientTransport.this.maxInboundMetadataSize) {
Status status = Status.RESOURCE_EXHAUSTED;
Locale locale = Locale.US;
Object[] objArr = new Object[3];
objArr[0] = inFinished ? "trailer" : "header";
objArr[1] = Integer.valueOf(OkHttpClientTransport.this.maxInboundMetadataSize);
objArr[2] = Integer.valueOf(metadataSize);
Status failedStatus2 = status.withDescription(String.format(locale, "Response %s metadata larger than %d: %d", objArr));
failedStatus = failedStatus2;
} else {
failedStatus = null;
}
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientStream stream = (OkHttpClientStream) OkHttpClientTransport.this.streams.get(Integer.valueOf(streamId));
if (stream == null) {
if (OkHttpClientTransport.this.mayHaveCreatedStream(streamId)) {
OkHttpClientTransport.this.frameWriter.rstStream(streamId, ErrorCode.STREAM_CLOSED);
} else {
unknownStream = true;
}
} else if (failedStatus == null) {
PerfMark.event("OkHttpClientTransport$ClientFrameHandler.headers", stream.transportState().tag());
stream.transportState().transportHeadersReceived(headerBlock, inFinished);
} else {
if (!inFinished) {
OkHttpClientTransport.this.frameWriter.rstStream(streamId, ErrorCode.CANCEL);
}
stream.transportState().transportReportStatus(failedStatus, false, new Metadata());
}
}
if (unknownStream) {
OkHttpClientTransport.this.onError(ErrorCode.PROTOCOL_ERROR, "Received header for unknown stream: " + streamId);
}
}
private int headerBlockSize(List<Header> headerBlock) {
long size = 0;
for (int i = 0; i < headerBlock.size(); i++) {
Header header = headerBlock.get(i);
size += header.name.size() + 32 + header.value.size();
}
return (int) Math.min(size, 2147483647L);
}
@Override
public void rstStream(int streamId, ErrorCode errorCode) {
this.logger.logRstStream(OkHttpFrameLogger.Direction.INBOUND, streamId, errorCode);
Status status = OkHttpClientTransport.toGrpcStatus(errorCode).augmentDescription("Rst Stream");
boolean stopDelivery = status.getCode() == Status.Code.CANCELLED || status.getCode() == Status.Code.DEADLINE_EXCEEDED;
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientStream stream = (OkHttpClientStream) OkHttpClientTransport.this.streams.get(Integer.valueOf(streamId));
if (stream != null) {
PerfMark.event("OkHttpClientTransport$ClientFrameHandler.rstStream", stream.transportState().tag());
OkHttpClientTransport.this.finishStream(streamId, status, errorCode == ErrorCode.REFUSED_STREAM ? ClientStreamListener.RpcProgress.REFUSED : ClientStreamListener.RpcProgress.PROCESSED, stopDelivery, null, null);
}
}
}
@Override
public void settings(boolean clearPrevious, Settings settings) {
this.logger.logSettings(OkHttpFrameLogger.Direction.INBOUND, settings);
boolean outboundWindowSizeIncreased = false;
synchronized (OkHttpClientTransport.this.lock) {
if (OkHttpSettingsUtil.isSet(settings, 4)) {
int receivedMaxConcurrentStreams = OkHttpSettingsUtil.get(settings, 4);
OkHttpClientTransport.this.maxConcurrentStreams = receivedMaxConcurrentStreams;
}
if (OkHttpSettingsUtil.isSet(settings, 7)) {
int initialWindowSize = OkHttpSettingsUtil.get(settings, 7);
outboundWindowSizeIncreased = OkHttpClientTransport.this.outboundFlow.initialOutboundWindowSize(initialWindowSize);
}
if (this.firstSettings) {
OkHttpClientTransport.this.listener.transportReady();
this.firstSettings = false;
}
OkHttpClientTransport.this.frameWriter.ackSettings(settings);
if (outboundWindowSizeIncreased) {
OkHttpClientTransport.this.outboundFlow.writeStreams();
}
OkHttpClientTransport.this.startPendingStreams();
}
}
@Override
public void ping(boolean ack, int payload1, int payload2) {
long ackPayload = (payload1 << 32) | (payload2 & InternalZipConstants.ZIP_64_LIMIT);
this.logger.logPing(OkHttpFrameLogger.Direction.INBOUND, ackPayload);
if (!ack) {
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientTransport.this.frameWriter.ping(true, payload1, payload2);
}
return;
}
Http2Ping p = null;
synchronized (OkHttpClientTransport.this.lock) {
if (OkHttpClientTransport.this.ping == null) {
OkHttpClientTransport.log.warning("Received unexpected ping ack. No ping outstanding");
} else if (OkHttpClientTransport.this.ping.payload() == ackPayload) {
p = OkHttpClientTransport.this.ping;
OkHttpClientTransport.this.ping = null;
} else {
OkHttpClientTransport.log.log(Level.WARNING, String.format(Locale.US, "Received unexpected ping ack. Expecting %d, got %d", Long.valueOf(OkHttpClientTransport.this.ping.payload()), Long.valueOf(ackPayload)));
}
}
if (p != null) {
p.complete();
}
}
@Override
public void ackSettings() {
}
@Override
public void goAway(int lastGoodStreamId, ErrorCode errorCode, ByteString debugData) {
this.logger.logGoAway(OkHttpFrameLogger.Direction.INBOUND, lastGoodStreamId, errorCode, debugData);
if (errorCode == ErrorCode.ENHANCE_YOUR_CALM) {
String data = debugData.utf8();
OkHttpClientTransport.log.log(Level.WARNING, String.format("%s: Received GOAWAY with ENHANCE_YOUR_CALM. Debug data: %s", this, data));
if ("too_many_pings".equals(data)) {
OkHttpClientTransport.this.tooManyPingsRunnable.run();
}
}
Status status = GrpcUtil.Http2Error.statusForCode(errorCode.httpCode).augmentDescription("Received Goaway");
if (debugData.size() > 0) {
status = status.augmentDescription(debugData.utf8());
}
OkHttpClientTransport.this.startGoAway(lastGoodStreamId, null, status);
}
@Override
public void pushPromise(int streamId, int promisedStreamId, List<Header> requestHeaders) throws IOException {
this.logger.logPushPromise(OkHttpFrameLogger.Direction.INBOUND, streamId, promisedStreamId, requestHeaders);
synchronized (OkHttpClientTransport.this.lock) {
OkHttpClientTransport.this.frameWriter.rstStream(streamId, ErrorCode.PROTOCOL_ERROR);
}
}
@Override
public void windowUpdate(int streamId, long delta) {
this.logger.logWindowsUpdate(OkHttpFrameLogger.Direction.INBOUND, streamId, delta);
if (delta == 0) {
if (streamId == 0) {
OkHttpClientTransport.this.onError(ErrorCode.PROTOCOL_ERROR, "Received 0 flow control window increment.");
return;
} else {
OkHttpClientTransport.this.finishStream(streamId, Status.INTERNAL.withDescription("Received 0 flow control window increment."), ClientStreamListener.RpcProgress.PROCESSED, false, ErrorCode.PROTOCOL_ERROR, null);
return;
}
}
boolean unknownStream = false;
synchronized (OkHttpClientTransport.this.lock) {
if (streamId == 0) {
OkHttpClientTransport.this.outboundFlow.windowUpdate(null, (int) delta);
return;
}
OkHttpClientStream stream = (OkHttpClientStream) OkHttpClientTransport.this.streams.get(Integer.valueOf(streamId));
if (stream != null) {
OkHttpClientTransport.this.outboundFlow.windowUpdate(stream.transportState().getOutboundFlowState(), (int) delta);
} else if (!OkHttpClientTransport.this.mayHaveCreatedStream(streamId)) {
unknownStream = true;
}
if (unknownStream) {
OkHttpClientTransport.this.onError(ErrorCode.PROTOCOL_ERROR, "Received window_update for unknown stream: " + streamId);
}
}
}
@Override
public void priority(int streamId, int streamDependency, int weight, boolean exclusive) {
}
@Override
public void alternateService(int streamId, String origin, ByteString protocol, String host, int port, long maxAge) {
}
}
}