Skip to content

Commit 3bbec98

Browse files
authored
Fix NIOHTTPDecompression bug for multi-request channels (#221)
Motivation: `NIOHTTPDecompression` erroneously accumulates decompressed data sizes across multiple requests in a single channel, leading to unwarranted `DecompressionError.limit` errors. This affects applications using persistent connections, as the decompression limits are improperly enforced. This change aims to address and rectify this issue. Modifications: - Add initialization of `inflated` within `Decompressor.initializeDecoder`. - Introduced new tests to validate decompression functionality across multiple requests on the same channel Result: This fix ensures each request's decompression size is independently considered, eliminating incorrect limit errors, and enhancing reliability for applications using HTTP compression with persistent connections.
1 parent c992030 commit 3bbec98

File tree

2 files changed

+16
-0
lines changed

2 files changed

+16
-0
lines changed

Sources/NIOHTTPCompression/HTTPDecompression.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public enum NIOHTTPDecompression {
129129
self.stream.zalloc = nil
130130
self.stream.zfree = nil
131131
self.stream.opaque = nil
132+
self.inflated = 0
132133

133134
let rc = CNIOExtrasZlib_inflateInit2(&self.stream, encoding.window)
134135
guard rc == Z_OK else {

Tests/NIOHTTPCompressionTests/HTTPResponseDecompressorTest.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,21 @@ class HTTPResponseDecompressorTest: XCTestCase {
143143
}
144144
}
145145

146+
func testDecompressionMultipleWriteWithLimit() {
147+
let channel = EmbeddedChannel()
148+
XCTAssertNoThrow(try channel.pipeline.addHandler(NIOHTTPResponseDecompressor(limit: .size(272))).wait())
149+
150+
let headers = HTTPHeaders([("Content-Encoding", "deflate")])
151+
// this compressed payload is 272 bytes long uncompressed
152+
let body = ByteBuffer.of(bytes: [120, 156, 75, 76, 28, 5, 200, 0, 0, 248, 66, 103, 17])
153+
154+
for i in 0..<3 {
155+
XCTAssertNoThrow(try channel.writeInbound(HTTPClientResponsePart.head(.init(version: .init(major: 1, minor: 1), status: .ok, headers: headers))), "\(i)")
156+
XCTAssertNoThrow(try channel.writeInbound(HTTPClientResponsePart.body(body)), "\(i)")
157+
XCTAssertNoThrow(try channel.writeInbound(HTTPClientResponsePart.end(nil)), "\(i)")
158+
}
159+
}
160+
146161
func testDecompression() {
147162
let channel = EmbeddedChannel()
148163
XCTAssertNoThrow(try channel.pipeline.addHandler(NIOHTTPResponseDecompressor(limit: .none)).wait())

0 commit comments

Comments
 (0)