what-the-bank/sources/io/grpc/internal/MessageDeframer.java

514 lines
20 KiB
Java
Raw Permalink Normal View History

2024-07-27 18:17:47 +07:00
package io.grpc.internal;
import com.google.common.base.Preconditions;
import io.grpc.Codec;
import io.grpc.Decompressor;
import io.grpc.Status;
import io.grpc.internal.StreamListener;
import java.io.Closeable;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.DataFormatException;
/* loaded from: classes6.dex */
public class MessageDeframer implements Closeable, Deframer {
private static final int COMPRESSED_FLAG_MASK = 1;
private static final int HEADER_LENGTH = 5;
private static final int MAX_BUFFER_SIZE = 2097152;
private static final int RESERVED_MASK = 254;
private boolean compressedFlag;
private Decompressor decompressor;
private GzipInflatingBuffer fullStreamDecompressor;
private int inboundBodyWireSize;
private byte[] inflatedBuffer;
private int inflatedIndex;
private Listener listener;
private int maxInboundMessageSize;
private CompositeReadableBuffer nextFrame;
private long pendingDeliveries;
private final StatsTraceContext statsTraceCtx;
private final TransportTracer transportTracer;
private State state = State.HEADER;
private int requiredLength = 5;
private CompositeReadableBuffer unprocessed = new CompositeReadableBuffer();
private boolean inDelivery = false;
private int currentMessageSeqNo = -1;
private boolean closeWhenComplete = false;
private volatile boolean stopDelivery = false;
/* loaded from: classes6.dex */
public interface Listener {
void bytesRead(int i);
void deframeFailed(Throwable th);
void deframerClosed(boolean z);
void messagesAvailable(StreamListener.MessageProducer messageProducer);
}
/* JADX INFO: Access modifiers changed from: package-private */
/* loaded from: classes6.dex */
public enum State {
HEADER,
BODY
}
public MessageDeframer(Listener listener, Decompressor decompressor, int i, StatsTraceContext statsTraceContext, TransportTracer transportTracer) {
this.listener = (Listener) Preconditions.checkNotNull(listener, "sink");
this.decompressor = (Decompressor) Preconditions.checkNotNull(decompressor, "decompressor");
this.maxInboundMessageSize = i;
this.statsTraceCtx = (StatsTraceContext) Preconditions.checkNotNull(statsTraceContext, "statsTraceCtx");
this.transportTracer = (TransportTracer) Preconditions.checkNotNull(transportTracer, "transportTracer");
}
@Override // io.grpc.internal.Deframer
public void setDecompressor(Decompressor decompressor) {
Preconditions.checkState(this.fullStreamDecompressor == null, "Already set full stream decompressor");
this.decompressor = (Decompressor) Preconditions.checkNotNull(decompressor, "Can't pass an empty decompressor");
}
@Override // io.grpc.internal.Deframer
public void setFullStreamDecompressor(GzipInflatingBuffer gzipInflatingBuffer) {
Preconditions.checkState(this.decompressor == Codec.Identity.NONE, "per-message decompressor already set");
Preconditions.checkState(this.fullStreamDecompressor == null, "full stream decompressor already set");
this.fullStreamDecompressor = (GzipInflatingBuffer) Preconditions.checkNotNull(gzipInflatingBuffer, "Can't pass a null full stream decompressor");
this.unprocessed = null;
}
@Override // io.grpc.internal.Deframer
public void request(int i) {
Preconditions.checkArgument(i > 0, "numMessages must be > 0");
if (isClosed()) {
return;
}
this.pendingDeliveries += i;
deliver();
}
@Override // io.grpc.internal.Deframer
public void deframe(ReadableBuffer readableBuffer) {
boolean z;
Preconditions.checkNotNull(readableBuffer, "data");
try {
if (!isClosedOrScheduledToClose()) {
GzipInflatingBuffer gzipInflatingBuffer = this.fullStreamDecompressor;
if (gzipInflatingBuffer != null) {
gzipInflatingBuffer.addGzippedBytes(readableBuffer);
} else {
this.unprocessed.addBuffer(readableBuffer);
}
try {
deliver();
return;
} catch (Throwable th) {
th = th;
z = false;
if (z) {
readableBuffer.close();
}
throw th;
}
}
readableBuffer.close();
} catch (Throwable th2) {
th = th2;
z = true;
}
}
@Override // io.grpc.internal.Deframer
public void closeWhenComplete() {
if (isClosed()) {
return;
}
if (isStalled()) {
close();
} else {
this.closeWhenComplete = true;
}
}
@Override // java.io.Closeable, java.lang.AutoCloseable, io.grpc.internal.Deframer
public void close() {
if (isClosed()) {
return;
}
CompositeReadableBuffer compositeReadableBuffer = this.nextFrame;
boolean z = compositeReadableBuffer != null && compositeReadableBuffer.readableBytes() > 0;
try {
GzipInflatingBuffer gzipInflatingBuffer = this.fullStreamDecompressor;
if (gzipInflatingBuffer != null) {
boolean z2 = z || gzipInflatingBuffer.hasPartialData();
this.fullStreamDecompressor.close();
z = z2;
}
CompositeReadableBuffer compositeReadableBuffer2 = this.unprocessed;
if (compositeReadableBuffer2 != null) {
compositeReadableBuffer2.close();
}
CompositeReadableBuffer compositeReadableBuffer3 = this.nextFrame;
if (compositeReadableBuffer3 != null) {
compositeReadableBuffer3.close();
}
this.fullStreamDecompressor = null;
this.unprocessed = null;
this.nextFrame = null;
this.listener.deframerClosed(z);
} catch (Throwable th) {
this.fullStreamDecompressor = null;
this.unprocessed = null;
this.nextFrame = null;
throw th;
}
}
private boolean isClosedOrScheduledToClose() {
return isClosed() || this.closeWhenComplete;
}
private boolean isStalled() {
GzipInflatingBuffer gzipInflatingBuffer = this.fullStreamDecompressor;
if (gzipInflatingBuffer != null) {
return gzipInflatingBuffer.isStalled();
}
return this.unprocessed.readableBytes() == 0;
}
/* JADX INFO: Access modifiers changed from: package-private */
/* renamed from: io.grpc.internal.MessageDeframer$1, reason: invalid class name */
/* loaded from: classes6.dex */
public static /* synthetic */ class AnonymousClass1 {
static final int[] $SwitchMap$io$grpc$internal$MessageDeframer$State;
static {
int[] iArr = new int[State.values().length];
$SwitchMap$io$grpc$internal$MessageDeframer$State = iArr;
try {
iArr[State.HEADER.ordinal()] = 1;
} catch (NoSuchFieldError unused) {
}
try {
$SwitchMap$io$grpc$internal$MessageDeframer$State[State.BODY.ordinal()] = 2;
} catch (NoSuchFieldError unused2) {
}
}
}
private void deliver() {
if (this.inDelivery) {
return;
}
this.inDelivery = true;
while (true) {
try {
if (this.stopDelivery || this.pendingDeliveries <= 0 || !readRequiredBytes()) {
break;
}
int i = AnonymousClass1.$SwitchMap$io$grpc$internal$MessageDeframer$State[this.state.ordinal()];
if (i == 1) {
processHeader();
} else if (i == 2) {
processBody();
this.pendingDeliveries--;
} else {
StringBuilder sb = new StringBuilder();
sb.append("Invalid state: ");
sb.append(this.state);
throw new AssertionError(sb.toString());
}
} finally {
this.inDelivery = false;
}
}
if (this.stopDelivery) {
close();
return;
}
if (this.closeWhenComplete && isStalled()) {
close();
}
}
private boolean readRequiredBytes() {
int i;
int i2 = 0;
try {
if (this.nextFrame == null) {
this.nextFrame = new CompositeReadableBuffer();
}
int i3 = 0;
i = 0;
while (true) {
try {
int readableBytes = this.requiredLength - this.nextFrame.readableBytes();
if (readableBytes <= 0) {
if (i3 <= 0) {
return true;
}
this.listener.bytesRead(i3);
if (this.state != State.BODY) {
return true;
}
if (this.fullStreamDecompressor != null) {
this.statsTraceCtx.inboundWireSize(i);
this.inboundBodyWireSize += i;
return true;
}
this.statsTraceCtx.inboundWireSize(i3);
this.inboundBodyWireSize += i3;
return true;
}
if (this.fullStreamDecompressor != null) {
try {
byte[] bArr = this.inflatedBuffer;
if (bArr == null || this.inflatedIndex == bArr.length) {
this.inflatedBuffer = new byte[Math.min(readableBytes, 2097152)];
this.inflatedIndex = 0;
}
int inflateBytes = this.fullStreamDecompressor.inflateBytes(this.inflatedBuffer, this.inflatedIndex, Math.min(readableBytes, this.inflatedBuffer.length - this.inflatedIndex));
i3 += this.fullStreamDecompressor.getAndResetBytesConsumed();
i += this.fullStreamDecompressor.getAndResetDeflatedBytesConsumed();
if (inflateBytes == 0) {
if (i3 > 0) {
this.listener.bytesRead(i3);
if (this.state == State.BODY) {
if (this.fullStreamDecompressor != null) {
this.statsTraceCtx.inboundWireSize(i);
this.inboundBodyWireSize += i;
} else {
this.statsTraceCtx.inboundWireSize(i3);
this.inboundBodyWireSize += i3;
}
}
}
return false;
}
this.nextFrame.addBuffer(ReadableBuffers.wrap(this.inflatedBuffer, this.inflatedIndex, inflateBytes));
this.inflatedIndex += inflateBytes;
} catch (IOException e) {
throw new RuntimeException(e);
} catch (DataFormatException e2) {
throw new RuntimeException(e2);
}
} else {
if (this.unprocessed.readableBytes() == 0) {
if (i3 > 0) {
this.listener.bytesRead(i3);
if (this.state == State.BODY) {
if (this.fullStreamDecompressor != null) {
this.statsTraceCtx.inboundWireSize(i);
this.inboundBodyWireSize += i;
} else {
this.statsTraceCtx.inboundWireSize(i3);
this.inboundBodyWireSize += i3;
}
}
}
return false;
}
int min = Math.min(readableBytes, this.unprocessed.readableBytes());
i3 += min;
this.nextFrame.addBuffer(this.unprocessed.readBytes(min));
}
} catch (Throwable th) {
int i4 = i3;
th = th;
i2 = i4;
if (i2 > 0) {
this.listener.bytesRead(i2);
if (this.state == State.BODY) {
if (this.fullStreamDecompressor != null) {
this.statsTraceCtx.inboundWireSize(i);
this.inboundBodyWireSize += i;
} else {
this.statsTraceCtx.inboundWireSize(i2);
this.inboundBodyWireSize += i2;
}
}
}
throw th;
}
}
} catch (Throwable th2) {
th = th2;
i = 0;
}
}
private void processHeader() {
int readUnsignedByte = this.nextFrame.readUnsignedByte();
if ((readUnsignedByte & RESERVED_MASK) != 0) {
throw Status.INTERNAL.withDescription("gRPC frame header malformed: reserved bits not zero").asRuntimeException();
}
this.compressedFlag = (readUnsignedByte & 1) != 0;
int readInt = this.nextFrame.readInt();
this.requiredLength = readInt;
if (readInt < 0 || readInt > this.maxInboundMessageSize) {
throw Status.RESOURCE_EXHAUSTED.withDescription(String.format("gRPC message exceeds maximum size %d: %d", Integer.valueOf(this.maxInboundMessageSize), Integer.valueOf(this.requiredLength))).asRuntimeException();
}
int i = this.currentMessageSeqNo + 1;
this.currentMessageSeqNo = i;
this.statsTraceCtx.inboundMessage(i);
this.transportTracer.reportMessageReceived();
this.state = State.BODY;
}
private void processBody() {
this.statsTraceCtx.inboundMessageRead(this.currentMessageSeqNo, this.inboundBodyWireSize, -1L);
this.inboundBodyWireSize = 0;
InputStream compressedBody = this.compressedFlag ? getCompressedBody() : getUncompressedBody();
this.nextFrame = null;
this.listener.messagesAvailable(new SingleMessageProducer(compressedBody, null));
this.state = State.HEADER;
this.requiredLength = 5;
}
private InputStream getUncompressedBody() {
this.statsTraceCtx.inboundUncompressedSize(this.nextFrame.readableBytes());
return ReadableBuffers.openStream(this.nextFrame, true);
}
private InputStream getCompressedBody() {
if (this.decompressor == Codec.Identity.NONE) {
throw Status.INTERNAL.withDescription("Can't decode compressed gRPC message as compression not configured").asRuntimeException();
}
try {
return new SizeEnforcingInputStream(this.decompressor.decompress(ReadableBuffers.openStream(this.nextFrame, true)), this.maxInboundMessageSize, this.statsTraceCtx);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/* JADX INFO: Access modifiers changed from: package-private */
/* loaded from: classes6.dex */
public static final class SizeEnforcingInputStream extends FilterInputStream {
private long count;
private long mark;
private long maxCount;
private final int maxMessageSize;
private final StatsTraceContext statsTraceCtx;
SizeEnforcingInputStream(InputStream inputStream, int i, StatsTraceContext statsTraceContext) {
super(inputStream);
this.mark = -1L;
this.maxMessageSize = i;
this.statsTraceCtx = statsTraceContext;
}
@Override // java.io.FilterInputStream, java.io.InputStream
public final int read() throws IOException {
int read = ((FilterInputStream) this).in.read();
if (read != -1) {
this.count++;
}
verifySize();
reportCount();
return read;
}
@Override // java.io.FilterInputStream, java.io.InputStream
public final int read(byte[] bArr, int i, int i2) throws IOException {
int read = ((FilterInputStream) this).in.read(bArr, i, i2);
if (read != -1) {
this.count += read;
}
verifySize();
reportCount();
return read;
}
@Override // java.io.FilterInputStream, java.io.InputStream
public final long skip(long j) throws IOException {
long skip = ((FilterInputStream) this).in.skip(j);
this.count += skip;
verifySize();
reportCount();
return skip;
}
@Override // java.io.FilterInputStream, java.io.InputStream
public final void mark(int i) {
synchronized (this) {
((FilterInputStream) this).in.mark(i);
this.mark = this.count;
}
}
@Override // java.io.FilterInputStream, java.io.InputStream
public final void reset() throws IOException {
synchronized (this) {
if (!((FilterInputStream) this).in.markSupported()) {
throw new IOException("Mark not supported");
}
if (this.mark == -1) {
throw new IOException("Mark not set");
}
((FilterInputStream) this).in.reset();
this.count = this.mark;
}
}
private void reportCount() {
long j = this.count;
long j2 = this.maxCount;
if (j > j2) {
this.statsTraceCtx.inboundUncompressedSize(j - j2);
this.maxCount = this.count;
}
}
private void verifySize() {
if (this.count > this.maxMessageSize) {
throw Status.RESOURCE_EXHAUSTED.withDescription(String.format("Decompressed gRPC message exceeds maximum size %d", Integer.valueOf(this.maxMessageSize))).asRuntimeException();
}
}
}
/* JADX INFO: Access modifiers changed from: package-private */
/* loaded from: classes6.dex */
public static class SingleMessageProducer implements StreamListener.MessageProducer {
private InputStream message;
/* synthetic */ SingleMessageProducer(InputStream inputStream, AnonymousClass1 anonymousClass1) {
this(inputStream);
}
private SingleMessageProducer(InputStream inputStream) {
this.message = inputStream;
}
@Override // io.grpc.internal.StreamListener.MessageProducer
public InputStream next() {
InputStream inputStream = this.message;
this.message = null;
return inputStream;
}
}
/* JADX INFO: Access modifiers changed from: package-private */
public void stopDelivery() {
this.stopDelivery = true;
}
@Override // io.grpc.internal.Deframer
public void setMaxInboundMessageSize(int i) {
this.maxInboundMessageSize = i;
}
/* JADX INFO: Access modifiers changed from: package-private */
public void setListener(Listener listener) {
this.listener = listener;
}
public boolean isClosed() {
return this.unprocessed == null && this.fullStreamDecompressor == null;
}
/* JADX INFO: Access modifiers changed from: package-private */
public boolean hasPendingDeliveries() {
return this.pendingDeliveries != 0;
}
}