Repository: grpc/grpc-go
File: rpc_util.go (Go)

Code before:
) (out mem.BufferSlice, err error) {
	pf, compressed, err := p.recvMsg(maxReceiveMessageSize)
	if err != nil {
		return nil, err
	}

	compressedLength := compressed.Len()

	if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil, isServer); st != nil {
		compressed.Free()
		return nil, st.Err()
	}

	if pf.isCompressed() {
		defer compressed.Free()

		// To match legacy behavior, if the decompressor is set by WithDecompressor or RPCDecompressor,
		// use this decompressor as the default.
		if dc != nil {
			var uncompressedBuf []byte
			uncompressedBuf, err = dc.Do(compressed.Reader())
			if err == nil {
				out = mem.BufferSlice{mem.SliceBuffer(uncompressedBuf)}
			}
		} else {
			out, _, err = decompress(compressor, compressed, maxReceiveMessageSize, p.bufferPool)
		}
		if err != nil {
			return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err)
		}

		if err == ErrMaxMessageSizeExceeded {
			out.Free()
			// TODO: Revisit the error code. Currently keep it consistent with java
			// implementation.
			return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max %d", maxReceiveMessageSize)
		}
	} else {
		out = compressed
	}

	if payInfo != nil {
		payInfo.compressedLength = compressedLength
		out.Ref()
		payInfo.uncompressedBytes = out
	}

	return out, nil
}

// Using compressor, decompress d, returning data and size.

Review comment (suggestion):
Since `size` isn't used anymore, we should remove the return value in `decompress`. As `decompress` is an internal function, we can freely change it's returns type.

Code after:
	}

	compressedLength := compressed.Len()

	if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil, isServer); st != nil {
		compressed.Free()
		return nil, st.Err()
	}

	if pf.isCompressed() {
		defer compressed.Free()
		// To match legacy behavior, if the decompressor is set by WithDecompressor or RPCDecompressor,
		// use this decompressor as the default.
		out, err = decompress(compressor, compressed, dc, maxReceiveMessageSize, p.bufferPool)
		if err != nil {
			return nil, err
		}
	} else {
		out = compressed
	}

	if payInfo != nil {
		payInfo.compressedLength = compressedLength
		out.Ref()
		payInfo.uncompressedBytes = out
	}

	return out, nil
}

// decompress processes the given data by decompressing it using either a custom decompressor or a standard compressor.
// If a custom decompressor is provided, it takes precedence. The function validates that the decompressed data
// does not exceed the specified maximum size and returns an error if this limit is exceeded.
// On success, it returns the decompressed data. Otherwise, it returns an error if decompression fails or the data exceeds the size limit.
func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompressor, maxReceiveMessageSize int, pool mem.BufferPool) (mem.BufferSlice, error) {
	if dc != nil {
		uncompressed, err := dc.Do(d.Reader())
		if err != nil {
			return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err)
		}
		if len(uncompressed) > maxReceiveMessageSize {
			return nil, status.Errorf(codes.ResourceExhausted, "grpc: message after decompression larger than max (%d vs. %d)", len(uncompressed), maxReceiveMessageSize)
		}
		return mem.BufferSlice{mem.SliceBuffer(uncompressed)}, nil
	}
	if compressor != nil {
		dcReader, err := compressor.Decompress(d.Reader())
		if err != nil {
			return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err)
		}