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 li
(compressor encoding.Compressor, d mem.BufferSlice, dc Decompressor, maxReceiveMessageSize int, pool mem.BufferPool)
| 983 | // data. Otherwise, it returns an error if decompression fails or the data |
| 984 | // exceeds the size limit. |
| 985 | func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompressor, maxReceiveMessageSize int, pool mem.BufferPool) (mem.BufferSlice, error) { |
| 986 | if dc != nil { |
| 987 | r := d.Reader() |
| 988 | // For the built-in gzip decompressor, bound the decompressed output |
| 989 | // at maxReceiveMessageSize+1 so that a small but highly compressed |
| 990 | // payload (a "zip bomb") cannot expand to gigabytes in memory before |
| 991 | // the post-decompression size check below has a chance to fire. The |
| 992 | // Decompressor interface does not accept an extra size parameter, |
| 993 | // so we type-assert to invoke a size-aware helper. Third-party |
| 994 | // Decompressor implementations keep the original Do behavior. |
| 995 | var uncompressed []byte |
| 996 | var err error |
| 997 | if gd, ok := dc.(*gzipDecompressor); ok { |
| 998 | uncompressed, err = gd.doWithMaxSize(r, int64(maxReceiveMessageSize)) |
| 999 | } else { |
| 1000 | uncompressed, err = dc.Do(r) |
| 1001 | } |
| 1002 | if err != nil { |
| 1003 | r.Close() // ensure buffers are reused |
| 1004 | return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err) |
| 1005 | } |
| 1006 | if len(uncompressed) > maxReceiveMessageSize { |
| 1007 | r.Close() // ensure buffers are reused |
| 1008 | return nil, status.Errorf(codes.ResourceExhausted, "grpc: message after decompression larger than max (%d vs. %d)", len(uncompressed), maxReceiveMessageSize) |
| 1009 | } |
| 1010 | return mem.BufferSlice{mem.SliceBuffer(uncompressed)}, nil |
| 1011 | } |
| 1012 | if compressor != nil { |
| 1013 | r := d.Reader() |
| 1014 | dcReader, err := compressor.Decompress(r) |
| 1015 | if err != nil { |
| 1016 | r.Close() // ensure buffers are reused |
| 1017 | return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err) |
| 1018 | } |
| 1019 | if closer, ok := dcReader.(io.Closer); ok { |
| 1020 | defer closer.Close() |
| 1021 | } |
| 1022 | |
| 1023 | // Read at most one byte more than the limit from the decompressor. |
| 1024 | // Unless the limit is MaxInt64, in which case, that's impossible, so |
| 1025 | // apply no limit. |
| 1026 | if limit := int64(maxReceiveMessageSize); limit < math.MaxInt64 { |
| 1027 | dcReader = io.LimitReader(dcReader, limit+1) |
| 1028 | } |
| 1029 | out, err := mem.ReadAll(dcReader, pool) |
| 1030 | if err != nil { |
| 1031 | r.Close() // ensure buffers are reused |
| 1032 | out.Free() |
| 1033 | return nil, status.Errorf(codes.Internal, "grpc: failed to read decompressed data: %v", err) |
| 1034 | } |
| 1035 | |
| 1036 | if out.Len() > maxReceiveMessageSize { |
| 1037 | r.Close() // ensure buffers are reused |
| 1038 | out.Free() |
| 1039 | return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max %d", maxReceiveMessageSize) |
| 1040 | } |
| 1041 | return out, nil |
| 1042 | } |