Skip to content

Commit a5044e8

Browse files
Simplify message compression
Assisted-By: devx/48bd9802-2aca-41ba-856d-0b5bd523f9cf
1 parent 1e70bc4 commit a5044e8

4 files changed

Lines changed: 58 additions & 32 deletions

File tree

lib/protocol/grpc/body/readable.rb

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -117,26 +117,20 @@ def read_exactly(n)
117117
def decompress(data)
118118
case @encoding
119119
when "gzip"
120-
# Gzip format: zlib stream with gzip header (RFC 1952)
121-
# Use MAX_WBITS + 32 to handle gzip header and CRC
122-
inflater = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
123-
result = inflater.inflate(data)
124-
inflater.close
125-
result
120+
begin
121+
Zlib.gunzip(data)
122+
rescue => error
123+
raise Error.new(Status::INTERNAL, "Failed to decompress message: #{error.message}")
124+
end
126125
when "deflate"
127-
# Zlib format (RFC 1950) - default window bits handle zlib header
128-
# This matches HTTP's "deflate" content-encoding
129-
inflater = Zlib::Inflate.new
130-
result = inflater.inflate(data)
131-
inflater.close
132-
result
126+
begin
127+
Zlib::Inflate.inflate(data)
128+
rescue => error
129+
raise Error.new(Status::INTERNAL, "Failed to decompress message: #{error.message}")
130+
end
133131
else
134132
raise Error.new(Status::UNIMPLEMENTED, "Unsupported compression encoding: #{@encoding.inspect}")
135133
end
136-
rescue Error
137-
raise
138-
rescue StandardError => error
139-
raise Error.new(Status::INTERNAL, "Failed to decompress message: #{error.message}")
140134
end
141135
end
142136
end

lib/protocol/grpc/body/writable.rb

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
require "protocol/http"
77
require "protocol/http/body/writable"
88
require "zlib"
9-
require "stringio"
109

1110
require_relative "../error"
1211
require_relative "../status"
@@ -89,21 +88,20 @@ def write(message, compressed: nil)
8988
def compress(data)
9089
case @encoding
9190
when "gzip"
92-
# Use GzipWriter for proper gzip format (includes headers, CRC)
93-
io = StringIO.new
94-
gz = Zlib::GzipWriter.new(io, @level)
95-
gz.write(data)
96-
gz.close
97-
io.string
91+
begin
92+
Zlib.gzip(data, level: @level)
93+
rescue => error
94+
raise Error.new(Status::INTERNAL, "Failed to compress message: #{error.message}")
95+
end
9896
when "deflate"
99-
# Use zlib format (RFC 1950) for HTTP compatibility
100-
# This matches HTTP's "deflate" content-encoding
101-
Zlib::Deflate.deflate(data, @level)
97+
begin
98+
Zlib::Deflate.deflate(data, @level)
99+
rescue => error
100+
raise Error.new(Status::INTERNAL, "Failed to compress message: #{error.message}")
101+
end
102102
else
103-
raise ArgumentError, "Unsupported compression encoding: #{@encoding.inspect}"
103+
raise Error.new(Status::INTERNAL, "Unsupported compression encoding: #{@encoding.inspect}")
104104
end
105-
rescue StandardError => error
106-
raise Error.new(Status::INTERNAL, "Failed to compress message: #{error.message}")
107105
end
108106
end
109107
end

test/protocol/grpc/body/readable.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,23 @@ def source_body.read
227227
end
228228
end
229229

230-
it "raises a gRPC error for invalid compressed data" do
230+
it "raises a gRPC error for invalid gzip data" do
231231
body = subject.new(source_body, encoding: "gzip")
232232
write_data("invalid", compressed: true)
233233

234234
expect{body.read}.to raise_exception(Protocol::GRPC::Error) do |error|
235235
expect(error.status_code).to be == Protocol::GRPC::Status::INTERNAL
236+
expect(error.message).to be =~ /Failed to decompress message/
237+
end
238+
end
239+
240+
it "raises a gRPC error for invalid deflate data" do
241+
body = subject.new(source_body, encoding: "deflate")
242+
write_data("invalid", compressed: true)
243+
244+
expect{body.read}.to raise_exception(Protocol::GRPC::Error) do |error|
245+
expect(error.status_code).to be == Protocol::GRPC::Status::INTERNAL
246+
expect(error.message).to be =~ /Failed to decompress message/
236247
end
237248
end
238249
end

test/protocol/grpc/body/writable.rb

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,17 @@ def message.encode
213213
expect(compressed).to be == 0
214214
end
215215

216+
it "compresses messages using gzip" do
217+
body = subject.new(encoding: "gzip")
218+
message = message_class.new(value: "Hello")
219+
body.write(message)
220+
body.close_write
221+
222+
framed_data = body.join
223+
expect(framed_data.getbyte(0)).to be == 1
224+
expect(Zlib.gunzip(framed_data.byteslice(5..))).to be == message.to_proto
225+
end
226+
216227
it "compresses messages using deflate" do
217228
body = subject.new(encoding: "deflate")
218229
message = message_class.new(value: "Hello")
@@ -234,11 +245,23 @@ def message.encode
234245
end
235246
end
236247

237-
it "raises a gRPC error when compression fails" do
238-
body = subject.new(encoding: "deflate", level: 100)
248+
it "raises a gRPC error when gzip compression fails" do
249+
body = subject.new(encoding: "gzip")
250+
expect(Zlib).to receive(:gzip).and_raise(Zlib::StreamError, "compression failed")
251+
252+
expect{body.write("Hello")}.to raise_exception(Protocol::GRPC::Error) do |error|
253+
expect(error.status_code).to be == Protocol::GRPC::Status::INTERNAL
254+
expect(error.message).to be == "Failed to compress message: compression failed"
255+
end
256+
end
257+
258+
it "raises a gRPC error when deflate compression fails" do
259+
body = subject.new(encoding: "deflate")
260+
expect(Zlib::Deflate).to receive(:deflate).and_raise(Zlib::StreamError, "compression failed")
239261

240262
expect{body.write("Hello")}.to raise_exception(Protocol::GRPC::Error) do |error|
241263
expect(error.status_code).to be == Protocol::GRPC::Status::INTERNAL
264+
expect(error.message).to be == "Failed to compress message: compression failed"
242265
end
243266
end
244267
end

0 commit comments

Comments
 (0)