http 4.4.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +65 -0
- data/.gitignore +6 -10
- data/.rspec +0 -4
- data/.rubocop/layout.yml +8 -0
- data/.rubocop/style.yml +32 -0
- data/.rubocop.yml +8 -110
- data/.rubocop_todo.yml +192 -0
- data/.yardopts +1 -1
- data/CHANGES.md +87 -3
- data/Gemfile +18 -10
- data/README.md +17 -20
- data/Rakefile +2 -10
- data/http.gemspec +3 -3
- data/lib/http/chainable.rb +23 -17
- data/lib/http/client.rb +36 -30
- data/lib/http/connection.rb +11 -7
- data/lib/http/content_type.rb +12 -7
- data/lib/http/feature.rb +3 -1
- data/lib/http/features/auto_deflate.rb +6 -6
- data/lib/http/features/auto_inflate.rb +6 -5
- data/lib/http/features/instrumentation.rb +1 -1
- data/lib/http/features/logging.rb +19 -21
- data/lib/http/headers.rb +50 -13
- data/lib/http/mime_type/adapter.rb +3 -1
- data/lib/http/mime_type/json.rb +1 -0
- data/lib/http/options.rb +5 -8
- data/lib/http/redirector.rb +2 -1
- data/lib/http/request/body.rb +1 -0
- data/lib/http/request/writer.rb +3 -2
- data/lib/http/request.rb +13 -10
- data/lib/http/response/body.rb +2 -2
- data/lib/http/response/inflater.rb +1 -1
- data/lib/http/response/parser.rb +74 -62
- data/lib/http/response/status.rb +4 -3
- data/lib/http/response.rb +17 -15
- data/lib/http/timeout/global.rb +17 -31
- data/lib/http/timeout/null.rb +2 -1
- data/lib/http/timeout/per_operation.rb +31 -54
- data/lib/http/uri.rb +5 -5
- data/lib/http/version.rb +1 -1
- data/spec/lib/http/client_spec.rb +119 -30
- data/spec/lib/http/connection_spec.rb +8 -5
- data/spec/lib/http/features/auto_inflate_spec.rb +4 -2
- data/spec/lib/http/features/instrumentation_spec.rb +28 -21
- data/spec/lib/http/features/logging_spec.rb +8 -9
- data/spec/lib/http/headers_spec.rb +53 -18
- data/spec/lib/http/options/headers_spec.rb +1 -1
- data/spec/lib/http/options/merge_spec.rb +16 -16
- data/spec/lib/http/redirector_spec.rb +2 -1
- data/spec/lib/http/request/writer_spec.rb +13 -1
- data/spec/lib/http/request_spec.rb +5 -5
- data/spec/lib/http/response/parser_spec.rb +33 -4
- data/spec/lib/http/response/status_spec.rb +3 -3
- data/spec/lib/http/response_spec.rb +11 -22
- data/spec/lib/http_spec.rb +30 -3
- data/spec/spec_helper.rb +21 -21
- data/spec/support/black_hole.rb +1 -1
- data/spec/support/dummy_server/servlet.rb +17 -6
- data/spec/support/dummy_server.rb +7 -7
- data/spec/support/fuubar.rb +21 -0
- data/spec/support/http_handling_shared.rb +4 -4
- data/spec/support/simplecov.rb +19 -0
- data/spec/support/ssl_helper.rb +4 -4
- metadata +18 -12
- data/.coveralls.yml +0 -1
- data/.travis.yml +0 -39
data/lib/http/timeout/global.rb
CHANGED
@@ -59,22 +59,12 @@ module HTTP
|
|
59
59
|
|
60
60
|
private
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
def write_nonblock(data)
|
68
|
-
@socket.write_nonblock(data)
|
69
|
-
end
|
70
|
-
else
|
71
|
-
def read_nonblock(size, buffer = nil)
|
72
|
-
@socket.read_nonblock(size, buffer, :exception => false)
|
73
|
-
end
|
62
|
+
def read_nonblock(size, buffer = nil)
|
63
|
+
@socket.read_nonblock(size, buffer, :exception => false)
|
64
|
+
end
|
74
65
|
|
75
|
-
|
76
|
-
|
77
|
-
end
|
66
|
+
def write_nonblock(data)
|
67
|
+
@socket.write_nonblock(data, :exception => false)
|
78
68
|
end
|
79
69
|
|
80
70
|
# Perform the given I/O operation with the given argument
|
@@ -82,20 +72,18 @@ module HTTP
|
|
82
72
|
reset_timer
|
83
73
|
|
84
74
|
loop do
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
else return result
|
93
|
-
end
|
94
|
-
rescue IO::WaitReadable
|
95
|
-
wait_readable_or_timeout
|
96
|
-
rescue IO::WaitWritable
|
97
|
-
wait_writable_or_timeout
|
75
|
+
result = yield
|
76
|
+
|
77
|
+
case result
|
78
|
+
when :wait_readable then wait_readable_or_timeout
|
79
|
+
when :wait_writable then wait_writable_or_timeout
|
80
|
+
when NilClass then return :eof
|
81
|
+
else return result
|
98
82
|
end
|
83
|
+
rescue IO::WaitReadable
|
84
|
+
wait_readable_or_timeout
|
85
|
+
rescue IO::WaitWritable
|
86
|
+
wait_writable_or_timeout
|
99
87
|
end
|
100
88
|
rescue EOFError
|
101
89
|
:eof
|
@@ -121,9 +109,7 @@ module HTTP
|
|
121
109
|
|
122
110
|
def log_time
|
123
111
|
@time_left -= (Time.now - @started)
|
124
|
-
if @time_left <= 0
|
125
|
-
raise TimeoutError, "Timed out after using the allocated #{@timeout} seconds"
|
126
|
-
end
|
112
|
+
raise TimeoutError, "Timed out after using the allocated #{@timeout} seconds" if @time_left <= 0
|
127
113
|
|
128
114
|
reset_timer
|
129
115
|
end
|
data/lib/http/timeout/null.rb
CHANGED
@@ -12,7 +12,7 @@ module HTTP
|
|
12
12
|
|
13
13
|
attr_reader :options, :socket
|
14
14
|
|
15
|
-
def initialize(options = {})
|
15
|
+
def initialize(options = {})
|
16
16
|
@options = options
|
17
17
|
end
|
18
18
|
|
@@ -36,6 +36,7 @@ module HTTP
|
|
36
36
|
connect_ssl
|
37
37
|
|
38
38
|
return unless ssl_context.verify_mode == OpenSSL::SSL::VERIFY_PEER
|
39
|
+
return if ssl_context.respond_to?(:verify_hostname) && !ssl_context.verify_hostname
|
39
40
|
|
40
41
|
@socket.post_connection_check(host)
|
41
42
|
end
|
@@ -34,65 +34,42 @@ module HTTP
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
:eof
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
# Read data from the socket
|
60
|
-
def readpartial(size, buffer = nil)
|
61
|
-
timeout = false
|
62
|
-
loop do
|
63
|
-
result = @socket.read_nonblock(size, buffer, :exception => false)
|
64
|
-
|
65
|
-
return :eof if result.nil?
|
66
|
-
return result if result != :wait_readable
|
67
|
-
|
68
|
-
raise TimeoutError, "Read timed out after #{@read_timeout} seconds" if timeout
|
69
|
-
# marking the socket for timeout. Why is this not being raised immediately?
|
70
|
-
# it seems there is some race-condition on the network level between calling
|
71
|
-
# #read_nonblock and #wait_readable, in which #read_nonblock signalizes waiting
|
72
|
-
# for reads, and when waiting for x seconds, it returns nil suddenly without completing
|
73
|
-
# the x seconds. In a normal case this would be a timeout on wait/read, but it can
|
74
|
-
# also mean that the socket has been closed by the server. Therefore we "mark" the
|
75
|
-
# socket for timeout and try to read more bytes. If it returns :eof, it's all good, no
|
76
|
-
# timeout. Else, the first timeout was a proper timeout.
|
77
|
-
# This hack has to be done because io/wait#wait_readable doesn't provide a value for when
|
78
|
-
# the socket is closed by the server, and HTTP::Parser doesn't provide the limit for the chunks.
|
79
|
-
timeout = true unless @socket.to_io.wait_readable(@read_timeout)
|
80
|
-
end
|
37
|
+
# Read data from the socket
|
38
|
+
def readpartial(size, buffer = nil)
|
39
|
+
timeout = false
|
40
|
+
loop do
|
41
|
+
result = @socket.read_nonblock(size, buffer, :exception => false)
|
42
|
+
|
43
|
+
return :eof if result.nil?
|
44
|
+
return result if result != :wait_readable
|
45
|
+
|
46
|
+
raise TimeoutError, "Read timed out after #{@read_timeout} seconds" if timeout
|
47
|
+
|
48
|
+
# marking the socket for timeout. Why is this not being raised immediately?
|
49
|
+
# it seems there is some race-condition on the network level between calling
|
50
|
+
# #read_nonblock and #wait_readable, in which #read_nonblock signalizes waiting
|
51
|
+
# for reads, and when waiting for x seconds, it returns nil suddenly without completing
|
52
|
+
# the x seconds. In a normal case this would be a timeout on wait/read, but it can
|
53
|
+
# also mean that the socket has been closed by the server. Therefore we "mark" the
|
54
|
+
# socket for timeout and try to read more bytes. If it returns :eof, it's all good, no
|
55
|
+
# timeout. Else, the first timeout was a proper timeout.
|
56
|
+
# This hack has to be done because io/wait#wait_readable doesn't provide a value for when
|
57
|
+
# the socket is closed by the server, and HTTP::Parser doesn't provide the limit for the chunks.
|
58
|
+
timeout = true unless @socket.to_io.wait_readable(@read_timeout)
|
81
59
|
end
|
60
|
+
end
|
82
61
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
62
|
+
# Write data to the socket
|
63
|
+
def write(data)
|
64
|
+
timeout = false
|
65
|
+
loop do
|
66
|
+
result = @socket.write_nonblock(data, :exception => false)
|
67
|
+
return result unless result == :wait_writable
|
89
68
|
|
90
|
-
|
69
|
+
raise TimeoutError, "Write timed out after #{@write_timeout} seconds" if timeout
|
91
70
|
|
92
|
-
|
93
|
-
end
|
71
|
+
timeout = true unless @socket.to_io.wait_writable(@write_timeout)
|
94
72
|
end
|
95
|
-
|
96
73
|
end
|
97
74
|
end
|
98
75
|
end
|
data/lib/http/uri.rb
CHANGED
@@ -31,11 +31,11 @@ module HTTP
|
|
31
31
|
uri = HTTP::URI.parse uri
|
32
32
|
|
33
33
|
HTTP::URI.new(
|
34
|
-
:scheme
|
35
|
-
:authority
|
36
|
-
:path
|
37
|
-
:query
|
38
|
-
:fragment
|
34
|
+
:scheme => uri.normalized_scheme,
|
35
|
+
:authority => uri.normalized_authority,
|
36
|
+
:path => uri.normalized_path,
|
37
|
+
:query => uri.query,
|
38
|
+
:fragment => uri.normalized_fragment
|
39
39
|
)
|
40
40
|
end
|
41
41
|
|
data/lib/http/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "support/http_handling_shared"
|
5
5
|
require "support/dummy_server"
|
@@ -8,39 +8,50 @@ require "support/ssl_helper"
|
|
8
8
|
RSpec.describe HTTP::Client do
|
9
9
|
run_server(:dummy) { DummyServer.new }
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
before do
|
12
|
+
stubbed_client = Class.new(HTTP::Client) do
|
13
|
+
def perform(request, options)
|
14
|
+
stubbed = stubs[HTTP::URI::NORMALIZER.call(request.uri).to_s]
|
15
|
+
stubbed ? stubbed.call(request) : super(request, options)
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
def stubs
|
19
|
+
@stubs ||= {}
|
20
|
+
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
def stub(stubs)
|
23
|
+
@stubs = stubs.transform_keys do |k|
|
24
|
+
HTTP::URI::NORMALIZER.call(k).to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
self
|
23
28
|
end
|
29
|
+
end
|
24
30
|
|
25
|
-
|
31
|
+
def redirect_response(location, status = 302)
|
32
|
+
lambda do |request|
|
33
|
+
HTTP::Response.new(
|
34
|
+
:status => status,
|
35
|
+
:version => "1.1",
|
36
|
+
:headers => {"Location" => location},
|
37
|
+
:body => "",
|
38
|
+
:request => request
|
39
|
+
)
|
40
|
+
end
|
26
41
|
end
|
27
|
-
end
|
28
42
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
43
|
+
def simple_response(body, status = 200)
|
44
|
+
lambda do |request|
|
45
|
+
HTTP::Response.new(
|
46
|
+
:status => status,
|
47
|
+
:version => "1.1",
|
48
|
+
:body => body,
|
49
|
+
:request => request
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
37
53
|
|
38
|
-
|
39
|
-
HTTP::Response.new(
|
40
|
-
:status => status,
|
41
|
-
:version => "1.1",
|
42
|
-
:body => body
|
43
|
-
)
|
54
|
+
stub_const("StubbedClient", stubbed_client)
|
44
55
|
end
|
45
56
|
|
46
57
|
describe "following redirects" do
|
@@ -193,7 +204,7 @@ RSpec.describe HTTP::Client do
|
|
193
204
|
context "when passing an HTTP::FormData object directly" do
|
194
205
|
it "creates url encoded form data object" do
|
195
206
|
client = HTTP::Client.new
|
196
|
-
form_data = HTTP::FormData::Multipart.new(:foo => "bar")
|
207
|
+
form_data = HTTP::FormData::Multipart.new({ :foo => "bar" })
|
197
208
|
|
198
209
|
allow(client).to receive(:perform)
|
199
210
|
|
@@ -279,6 +290,75 @@ RSpec.describe HTTP::Client do
|
|
279
290
|
end
|
280
291
|
end
|
281
292
|
end
|
293
|
+
|
294
|
+
context "Feature" do
|
295
|
+
let(:feature_class) do
|
296
|
+
Class.new(HTTP::Feature) do
|
297
|
+
attr_reader :captured_request, :captured_response, :captured_error
|
298
|
+
|
299
|
+
def wrap_request(request)
|
300
|
+
@captured_request = request
|
301
|
+
end
|
302
|
+
|
303
|
+
def wrap_response(response)
|
304
|
+
@captured_response = response
|
305
|
+
end
|
306
|
+
|
307
|
+
def on_error(request, error)
|
308
|
+
@captured_request = request
|
309
|
+
@captured_error = error
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
it "is given a chance to wrap the Request" do
|
315
|
+
feature_instance = feature_class.new
|
316
|
+
|
317
|
+
response = client.use(:test_feature => feature_instance).
|
318
|
+
request(:get, dummy.endpoint)
|
319
|
+
|
320
|
+
expect(response.code).to eq(200)
|
321
|
+
expect(feature_instance.captured_request.verb).to eq(:get)
|
322
|
+
expect(feature_instance.captured_request.uri.to_s).to eq("#{dummy.endpoint}/")
|
323
|
+
end
|
324
|
+
|
325
|
+
it "is given a chance to wrap the Response" do
|
326
|
+
feature_instance = feature_class.new
|
327
|
+
|
328
|
+
response = client.use(:test_feature => feature_instance).
|
329
|
+
request(:get, dummy.endpoint)
|
330
|
+
|
331
|
+
expect(feature_instance.captured_response).to eq(response)
|
332
|
+
end
|
333
|
+
|
334
|
+
it "is given a chance to handle an error" do
|
335
|
+
sleep_url = "#{dummy.endpoint}/sleep"
|
336
|
+
feature_instance = feature_class.new
|
337
|
+
|
338
|
+
expect do
|
339
|
+
client.use(:test_feature => feature_instance).
|
340
|
+
timeout(0.2).
|
341
|
+
request(:post, sleep_url)
|
342
|
+
end.to raise_error(HTTP::TimeoutError)
|
343
|
+
|
344
|
+
expect(feature_instance.captured_error).to be_a(HTTP::TimeoutError)
|
345
|
+
expect(feature_instance.captured_request.verb).to eq(:post)
|
346
|
+
expect(feature_instance.captured_request.uri.to_s).to eq(sleep_url)
|
347
|
+
end
|
348
|
+
|
349
|
+
it "is given a chance to handle a connection timeout error" do
|
350
|
+
allow(TCPSocket).to receive(:open) { sleep 1 }
|
351
|
+
sleep_url = "#{dummy.endpoint}/sleep"
|
352
|
+
feature_instance = feature_class.new
|
353
|
+
|
354
|
+
expect do
|
355
|
+
client.use(:test_feature => feature_instance).
|
356
|
+
timeout(0.001).
|
357
|
+
request(:post, sleep_url)
|
358
|
+
end.to raise_error(HTTP::TimeoutError)
|
359
|
+
expect(feature_instance.captured_error).to be_a(HTTP::TimeoutError)
|
360
|
+
end
|
361
|
+
end
|
282
362
|
end
|
283
363
|
|
284
364
|
include_context "HTTP handling" do
|
@@ -288,7 +368,8 @@ RSpec.describe HTTP::Client do
|
|
288
368
|
let(:client) { described_class.new(options.merge(extra_options)) }
|
289
369
|
end
|
290
370
|
|
291
|
-
|
371
|
+
# TODO: https://github.com/httprb/http/issues/627
|
372
|
+
xdescribe "working with SSL" do
|
292
373
|
run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
|
293
374
|
|
294
375
|
let(:extra_options) { {} }
|
@@ -331,6 +412,14 @@ RSpec.describe HTTP::Client do
|
|
331
412
|
client.get(dummy.endpoint).to_s
|
332
413
|
end
|
333
414
|
|
415
|
+
it "provides access to the Request from the Response" do
|
416
|
+
unique_value = "20190424"
|
417
|
+
response = client.headers("X-Value" => unique_value).get(dummy.endpoint)
|
418
|
+
|
419
|
+
expect(response.request).to be_a(HTTP::Request)
|
420
|
+
expect(response.request.headers["X-Value"]).to eq(unique_value)
|
421
|
+
end
|
422
|
+
|
334
423
|
context "with HEAD request" do
|
335
424
|
it "does not iterates through body" do
|
336
425
|
expect_any_instance_of(HTTP::Connection).to_not receive(:readpartial)
|
@@ -421,7 +510,7 @@ RSpec.describe HTTP::Client do
|
|
421
510
|
BODY
|
422
511
|
end
|
423
512
|
|
424
|
-
|
513
|
+
xit "raises HTTP::ConnectionError" do
|
425
514
|
expect { client.get(dummy.endpoint).to_s }.to raise_error(HTTP::ConnectionError)
|
426
515
|
end
|
427
516
|
end
|
@@ -3,9 +3,9 @@
|
|
3
3
|
RSpec.describe HTTP::Connection do
|
4
4
|
let(:req) do
|
5
5
|
HTTP::Request.new(
|
6
|
-
:verb
|
7
|
-
:uri
|
8
|
-
:headers
|
6
|
+
:verb => :get,
|
7
|
+
:uri => "http://example.com/",
|
8
|
+
:headers => {}
|
9
9
|
)
|
10
10
|
end
|
11
11
|
let(:socket) { double(:connect => nil) }
|
@@ -20,14 +20,17 @@ RSpec.describe HTTP::Connection do
|
|
20
20
|
<<-RESPONSE.gsub(/^\s*\| */, "").gsub(/\n/, "\r\n")
|
21
21
|
| HTTP/1.1 200 OK
|
22
22
|
| Content-Type: text
|
23
|
+
| foo_bar: 123
|
23
24
|
|
|
24
25
|
RESPONSE
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
it "
|
29
|
+
it "populates headers collection, preserving casing" do
|
29
30
|
connection.read_headers!
|
30
|
-
expect(connection.headers).to eq("Content-Type" => "text")
|
31
|
+
expect(connection.headers).to eq("Content-Type" => "text", "foo_bar" => "123")
|
32
|
+
expect(connection.headers["Foo-Bar"]).to eq("123")
|
33
|
+
expect(connection.headers["foo_bar"]).to eq("123")
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
@@ -11,7 +11,8 @@ RSpec.describe HTTP::Features::AutoInflate do
|
|
11
11
|
:version => "1.1",
|
12
12
|
:status => 200,
|
13
13
|
:headers => headers,
|
14
|
-
:connection => connection
|
14
|
+
:connection => connection,
|
15
|
+
:request => HTTP::Request.new(:verb => :get, :uri => "http://example.com")
|
15
16
|
)
|
16
17
|
end
|
17
18
|
|
@@ -73,7 +74,8 @@ RSpec.describe HTTP::Features::AutoInflate do
|
|
73
74
|
:status => 200,
|
74
75
|
:headers => {:content_encoding => "gzip"},
|
75
76
|
:connection => connection,
|
76
|
-
:uri => "https://example.com"
|
77
|
+
:uri => "https://example.com",
|
78
|
+
:request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
|
77
79
|
)
|
78
80
|
end
|
79
81
|
|
@@ -2,15 +2,36 @@
|
|
2
2
|
|
3
3
|
RSpec.describe HTTP::Features::Instrumentation do
|
4
4
|
subject(:feature) { HTTP::Features::Instrumentation.new(:instrumenter => instrumenter) }
|
5
|
+
|
5
6
|
let(:instrumenter) { TestInstrumenter.new }
|
6
7
|
|
8
|
+
before do
|
9
|
+
test_instrumenter = Class.new(HTTP::Features::Instrumentation::NullInstrumenter) do
|
10
|
+
attr_reader :output
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@output = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def start(_name, payload)
|
17
|
+
output[:start] = payload
|
18
|
+
end
|
19
|
+
|
20
|
+
def finish(_name, payload)
|
21
|
+
output[:finish] = payload
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
stub_const("TestInstrumenter", test_instrumenter)
|
26
|
+
end
|
27
|
+
|
7
28
|
describe "logging the request" do
|
8
29
|
let(:request) do
|
9
30
|
HTTP::Request.new(
|
10
|
-
:verb
|
11
|
-
:uri
|
31
|
+
:verb => :post,
|
32
|
+
:uri => "https://example.com/",
|
12
33
|
:headers => {:accept => "application/json"},
|
13
|
-
:body
|
34
|
+
:body => '{"hello": "world!"}'
|
14
35
|
)
|
15
36
|
end
|
16
37
|
|
@@ -25,10 +46,11 @@ RSpec.describe HTTP::Features::Instrumentation do
|
|
25
46
|
let(:response) do
|
26
47
|
HTTP::Response.new(
|
27
48
|
:version => "1.1",
|
28
|
-
:uri
|
29
|
-
:status
|
49
|
+
:uri => "https://example.com",
|
50
|
+
:status => 200,
|
30
51
|
:headers => {:content_type => "application/json"},
|
31
|
-
:body
|
52
|
+
:body => '{"success": true}',
|
53
|
+
:request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
|
32
54
|
)
|
33
55
|
end
|
34
56
|
|
@@ -38,19 +60,4 @@ RSpec.describe HTTP::Features::Instrumentation do
|
|
38
60
|
expect(instrumenter.output[:finish]).to eq(:response => response)
|
39
61
|
end
|
40
62
|
end
|
41
|
-
|
42
|
-
class TestInstrumenter < HTTP::Features::Instrumentation::NullInstrumenter
|
43
|
-
attr_reader :output
|
44
|
-
def initialize
|
45
|
-
@output = {}
|
46
|
-
end
|
47
|
-
|
48
|
-
def start(_name, payload)
|
49
|
-
output[:start] = payload
|
50
|
-
end
|
51
|
-
|
52
|
-
def finish(_name, payload)
|
53
|
-
output[:finish] = payload
|
54
|
-
end
|
55
|
-
end
|
56
63
|
end
|
@@ -4,10 +4,8 @@ require "logger"
|
|
4
4
|
|
5
5
|
RSpec.describe HTTP::Features::Logging do
|
6
6
|
subject(:feature) do
|
7
|
-
logger
|
8
|
-
logger.formatter = ->(severity, _, _, message)
|
9
|
-
format("** %s **\n%s\n", severity, message)
|
10
|
-
end
|
7
|
+
logger = Logger.new(logdev)
|
8
|
+
logger.formatter = ->(severity, _, _, message) { format("** %s **\n%s\n", severity, message) }
|
11
9
|
|
12
10
|
described_class.new(:logger => logger)
|
13
11
|
end
|
@@ -17,10 +15,10 @@ RSpec.describe HTTP::Features::Logging do
|
|
17
15
|
describe "logging the request" do
|
18
16
|
let(:request) do
|
19
17
|
HTTP::Request.new(
|
20
|
-
:verb
|
21
|
-
:uri
|
22
|
-
:headers
|
23
|
-
:body
|
18
|
+
:verb => :post,
|
19
|
+
:uri => "https://example.com/",
|
20
|
+
:headers => {:accept => "application/json"},
|
21
|
+
:body => '{"hello": "world!"}'
|
24
22
|
)
|
25
23
|
end
|
26
24
|
|
@@ -47,7 +45,8 @@ RSpec.describe HTTP::Features::Logging do
|
|
47
45
|
:uri => "https://example.com",
|
48
46
|
:status => 200,
|
49
47
|
:headers => {:content_type => "application/json"},
|
50
|
-
:body => '{"success": true}'
|
48
|
+
:body => '{"success": true}',
|
49
|
+
:request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
|
51
50
|
)
|
52
51
|
end
|
53
52
|
|