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

Code before:
			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 {
		r := d.Reader()
		defer r.Close() // ensure buffers are reused
		uncompressed, err := dc.Do(r)
		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 {
		r := d.Reader()
		defer r.Close() // ensure buffers are reused
		dcReader, err := compressor.Decompress(r)
		if err != nil {
			return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err)
		}

		// Read at most one byte more than the limit from the decompressor.
		// Unless the limit is MaxInt64, in which case, that's impossible, so
		// apply no limit.
		if limit := int64(maxReceiveMessageSize); limit < math.MaxInt64 {
			dcReader = io.LimitReader(dcReader, limit+1)
		}
		out, err := mem.ReadAll(dcReader, pool)
		if err != nil {

Review comment (performance):
I don't think we need a `defer` here, we can call `r.Close()` after `dc.Do` either inside the `if err != nil` or even outside since the implementaiton of `Close` is idempotent. `defer` statements have a very small performance cost, so we should try to avoid them on the RPC path if possible.

Code after:
			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 {
		r := d.Reader()
		uncompressed, err := dc.Do(r)
		if err != nil {
			r.Close() // ensure buffers are reused
			return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err)
		}
		if len(uncompressed) > maxReceiveMessageSize {
			r.Close() // ensure buffers are reused
			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 {
		r := d.Reader()
		dcReader, err := compressor.Decompress(r)
		if err != nil {
			r.Close() // ensure buffers are reused
			return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err)
		}

		// Read at most one byte more than the limit from the decompressor.
		// Unless the limit is MaxInt64, in which case, that's impossible, so
		// apply no limit.
		if limit := int64(maxReceiveMessageSize); limit < math.MaxInt64 {
			dcReader = io.LimitReader(dcReader, limit+1)
		}
		out, err := mem.ReadAll(dcReader, pool)