Skip to content

Commit 0543f93

Browse files
committed
Add failing test case.
1 parent 2d9437e commit 0543f93

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed

test/protocol/http/accept_encoding.rb

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2019-2025, by Samuel Williams.
5+
6+
require "protocol/http/accept_encoding"
7+
8+
describe Protocol::HTTP::AcceptEncoding do
9+
let(:delegate) do
10+
->(request) {
11+
Protocol::HTTP::Response[200, Protocol::HTTP::Headers["content-type" => "text/plain"], ["Hello World!"]]
12+
}
13+
end
14+
15+
let(:middleware) { Protocol::HTTP::AcceptEncoding.new(delegate) }
16+
17+
with "known encodings" do
18+
it "can decode gzip responses" do
19+
# Mock a response with gzip encoding
20+
gzip_delegate = ->(request) {
21+
Protocol::HTTP::Response[200,
22+
Protocol::HTTP::Headers[
23+
"content-type" => "text/plain",
24+
"content-encoding" => "gzip"
25+
],
26+
["Hello World!"]
27+
]
28+
}
29+
30+
gzip_middleware = Protocol::HTTP::AcceptEncoding.new(gzip_delegate)
31+
request = Protocol::HTTP::Request["GET", "/"]
32+
response = gzip_middleware.call(request)
33+
34+
expect(response.headers).not.to have_keys("content-encoding")
35+
expect(response.body).to be_a(Protocol::HTTP::Body::Inflate)
36+
end
37+
end
38+
39+
with "unknown encodings" do
40+
it "preserves unknown content-encoding headers" do
41+
# Mock a response with brotli encoding (not in DEFAULT_WRAPPERS)
42+
br_delegate = ->(request) {
43+
Protocol::HTTP::Response[200,
44+
Protocol::HTTP::Headers[
45+
"content-type" => "text/plain",
46+
"content-encoding" => "br"
47+
],
48+
["Hello World!"] # This would actually be brotli-encoded in reality
49+
]
50+
}
51+
52+
br_middleware = Protocol::HTTP::AcceptEncoding.new(br_delegate)
53+
request = Protocol::HTTP::Request["GET", "/"]
54+
response = br_middleware.call(request)
55+
56+
# The bug: this currently fails because content-encoding gets removed
57+
# when the middleware encounters an unknown encoding
58+
expect(response.headers).to have_keys("content-encoding")
59+
expect(response.headers["content-encoding"]).to be == ["br"]
60+
# The body should remain untouched since we can't decode it
61+
expect(response.body).not.to be_a(Protocol::HTTP::Body::Inflate)
62+
end
63+
64+
it "preserves mixed known and unknown encodings" do
65+
# Mock a response with multiple encodings where some are unknown
66+
mixed_delegate = ->(request) {
67+
Protocol::HTTP::Response[200,
68+
Protocol::HTTP::Headers[
69+
"content-type" => "text/plain",
70+
"content-encoding" => "gzip, br" # gzip is known, br is unknown
71+
],
72+
["Hello World!"]
73+
]
74+
}
75+
76+
mixed_middleware = Protocol::HTTP::AcceptEncoding.new(mixed_delegate)
77+
request = Protocol::HTTP::Request["GET", "/"]
78+
response = mixed_middleware.call(request)
79+
80+
# The bug: this currently fails because the entire content-encoding
81+
# header gets removed when ANY unknown encoding is present
82+
expect(response.headers).to have_keys("content-encoding")
83+
expect(response.headers["content-encoding"]).to be == ["gzip", "br"]
84+
# The body should remain untouched since we can't decode the br part
85+
expect(response.body).not.to be_a(Protocol::HTTP::Body::Inflate)
86+
end
87+
88+
it "handles case-insensitive encoding names" do
89+
# Mock a response with uppercase encoding name
90+
uppercase_delegate = ->(request) {
91+
Protocol::HTTP::Response[200,
92+
Protocol::HTTP::Headers[
93+
"content-type" => "text/plain",
94+
"content-encoding" => "GZIP"
95+
],
96+
["Hello World!"]
97+
]
98+
}
99+
100+
uppercase_middleware = Protocol::HTTP::AcceptEncoding.new(uppercase_delegate)
101+
request = Protocol::HTTP::Request["GET", "/"]
102+
response = uppercase_middleware.call(request)
103+
104+
# This might also be a bug - encoding names should be case-insensitive
105+
# but the current implementation uses exact string matching
106+
expect(response.headers).not.to have_keys("content-encoding")
107+
expect(response.body).to be_a(Protocol::HTTP::Body::Inflate)
108+
end
109+
end
110+
111+
with "issue #86 - transparent proxy scenario" do
112+
it "preserves unknown content-encoding when acting as transparent proxy" do
113+
# This test simulates the exact scenario described in issue #86
114+
# where a transparent proxy fetches content with brotli encoding
115+
# but the AcceptEncoding middleware doesn't know about brotli
116+
117+
# Mock upstream server that returns brotli-encoded content
118+
upstream_delegate = ->(request) {
119+
# Simulate a server responding with brotli encoding
120+
# when the request has accept-encoding: gzip
121+
expect(request.headers["accept-encoding"]).to be == ["gzip"]
122+
123+
Protocol::HTTP::Response[200,
124+
Protocol::HTTP::Headers[
125+
"content-type" => "text/html",
126+
"content-encoding" => "br" # Server chose brotli
127+
],
128+
["<compressed brotli content>"] # This would be actual brotli data
129+
]
130+
}
131+
132+
# Proxy middleware that only knows about gzip
133+
proxy_middleware = Protocol::HTTP::AcceptEncoding.new(upstream_delegate)
134+
135+
# Client request that accepts both gzip and brotli
136+
request = Protocol::HTTP::Request["GET", "/some/resource"]
137+
response = proxy_middleware.call(request)
138+
139+
# BUG: The content-encoding header should be preserved
140+
# so the client knows the content is still brotli-encoded
141+
expect(response.headers).to have_keys("content-encoding")
142+
expect(response.headers["content-encoding"]).to be == ["br"]
143+
144+
# The body should remain untouched since proxy can't decode brotli
145+
expect(response.body).not.to be_a(Protocol::HTTP::Body::Inflate)
146+
expect(response.read).to be == "<compressed brotli content>"
147+
end
148+
end
149+
150+
with "empty or identity encodings" do
151+
it "handles identity encoding correctly" do
152+
identity_delegate = ->(request) {
153+
Protocol::HTTP::Response[200,
154+
Protocol::HTTP::Headers[
155+
"content-type" => "text/plain",
156+
"content-encoding" => "identity"
157+
],
158+
["Hello World!"]
159+
]
160+
}
161+
162+
identity_middleware = Protocol::HTTP::AcceptEncoding.new(identity_delegate)
163+
request = Protocol::HTTP::Request["GET", "/"]
164+
response = identity_middleware.call(request)
165+
166+
# Identity encoding means no encoding, so header should be removed
167+
expect(response.headers).not.to have_keys("content-encoding")
168+
expect(response.body).not.to be_a(Protocol::HTTP::Body::Inflate)
169+
end
170+
end
171+
end

0 commit comments

Comments
 (0)