Http2Stream.java 源代码
package com.mbridge.msdk.thrid.okhttp.internal.http2;
import com.mbridge.msdk.thrid.okhttp.Headers;
import com.mbridge.msdk.thrid.okhttp.internal.Util;
import com.mbridge.msdk.thrid.okhttp.internal.http2.Header;
import com.mbridge.msdk.thrid.okio.AsyncTimeout;
import com.mbridge.msdk.thrid.okio.Buffer;
import com.mbridge.msdk.thrid.okio.BufferedSource;
import com.mbridge.msdk.thrid.okio.Sink;
import com.mbridge.msdk.thrid.okio.Source;
import com.mbridge.msdk.thrid.okio.Timeout;
import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketTimeoutException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
public final class Http2Stream {
static final boolean $assertionsDisabled = false;
long bytesLeftInWriteWindow;
final Http2Connection connection;
ErrorCode errorCode;
private boolean hasResponseHeaders;
private Header.Listener headersListener;
private final Deque<Headers> headersQueue;
final int id;
final StreamTimeout readTimeout;
final FramingSink sink;
private final FramingSource source;
long unacknowledgedBytesRead = 0;
final StreamTimeout writeTimeout;
public final class FramingSink implements Sink {
static final 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 z6) throws IOException {
Http2Stream http2Stream;
long min;
Http2Stream http2Stream2;
boolean z7;
synchronized (Http2Stream.this) {
Http2Stream.this.writeTimeout.enter();
while (true) {
try {
http2Stream = Http2Stream.this;
if (http2Stream.bytesLeftInWriteWindow > 0 || this.finished || this.closed || http2Stream.errorCode != null) {
break;
} else {
http2Stream.waitForIo();
}
} finally {
}
}
http2Stream.writeTimeout.exitAndThrowIfTimedOut();
Http2Stream.this.checkOutNotClosed();
min = Math.min(Http2Stream.this.bytesLeftInWriteWindow, this.sendBuffer.size());
http2Stream2 = Http2Stream.this;
http2Stream2.bytesLeftInWriteWindow -= min;
}
http2Stream2.writeTimeout.enter();
try {
Http2Stream http2Stream3 = Http2Stream.this;
Http2Connection http2Connection = http2Stream3.connection;
int i6 = http2Stream3.id;
if (z6 && min == this.sendBuffer.size()) {
z7 = true;
} else {
z7 = false;
}
http2Connection.writeData(i6, z7, this.sendBuffer, min);
} finally {
}
}
@Override
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
public void flush() throws IOException {
synchronized (Http2Stream.this) {
Http2Stream.this.checkOutNotClosed();
}
while (this.sendBuffer.size() > 0) {
emitFrame(false);
Http2Stream.this.connection.flush();
}
}
@Override
public Timeout timeout() {
return Http2Stream.this.writeTimeout;
}
@Override
public void write(Buffer buffer, long j6) throws IOException {
this.sendBuffer.write(buffer, j6);
while (this.sendBuffer.size() >= EMIT_BUFFER_SIZE) {
emitFrame(false);
}
}
}
public final class FramingSource implements Source {
static final 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 j6) {
this.maxByteCount = j6;
}
private void updateConnectionFlowControl(long j6) {
Http2Stream.this.connection.updateConnectionFlowControl(j6);
}
@Override
public void close() throws IOException {
long size;
ArrayList arrayList;
Header.Listener listener;
synchronized (Http2Stream.this) {
this.closed = true;
size = this.readBuffer.size();
this.readBuffer.clear();
if (!Http2Stream.this.headersQueue.isEmpty() && Http2Stream.this.headersListener != null) {
arrayList = new ArrayList(Http2Stream.this.headersQueue);
Http2Stream.this.headersQueue.clear();
listener = Http2Stream.this.headersListener;
} else {
arrayList = null;
listener = null;
}
Http2Stream.this.notifyAll();
}
if (size > 0) {
updateConnectionFlowControl(size);
}
Http2Stream.this.cancelStreamIfNecessary();
if (listener != null) {
Iterator it = arrayList.iterator();
while (it.hasNext()) {
listener.onHeaders((Headers) it.next());
}
}
}
@Override
public long read(Buffer buffer, long j6) throws IOException {
ErrorCode errorCode;
long read;
Headers headers;
Header.Listener listener;
if (j6 >= 0) {
while (true) {
synchronized (Http2Stream.this) {
Http2Stream.this.readTimeout.enter();
try {
Http2Stream http2Stream = Http2Stream.this;
errorCode = http2Stream.errorCode;
if (errorCode == null) {
errorCode = null;
}
if (!this.closed) {
if (!http2Stream.headersQueue.isEmpty() && Http2Stream.this.headersListener != null) {
headers = (Headers) Http2Stream.this.headersQueue.removeFirst();
listener = Http2Stream.this.headersListener;
} else if (this.readBuffer.size() > 0) {
Buffer buffer2 = this.readBuffer;
read = buffer2.read(buffer, Math.min(j6, buffer2.size()));
Http2Stream http2Stream2 = Http2Stream.this;
long j7 = http2Stream2.unacknowledgedBytesRead + read;
http2Stream2.unacknowledgedBytesRead = j7;
if (errorCode == null && j7 >= http2Stream2.connection.okHttpSettings.getInitialWindowSize() / 2) {
Http2Stream http2Stream3 = Http2Stream.this;
http2Stream3.connection.writeWindowUpdateLater(http2Stream3.id, http2Stream3.unacknowledgedBytesRead);
Http2Stream.this.unacknowledgedBytesRead = 0L;
}
headers = null;
listener = null;
if (headers == null || listener == null) {
break;
}
listener.onHeaders(headers);
} else if (!this.finished && errorCode == null) {
Http2Stream.this.waitForIo();
Http2Stream.this.readTimeout.exitAndThrowIfTimedOut();
} else {
headers = null;
listener = null;
}
read = -1;
if (headers == null) {
break;
}
break;
}
break;
} finally {
}
}
}
if (read != -1) {
updateConnectionFlowControl(read);
return read;
}
if (errorCode == null) {
return -1L;
}
throw new StreamResetException(errorCode);
}
throw new IllegalArgumentException("byteCount < 0: " + j6);
}
void receive(BufferedSource bufferedSource, long j6) throws IOException {
boolean z6;
boolean z7;
boolean z8;
long j7;
while (j6 > 0) {
synchronized (Http2Stream.this) {
z6 = this.finished;
z7 = true;
if (this.readBuffer.size() + j6 > this.maxByteCount) {
z8 = true;
} else {
z8 = false;
}
}
if (z8) {
bufferedSource.skip(j6);
Http2Stream.this.closeLater(ErrorCode.FLOW_CONTROL_ERROR);
return;
}
if (z6) {
bufferedSource.skip(j6);
return;
}
long read = bufferedSource.read(this.receiveBuffer, j6);
if (read != -1) {
j6 -= read;
synchronized (Http2Stream.this) {
if (this.closed) {
j7 = this.receiveBuffer.size();
this.receiveBuffer.clear();
} else {
if (this.readBuffer.size() != 0) {
z7 = false;
}
this.readBuffer.writeAll(this.receiveBuffer);
if (z7) {
Http2Stream.this.notifyAll();
}
j7 = 0;
}
}
if (j7 > 0) {
updateConnectionFlowControl(j7);
}
} else {
throw new EOFException();
}
}
}
@Override
public Timeout timeout() {
return Http2Stream.this.readTimeout;
}
}
public class StreamTimeout extends AsyncTimeout {
StreamTimeout() {
}
public void exitAndThrowIfTimedOut() throws IOException {
if (!exit()) {
} else {
throw newTimeoutException(null);
}
}
@Override
protected IOException newTimeoutException(IOException iOException) {
SocketTimeoutException socketTimeoutException = new SocketTimeoutException("timeout");
if (iOException != null) {
socketTimeoutException.initCause(iOException);
}
return socketTimeoutException;
}
@Override
protected void timedOut() {
Http2Stream.this.closeLater(ErrorCode.CANCEL);
Http2Stream.this.connection.sendDegradedPingLater();
}
}
public Http2Stream(int i6, Http2Connection http2Connection, boolean z6, boolean z7, @Nullable Headers headers) {
ArrayDeque arrayDeque = new ArrayDeque();
this.headersQueue = arrayDeque;
this.readTimeout = new StreamTimeout();
this.writeTimeout = new StreamTimeout();
this.errorCode = null;
if (http2Connection != null) {
this.id = i6;
this.connection = http2Connection;
this.bytesLeftInWriteWindow = http2Connection.peerSettings.getInitialWindowSize();
FramingSource framingSource = new FramingSource(http2Connection.okHttpSettings.getInitialWindowSize());
this.source = framingSource;
FramingSink framingSink = new FramingSink();
this.sink = framingSink;
framingSource.finished = z7;
framingSink.finished = z6;
if (headers != null) {
arrayDeque.add(headers);
}
if (isLocallyInitiated() && headers != null) {
throw new IllegalStateException("locally-initiated streams shouldn't have headers yet");
}
if (!isLocallyInitiated() && headers == null) {
throw new IllegalStateException("remotely-initiated streams should have headers");
}
return;
}
throw new NullPointerException("connection == null");
}
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;
}
}
public void addBytesToWriteWindow(long j6) {
this.bytesLeftInWriteWindow += j6;
if (j6 > 0) {
notifyAll();
}
}
void cancelStreamIfNecessary() throws IOException {
boolean z6;
boolean isOpen;
synchronized (this) {
FramingSource framingSource = this.source;
if (!framingSource.finished && framingSource.closed) {
FramingSink framingSink = this.sink;
if (framingSink.finished || framingSink.closed) {
z6 = true;
isOpen = isOpen();
}
}
z6 = false;
isOpen = isOpen();
}
if (z6) {
close(ErrorCode.CANCEL);
} else if (!isOpen) {
this.connection.removeStream(this.id);
}
}
void checkOutNotClosed() throws IOException {
FramingSink framingSink = this.sink;
if (!framingSink.closed) {
if (!framingSink.finished) {
if (this.errorCode == null) {
return;
} else {
throw new StreamResetException(this.errorCode);
}
}
throw new IOException("stream finished");
}
throw new IOException("stream closed");
}
public void close(ErrorCode errorCode) throws IOException {
if (!closeInternal(errorCode)) {
return;
}
this.connection.writeSynReset(this.id, errorCode);
}
public void closeLater(ErrorCode errorCode) {
if (!closeInternal(errorCode)) {
return;
}
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 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() {
boolean z6;
if ((this.id & 1) == 1) {
z6 = true;
} else {
z6 = false;
}
if (this.connection.client == z6) {
return true;
}
return false;
}
public synchronized boolean isOpen() {
if (this.errorCode != null) {
return false;
}
FramingSource framingSource = this.source;
if (framingSource.finished || framingSource.closed) {
FramingSink framingSink = this.sink;
if (framingSink.finished || framingSink.closed) {
if (this.hasResponseHeaders) {
return false;
}
}
}
return true;
}
public Timeout readTimeout() {
return this.readTimeout;
}
public void receiveData(BufferedSource bufferedSource, int i6) throws IOException {
this.source.receive(bufferedSource, i6);
}
public void receiveFin() {
boolean isOpen;
synchronized (this) {
this.source.finished = true;
isOpen = isOpen();
notifyAll();
}
if (!isOpen) {
this.connection.removeStream(this.id);
}
}
public void receiveHeaders(List<Header> list) {
boolean isOpen;
synchronized (this) {
this.hasResponseHeaders = true;
this.headersQueue.add(Util.toHeaders(list));
isOpen = isOpen();
notifyAll();
}
if (!isOpen) {
this.connection.removeStream(this.id);
}
}
public synchronized void receiveRstStream(ErrorCode errorCode) {
if (this.errorCode == null) {
this.errorCode = errorCode;
notifyAll();
}
}
public synchronized void setHeadersListener(Header.Listener listener) {
this.headersListener = listener;
if (!this.headersQueue.isEmpty() && listener != null) {
notifyAll();
}
}
public synchronized Headers takeHeaders() throws IOException {
this.readTimeout.enter();
while (this.headersQueue.isEmpty() && this.errorCode == null) {
try {
waitForIo();
} catch (Throwable th) {
this.readTimeout.exitAndThrowIfTimedOut();
throw th;
}
}
this.readTimeout.exitAndThrowIfTimedOut();
if (!this.headersQueue.isEmpty()) {
} else {
throw new StreamResetException(this.errorCode);
}
return this.headersQueue.removeFirst();
}
void waitForIo() throws InterruptedIOException {
try {
wait();
} catch (InterruptedException unused) {
Thread.currentThread().interrupt();
throw new InterruptedIOException();
}
}
public void writeHeaders(List<Header> list, boolean z6) throws IOException {
boolean z7;
boolean z8;
boolean z9;
if (list != null) {
synchronized (this) {
z7 = true;
this.hasResponseHeaders = true;
if (!z6) {
this.sink.finished = true;
z8 = true;
z9 = true;
} else {
z8 = false;
z9 = false;
}
}
if (!z8) {
synchronized (this.connection) {
if (this.connection.bytesLeftInWriteWindow != 0) {
z7 = false;
}
}
z8 = z7;
}
this.connection.writeSynReply(this.id, z9, list);
if (z8) {
this.connection.flush();
return;
}
return;
}
throw new NullPointerException("headers == null");
}
public Timeout writeTimeout() {
return this.writeTimeout;
}
}