Skip to content

Commit b6b548a

Browse files
committed
feat: allow payload compression in POST requests
- only done if custom_http_headers config includes {'Content-Encoding' => 'gzip'} - only allow gzip. - 'Content-Encoding' header will get dropped in GET requests. - undocumented feature.
1 parent 6328d73 commit b6b548a

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed

lib/unleash/util/http.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
require 'net/http'
22
require 'uri'
3+
require 'zlib'
4+
require 'stringio'
35

46
module Unleash
57
module Util
@@ -8,6 +10,7 @@ def self.get(uri, etag = nil, headers_override = nil)
810
http = http_connection(uri)
911

1012
request = Net::HTTP::Get.new(uri.request_uri, http_headers(etag, headers_override))
13+
request.delete('Content-Encoding')
1114

1215
http.request(request)
1316
end
@@ -16,7 +19,15 @@ def self.post(uri, body)
1619
http = http_connection(uri)
1720

1821
request = Net::HTTP::Post.new(uri.request_uri, http_headers)
19-
request.body = body
22+
request_body =
23+
if request['Content-Encoding'] == 'gzip'
24+
request_body_writer = Zlib::GzipWriter.new(StringIO.new)
25+
request_body_writer << body
26+
request_body_writer.close.string
27+
else
28+
body
29+
end
30+
request.body = request_body
2031

2132
http.request(request)
2233
end
@@ -32,6 +43,7 @@ def self.http_connection(uri)
3243

3344
# @param etag [String, nil]
3445
# @param headers_override [Hash, nil]
46+
# @return [Hash]
3547
def self.http_headers(etag = nil, headers_override = nil)
3648
Unleash.logger.debug "ETag: #{etag}" unless etag.nil?
3749

spec/unleash/client_spec.rb

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
require 'stringio'
2+
require 'zlib'
3+
14
RSpec.describe Unleash::Client do
25
after do
36
WebMock.reset!
@@ -108,6 +111,107 @@
108111
).to have_been_made.once
109112
end
110113

114+
it "The compress http header compresses post requests when initializing client" do
115+
WebMock.stub_request(:post, "http://test-url/client/register")
116+
.with(
117+
headers: {
118+
'Accept' => '*/*',
119+
'Content-Type' => 'application/json',
120+
'Content-Encoding' => 'gzip',
121+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
122+
'User-Agent' => 'Ruby',
123+
'X-Api-Key' => '123'
124+
}
125+
)
126+
.to_return(status: 200, body: "", headers: {})
127+
WebMock.stub_request(:post, "http://test-url/client/metrics")
128+
.with(
129+
headers: {
130+
'Accept' => '*/*',
131+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
132+
'Content-Type' => 'application/json',
133+
'Content-Encoding' => 'gzip',
134+
'User-Agent' => 'Ruby'
135+
}
136+
)
137+
.to_return(status: 200, body: "", headers: {})
138+
139+
simple_features = {
140+
"version": 1,
141+
"features": [
142+
{
143+
"name": "Feature.A",
144+
"description": "Enabled toggle",
145+
"enabled": true,
146+
"strategies": [{ "name": "default" }]
147+
}
148+
]
149+
}
150+
WebMock.stub_request(:get, "http://test-url/client/features")
151+
.with(
152+
headers: {
153+
'Accept' => '*/*',
154+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
155+
'Content-Type' => 'application/json',
156+
'Unleash-Appname' => 'my-test-app',
157+
'Unleash-Instanceid' => 'rspec/test',
158+
'User-Agent' => 'Ruby',
159+
'X-Api-Key' => '123'
160+
}
161+
)
162+
.to_return(status: 200, body: simple_features.to_json, headers: {})
163+
164+
unleash_client = Unleash::Client.new(
165+
url: 'http://test-url/',
166+
app_name: 'my-test-app',
167+
instance_id: 'rspec/test',
168+
custom_http_headers: { 'X-API-KEY' => '123', 'Content-Encoding' => 'gzip' }
169+
)
170+
171+
expect(unleash_client).to be_a(Unleash::Client)
172+
173+
expect(
174+
a_request(:post, "http://test-url/client/register")
175+
.with(headers: {
176+
'Content-Type': 'application/json',
177+
'Content-Encoding': 'gzip',
178+
'X-API-KEY': '123',
179+
'UNLEASH-APPNAME': 'my-test-app',
180+
'UNLEASH-INSTANCEID': 'rspec/test'
181+
})
182+
).to have_been_made.once
183+
184+
expect(
185+
a_request(:get, "http://test-url/client/features")
186+
.with(headers: {
187+
'Content-Type': 'application/json',
188+
'X-API-KEY': '123',
189+
'UNLEASH-APPNAME': 'my-test-app',
190+
'UNLEASH-INSTANCEID': 'rspec/test'
191+
})
192+
).to have_been_made.once
193+
194+
# Test now sending of metrics
195+
# Sending metrics, if they have been evaluated:
196+
unleash_client.is_enabled?("Feature.A")
197+
unleash_client.get_variant("Feature.A")
198+
Unleash.reporter.post
199+
expect(
200+
a_request(:post, "http://test-url/client/metrics")
201+
.with(headers: {
202+
'Content-Type': 'application/json',
203+
'Content-Encoding': 'gzip',
204+
'X-API-KEY': '123',
205+
'UNLEASH-APPNAME': 'my-test-app',
206+
'UNLEASH-INSTANCEID': 'rspec/test'
207+
})
208+
.with do |request|
209+
uncompressed_request_body = Zlib::GzipReader.wrap(StringIO.new(request.body), &:read)
210+
JSON.parse(uncompressed_request_body)['bucket']['toggles']['Feature.A']['yes'] == 2
211+
end
212+
).to have_been_made.once
213+
end
214+
111215
it "should load/use correct variants from the unleash server" do
112216
WebMock.stub_request(:post, "http://test-url/client/register")
113217
.with(

0 commit comments

Comments
 (0)