package okhttp3.internal.http1; import android.support.v4.media.session.PlaybackStateCompat; import java.io.EOFException; import java.io.IOException; import java.net.ProtocolException; import java.util.concurrent.TimeUnit; import okhttp3.Headers; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; import okhttp3.internal.Internal; import okhttp3.internal.Util; import okhttp3.internal.connection.RealConnection; import okhttp3.internal.connection.StreamAllocation; import okhttp3.internal.http.HttpCodec; import okhttp3.internal.http.HttpHeaders; import okhttp3.internal.http.RealResponseBody; import okhttp3.internal.http.RequestLine; import okhttp3.internal.http.StatusLine; import okio.Buffer; import okio.BufferedSink; import okio.BufferedSource; import okio.ForwardingTimeout; import okio.Okio; import okio.Sink; import okio.Source; import okio.Timeout; /* loaded from: classes2.dex */ public final class Http1Codec implements HttpCodec { private static final int HEADER_LIMIT = 262144; private static final int STATE_CLOSED = 6; private static final int STATE_IDLE = 0; private static final int STATE_OPEN_REQUEST_BODY = 1; private static final int STATE_OPEN_RESPONSE_BODY = 4; private static final int STATE_READING_RESPONSE_BODY = 5; private static final int STATE_READ_RESPONSE_HEADERS = 3; private static final int STATE_WRITING_REQUEST_BODY = 2; final OkHttpClient client; final BufferedSink sink; final BufferedSource source; final StreamAllocation streamAllocation; int state = 0; private long headerLimit = PlaybackStateCompat.ACTION_SET_REPEAT_MODE; private abstract class AbstractSource implements Source { protected long bytesRead; protected boolean closed; protected final ForwardingTimeout timeout; private AbstractSource() { this.timeout = new ForwardingTimeout(Http1Codec.this.source.timeout()); this.bytesRead = 0L; } protected final void endOfInput(boolean z, IOException iOException) throws IOException { Http1Codec http1Codec = Http1Codec.this; int i = http1Codec.state; if (i == 6) { return; } if (i != 5) { throw new IllegalStateException("state: " + Http1Codec.this.state); } http1Codec.detachTimeout(this.timeout); Http1Codec http1Codec2 = Http1Codec.this; http1Codec2.state = 6; StreamAllocation streamAllocation = http1Codec2.streamAllocation; if (streamAllocation != null) { streamAllocation.streamFinished(!z, http1Codec2, this.bytesRead, iOException); } } @Override // okio.Source public long read(Buffer buffer, long j) throws IOException { try { long read = Http1Codec.this.source.read(buffer, j); if (read > 0) { this.bytesRead += read; } return read; } catch (IOException e) { endOfInput(false, e); throw e; } } @Override // okio.Source public Timeout timeout() { return this.timeout; } } private final class ChunkedSink implements Sink { private boolean closed; private final ForwardingTimeout timeout; ChunkedSink() { this.timeout = new ForwardingTimeout(Http1Codec.this.sink.timeout()); } @Override // okio.Sink, java.io.Closeable, java.lang.AutoCloseable public synchronized void close() throws IOException { if (this.closed) { return; } this.closed = true; Http1Codec.this.sink.writeUtf8("0\r\n\r\n"); Http1Codec.this.detachTimeout(this.timeout); Http1Codec.this.state = 3; } @Override // okio.Sink, java.io.Flushable public synchronized void flush() throws IOException { if (this.closed) { return; } Http1Codec.this.sink.flush(); } @Override // okio.Sink public Timeout timeout() { return this.timeout; } @Override // okio.Sink public void write(Buffer buffer, long j) throws IOException { if (this.closed) { throw new IllegalStateException("closed"); } if (j == 0) { return; } Http1Codec.this.sink.writeHexadecimalUnsignedLong(j); Http1Codec.this.sink.writeUtf8("\r\n"); Http1Codec.this.sink.write(buffer, j); Http1Codec.this.sink.writeUtf8("\r\n"); } } private class ChunkedSource extends AbstractSource { private static final long NO_CHUNK_YET = -1; private long bytesRemainingInChunk; private boolean hasMoreChunks; private final HttpUrl url; ChunkedSource(HttpUrl httpUrl) { super(); this.bytesRemainingInChunk = -1L; this.hasMoreChunks = true; this.url = httpUrl; } private void readChunkSize() throws IOException { if (this.bytesRemainingInChunk != -1) { Http1Codec.this.source.readUtf8LineStrict(); } try { this.bytesRemainingInChunk = Http1Codec.this.source.readHexadecimalUnsignedLong(); String trim = Http1Codec.this.source.readUtf8LineStrict().trim(); if (this.bytesRemainingInChunk < 0 || !(trim.isEmpty() || trim.startsWith(";"))) { throw new ProtocolException("expected chunk size and optional extensions but was \"" + this.bytesRemainingInChunk + trim + "\""); } if (this.bytesRemainingInChunk == 0) { this.hasMoreChunks = false; HttpHeaders.receiveHeaders(Http1Codec.this.client.cookieJar(), this.url, Http1Codec.this.readHeaders()); endOfInput(true, null); } } catch (NumberFormatException e) { throw new ProtocolException(e.getMessage()); } } @Override // okio.Source, java.io.Closeable, java.lang.AutoCloseable public void close() throws IOException { if (this.closed) { return; } if (this.hasMoreChunks && !Util.discard(this, 100, TimeUnit.MILLISECONDS)) { endOfInput(false, null); } this.closed = true; } @Override // okhttp3.internal.http1.Http1Codec.AbstractSource, okio.Source public long read(Buffer buffer, long j) throws IOException { if (j < 0) { throw new IllegalArgumentException("byteCount < 0: " + j); } if (this.closed) { throw new IllegalStateException("closed"); } if (!this.hasMoreChunks) { return -1L; } long j2 = this.bytesRemainingInChunk; if (j2 == 0 || j2 == -1) { readChunkSize(); if (!this.hasMoreChunks) { return -1L; } } long read = super.read(buffer, Math.min(j, this.bytesRemainingInChunk)); if (read != -1) { this.bytesRemainingInChunk -= read; return read; } ProtocolException protocolException = new ProtocolException("unexpected end of stream"); endOfInput(false, protocolException); throw protocolException; } } private final class FixedLengthSink implements Sink { private long bytesRemaining; private boolean closed; private final ForwardingTimeout timeout; FixedLengthSink(long j) { this.timeout = new ForwardingTimeout(Http1Codec.this.sink.timeout()); this.bytesRemaining = j; } @Override // okio.Sink, java.io.Closeable, java.lang.AutoCloseable public void close() throws IOException { if (this.closed) { return; } this.closed = true; if (this.bytesRemaining > 0) { throw new ProtocolException("unexpected end of stream"); } Http1Codec.this.detachTimeout(this.timeout); Http1Codec.this.state = 3; } @Override // okio.Sink, java.io.Flushable public void flush() throws IOException { if (this.closed) { return; } Http1Codec.this.sink.flush(); } @Override // okio.Sink public Timeout timeout() { return this.timeout; } @Override // okio.Sink public void write(Buffer buffer, long j) throws IOException { if (this.closed) { throw new IllegalStateException("closed"); } Util.checkOffsetAndCount(buffer.size(), 0L, j); if (j <= this.bytesRemaining) { Http1Codec.this.sink.write(buffer, j); this.bytesRemaining -= j; return; } throw new ProtocolException("expected " + this.bytesRemaining + " bytes but received " + j); } } private class FixedLengthSource extends AbstractSource { private long bytesRemaining; FixedLengthSource(long j) throws IOException { super(); this.bytesRemaining = j; if (this.bytesRemaining == 0) { endOfInput(true, null); } } @Override // okio.Source, java.io.Closeable, java.lang.AutoCloseable public void close() throws IOException { if (this.closed) { return; } if (this.bytesRemaining != 0 && !Util.discard(this, 100, TimeUnit.MILLISECONDS)) { endOfInput(false, null); } this.closed = true; } @Override // okhttp3.internal.http1.Http1Codec.AbstractSource, okio.Source public long read(Buffer buffer, long j) throws IOException { if (j < 0) { throw new IllegalArgumentException("byteCount < 0: " + j); } if (this.closed) { throw new IllegalStateException("closed"); } long j2 = this.bytesRemaining; if (j2 == 0) { return -1L; } long read = super.read(buffer, Math.min(j2, j)); if (read == -1) { ProtocolException protocolException = new ProtocolException("unexpected end of stream"); endOfInput(false, protocolException); throw protocolException; } this.bytesRemaining -= read; if (this.bytesRemaining == 0) { endOfInput(true, null); } return read; } } private class UnknownLengthSource extends AbstractSource { private boolean inputExhausted; UnknownLengthSource() { super(); } @Override // okio.Source, java.io.Closeable, java.lang.AutoCloseable public void close() throws IOException { if (this.closed) { return; } if (!this.inputExhausted) { endOfInput(false, null); } this.closed = true; } @Override // okhttp3.internal.http1.Http1Codec.AbstractSource, okio.Source public long read(Buffer buffer, long j) throws IOException { if (j < 0) { throw new IllegalArgumentException("byteCount < 0: " + j); } if (this.closed) { throw new IllegalStateException("closed"); } if (this.inputExhausted) { return -1L; } long read = super.read(buffer, j); if (read != -1) { return read; } this.inputExhausted = true; endOfInput(true, null); return -1L; } } public Http1Codec(OkHttpClient okHttpClient, StreamAllocation streamAllocation, BufferedSource bufferedSource, BufferedSink bufferedSink) { this.client = okHttpClient; this.streamAllocation = streamAllocation; this.source = bufferedSource; this.sink = bufferedSink; } private String readHeaderLine() throws IOException { String readUtf8LineStrict = this.source.readUtf8LineStrict(this.headerLimit); this.headerLimit -= readUtf8LineStrict.length(); return readUtf8LineStrict; } @Override // okhttp3.internal.http.HttpCodec public void cancel() { RealConnection connection = this.streamAllocation.connection(); if (connection != null) { connection.cancel(); } } @Override // okhttp3.internal.http.HttpCodec public Sink createRequestBody(Request request, long j) { if ("chunked".equalsIgnoreCase(request.header("Transfer-Encoding"))) { return newChunkedSink(); } if (j != -1) { return newFixedLengthSink(j); } throw new IllegalStateException("Cannot stream a request body without chunked encoding or a known content length!"); } void detachTimeout(ForwardingTimeout forwardingTimeout) { Timeout delegate = forwardingTimeout.delegate(); forwardingTimeout.setDelegate(Timeout.NONE); delegate.clearDeadline(); delegate.clearTimeout(); } @Override // okhttp3.internal.http.HttpCodec public void finishRequest() throws IOException { this.sink.flush(); } @Override // okhttp3.internal.http.HttpCodec public void flushRequest() throws IOException { this.sink.flush(); } public boolean isClosed() { return this.state == 6; } public Sink newChunkedSink() { if (this.state == 1) { this.state = 2; return new ChunkedSink(); } throw new IllegalStateException("state: " + this.state); } public Source newChunkedSource(HttpUrl httpUrl) throws IOException { if (this.state == 4) { this.state = 5; return new ChunkedSource(httpUrl); } throw new IllegalStateException("state: " + this.state); } public Sink newFixedLengthSink(long j) { if (this.state == 1) { this.state = 2; return new FixedLengthSink(j); } throw new IllegalStateException("state: " + this.state); } public Source newFixedLengthSource(long j) throws IOException { if (this.state == 4) { this.state = 5; return new FixedLengthSource(j); } throw new IllegalStateException("state: " + this.state); } public Source newUnknownLengthSource() throws IOException { if (this.state != 4) { throw new IllegalStateException("state: " + this.state); } StreamAllocation streamAllocation = this.streamAllocation; if (streamAllocation == null) { throw new IllegalStateException("streamAllocation == null"); } this.state = 5; streamAllocation.noNewStreams(); return new UnknownLengthSource(); } @Override // okhttp3.internal.http.HttpCodec public ResponseBody openResponseBody(Response response) throws IOException { StreamAllocation streamAllocation = this.streamAllocation; streamAllocation.eventListener.responseBodyStart(streamAllocation.call); String header = response.header("Content-Type"); if (!HttpHeaders.hasBody(response)) { return new RealResponseBody(header, 0L, Okio.buffer(newFixedLengthSource(0L))); } if ("chunked".equalsIgnoreCase(response.header("Transfer-Encoding"))) { return new RealResponseBody(header, -1L, Okio.buffer(newChunkedSource(response.request().url()))); } long contentLength = HttpHeaders.contentLength(response); return contentLength != -1 ? new RealResponseBody(header, contentLength, Okio.buffer(newFixedLengthSource(contentLength))) : new RealResponseBody(header, -1L, Okio.buffer(newUnknownLengthSource())); } public Headers readHeaders() throws IOException { Headers.Builder builder = new Headers.Builder(); while (true) { String readHeaderLine = readHeaderLine(); if (readHeaderLine.length() == 0) { return builder.build(); } Internal.instance.addLenient(builder, readHeaderLine); } } @Override // okhttp3.internal.http.HttpCodec public Response.Builder readResponseHeaders(boolean z) throws IOException { int i = this.state; if (i != 1 && i != 3) { throw new IllegalStateException("state: " + this.state); } try { StatusLine parse = StatusLine.parse(readHeaderLine()); Response.Builder headers = new Response.Builder().protocol(parse.protocol).code(parse.code).message(parse.message).headers(readHeaders()); if (z && parse.code == 100) { return null; } if (parse.code == 100) { this.state = 3; return headers; } this.state = 4; return headers; } catch (EOFException e) { IOException iOException = new IOException("unexpected end of stream on " + this.streamAllocation); iOException.initCause(e); throw iOException; } } public void writeRequest(Headers headers, String str) throws IOException { if (this.state != 0) { throw new IllegalStateException("state: " + this.state); } this.sink.writeUtf8(str).writeUtf8("\r\n"); int size = headers.size(); for (int i = 0; i < size; i++) { this.sink.writeUtf8(headers.name(i)).writeUtf8(": ").writeUtf8(headers.value(i)).writeUtf8("\r\n"); } this.sink.writeUtf8("\r\n"); this.state = 1; } @Override // okhttp3.internal.http.HttpCodec public void writeRequestHeaders(Request request) throws IOException { writeRequest(request.headers(), RequestLine.get(request, this.streamAllocation.connection().route().proxy().type())); } }