jimu-decompiled/sources/okhttp3/internal/http2/Http2Stream.java
2025-05-13 19:24:51 +02:00

498 lines
16 KiB
Java

package okhttp3.internal.http2;
import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import okio.AsyncTimeout;
import okio.Buffer;
import okio.BufferedSource;
import okio.Sink;
import okio.Source;
import okio.Timeout;
/* loaded from: classes2.dex */
public final class Http2Stream {
static final /* synthetic */ boolean $assertionsDisabled = false;
long bytesLeftInWriteWindow;
final Http2Connection connection;
private boolean hasResponseHeaders;
final int id;
private final List<Header> requestHeaders;
private List<Header> responseHeaders;
final FramingSink sink;
private final FramingSource source;
long unacknowledgedBytesRead = 0;
final StreamTimeout readTimeout = new StreamTimeout();
final StreamTimeout writeTimeout = new StreamTimeout();
ErrorCode errorCode = null;
final class FramingSink implements Sink {
static final /* synthetic */ boolean $assertionsDisabled = false;
private static final long EMIT_BUFFER_SIZE = 16384;
boolean closed;
boolean finished;
private final Buffer sendBuffer = new Buffer();
FramingSink() {
}
private void emitFrame(boolean z) throws IOException {
long min;
synchronized (Http2Stream.this) {
Http2Stream.this.writeTimeout.enter();
while (Http2Stream.this.bytesLeftInWriteWindow <= 0 && !this.finished && !this.closed && Http2Stream.this.errorCode == null) {
try {
Http2Stream.this.waitForIo();
} finally {
}
}
Http2Stream.this.writeTimeout.exitAndThrowIfTimedOut();
Http2Stream.this.checkOutNotClosed();
min = Math.min(Http2Stream.this.bytesLeftInWriteWindow, this.sendBuffer.size());
Http2Stream.this.bytesLeftInWriteWindow -= min;
}
Http2Stream.this.writeTimeout.enter();
try {
Http2Stream.this.connection.writeData(Http2Stream.this.id, z && min == this.sendBuffer.size(), this.sendBuffer, min);
} finally {
}
}
@Override // okio.Sink, java.io.Closeable, java.lang.AutoCloseable
public void close() throws IOException {
synchronized (Http2Stream.this) {
if (this.closed) {
return;
}
if (!Http2Stream.this.sink.finished) {
if (this.sendBuffer.size() > 0) {
while (this.sendBuffer.size() > 0) {
emitFrame(true);
}
} else {
Http2Stream http2Stream = Http2Stream.this;
http2Stream.connection.writeData(http2Stream.id, true, null, 0L);
}
}
synchronized (Http2Stream.this) {
this.closed = true;
}
Http2Stream.this.connection.flush();
Http2Stream.this.cancelStreamIfNecessary();
}
}
@Override // okio.Sink, java.io.Flushable
public void flush() throws IOException {
synchronized (Http2Stream.this) {
Http2Stream.this.checkOutNotClosed();
}
while (this.sendBuffer.size() > 0) {
emitFrame(false);
Http2Stream.this.connection.flush();
}
}
@Override // okio.Sink
public Timeout timeout() {
return Http2Stream.this.writeTimeout;
}
@Override // okio.Sink
public void write(Buffer buffer, long j) throws IOException {
this.sendBuffer.write(buffer, j);
while (this.sendBuffer.size() >= 16384) {
emitFrame(false);
}
}
}
private final class FramingSource implements Source {
static final /* synthetic */ boolean $assertionsDisabled = false;
boolean closed;
boolean finished;
private final long maxByteCount;
private final Buffer receiveBuffer = new Buffer();
private final Buffer readBuffer = new Buffer();
FramingSource(long j) {
this.maxByteCount = j;
}
private void updateConnectionFlowControl(long j) {
Http2Stream.this.connection.updateConnectionFlowControl(j);
}
private void waitUntilReadable() throws IOException {
Http2Stream.this.readTimeout.enter();
while (this.readBuffer.size() == 0 && !this.finished && !this.closed && Http2Stream.this.errorCode == null) {
try {
Http2Stream.this.waitForIo();
} finally {
Http2Stream.this.readTimeout.exitAndThrowIfTimedOut();
}
}
}
@Override // okio.Source, java.io.Closeable, java.lang.AutoCloseable
public void close() throws IOException {
long size;
synchronized (Http2Stream.this) {
this.closed = true;
size = this.readBuffer.size();
this.readBuffer.clear();
Http2Stream.this.notifyAll();
}
if (size > 0) {
updateConnectionFlowControl(size);
}
Http2Stream.this.cancelStreamIfNecessary();
}
@Override // okio.Source
public long read(Buffer buffer, long j) throws IOException {
ErrorCode errorCode;
long j2;
if (j < 0) {
throw new IllegalArgumentException("byteCount < 0: " + j);
}
synchronized (Http2Stream.this) {
waitUntilReadable();
if (this.closed) {
throw new IOException("stream closed");
}
errorCode = Http2Stream.this.errorCode;
if (this.readBuffer.size() > 0) {
j2 = this.readBuffer.read(buffer, Math.min(j, this.readBuffer.size()));
Http2Stream.this.unacknowledgedBytesRead += j2;
} else {
j2 = -1;
}
if (errorCode == null && Http2Stream.this.unacknowledgedBytesRead >= Http2Stream.this.connection.okHttpSettings.getInitialWindowSize() / 2) {
Http2Stream.this.connection.writeWindowUpdateLater(Http2Stream.this.id, Http2Stream.this.unacknowledgedBytesRead);
Http2Stream.this.unacknowledgedBytesRead = 0L;
}
}
if (j2 != -1) {
updateConnectionFlowControl(j2);
return j2;
}
if (errorCode == null) {
return -1L;
}
throw new StreamResetException(errorCode);
}
void receive(BufferedSource bufferedSource, long j) throws IOException {
boolean z;
boolean z2;
boolean z3;
while (j > 0) {
synchronized (Http2Stream.this) {
z = this.finished;
z2 = true;
z3 = this.readBuffer.size() + j > this.maxByteCount;
}
if (z3) {
bufferedSource.skip(j);
Http2Stream.this.closeLater(ErrorCode.FLOW_CONTROL_ERROR);
return;
}
if (z) {
bufferedSource.skip(j);
return;
}
long read = bufferedSource.read(this.receiveBuffer, j);
if (read == -1) {
throw new EOFException();
}
j -= read;
synchronized (Http2Stream.this) {
if (this.readBuffer.size() != 0) {
z2 = false;
}
this.readBuffer.writeAll(this.receiveBuffer);
if (z2) {
Http2Stream.this.notifyAll();
}
}
}
}
@Override // okio.Source
public Timeout timeout() {
return Http2Stream.this.readTimeout;
}
}
class StreamTimeout extends AsyncTimeout {
StreamTimeout() {
}
public void exitAndThrowIfTimedOut() throws IOException {
if (exit()) {
throw newTimeoutException(null);
}
}
@Override // okio.AsyncTimeout
protected IOException newTimeoutException(IOException iOException) {
SocketTimeoutException socketTimeoutException = new SocketTimeoutException("timeout");
if (iOException != null) {
socketTimeoutException.initCause(iOException);
}
return socketTimeoutException;
}
@Override // okio.AsyncTimeout
protected void timedOut() {
Http2Stream.this.closeLater(ErrorCode.CANCEL);
}
}
Http2Stream(int i, Http2Connection http2Connection, boolean z, boolean z2, List<Header> list) {
if (http2Connection == null) {
throw new NullPointerException("connection == null");
}
if (list == null) {
throw new NullPointerException("requestHeaders == null");
}
this.id = i;
this.connection = http2Connection;
this.bytesLeftInWriteWindow = http2Connection.peerSettings.getInitialWindowSize();
this.source = new FramingSource(http2Connection.okHttpSettings.getInitialWindowSize());
this.sink = new FramingSink();
this.source.finished = z2;
this.sink.finished = z;
this.requestHeaders = list;
}
private boolean closeInternal(ErrorCode errorCode) {
synchronized (this) {
if (this.errorCode != null) {
return false;
}
if (this.source.finished && this.sink.finished) {
return false;
}
this.errorCode = errorCode;
notifyAll();
this.connection.removeStream(this.id);
return true;
}
}
void addBytesToWriteWindow(long j) {
this.bytesLeftInWriteWindow += j;
if (j > 0) {
notifyAll();
}
}
void cancelStreamIfNecessary() throws IOException {
boolean z;
boolean isOpen;
synchronized (this) {
z = !this.source.finished && this.source.closed && (this.sink.finished || this.sink.closed);
isOpen = isOpen();
}
if (z) {
close(ErrorCode.CANCEL);
} else {
if (isOpen) {
return;
}
this.connection.removeStream(this.id);
}
}
void checkOutNotClosed() throws IOException {
FramingSink framingSink = this.sink;
if (framingSink.closed) {
throw new IOException("stream closed");
}
if (framingSink.finished) {
throw new IOException("stream finished");
}
ErrorCode errorCode = this.errorCode;
if (errorCode != null) {
throw new StreamResetException(errorCode);
}
}
public void close(ErrorCode errorCode) throws IOException {
if (closeInternal(errorCode)) {
this.connection.writeSynReset(this.id, errorCode);
}
}
public void closeLater(ErrorCode errorCode) {
if (closeInternal(errorCode)) {
this.connection.writeSynResetLater(this.id, errorCode);
}
}
public Http2Connection getConnection() {
return this.connection;
}
public synchronized ErrorCode getErrorCode() {
return this.errorCode;
}
public int getId() {
return this.id;
}
public List<Header> getRequestHeaders() {
return this.requestHeaders;
}
public Sink getSink() {
synchronized (this) {
if (!this.hasResponseHeaders && !isLocallyInitiated()) {
throw new IllegalStateException("reply before requesting the sink");
}
}
return this.sink;
}
public Source getSource() {
return this.source;
}
public boolean isLocallyInitiated() {
return this.connection.client == ((this.id & 1) == 1);
}
public synchronized boolean isOpen() {
if (this.errorCode != null) {
return false;
}
if ((this.source.finished || this.source.closed) && (this.sink.finished || this.sink.closed)) {
if (this.hasResponseHeaders) {
return false;
}
}
return true;
}
public Timeout readTimeout() {
return this.readTimeout;
}
void receiveData(BufferedSource bufferedSource, int i) throws IOException {
this.source.receive(bufferedSource, i);
}
void receiveFin() {
boolean isOpen;
synchronized (this) {
this.source.finished = true;
isOpen = isOpen();
notifyAll();
}
if (isOpen) {
return;
}
this.connection.removeStream(this.id);
}
void receiveHeaders(List<Header> list) {
boolean z;
synchronized (this) {
z = true;
this.hasResponseHeaders = true;
if (this.responseHeaders == null) {
this.responseHeaders = list;
z = isOpen();
notifyAll();
} else {
ArrayList arrayList = new ArrayList();
arrayList.addAll(this.responseHeaders);
arrayList.add(null);
arrayList.addAll(list);
this.responseHeaders = arrayList;
}
}
if (z) {
return;
}
this.connection.removeStream(this.id);
}
synchronized void receiveRstStream(ErrorCode errorCode) {
if (this.errorCode == null) {
this.errorCode = errorCode;
notifyAll();
}
}
public void sendResponseHeaders(List<Header> list, boolean z) throws IOException {
boolean z2;
boolean z3;
if (list == null) {
throw new NullPointerException("responseHeaders == null");
}
synchronized (this) {
this.hasResponseHeaders = true;
if (z) {
z2 = false;
z3 = false;
} else {
this.sink.finished = true;
z2 = true;
z3 = true;
}
}
if (!z2) {
synchronized (this.connection) {
z2 = this.connection.bytesLeftInWriteWindow == 0;
}
}
this.connection.writeSynReply(this.id, z3, list);
if (z2) {
this.connection.flush();
}
}
public synchronized List<Header> takeResponseHeaders() throws IOException {
List<Header> list;
if (!isLocallyInitiated()) {
throw new IllegalStateException("servers cannot read response headers");
}
this.readTimeout.enter();
while (this.responseHeaders == null && this.errorCode == null) {
try {
waitForIo();
} catch (Throwable th) {
this.readTimeout.exitAndThrowIfTimedOut();
throw th;
}
}
this.readTimeout.exitAndThrowIfTimedOut();
list = this.responseHeaders;
if (list == null) {
throw new StreamResetException(this.errorCode);
}
this.responseHeaders = null;
return list;
}
void waitForIo() throws InterruptedIOException {
try {
wait();
} catch (InterruptedException unused) {
Thread.currentThread().interrupt();
throw new InterruptedIOException();
}
}
public Timeout writeTimeout() {
return this.writeTimeout;
}
}