httpx 1.4.1 → 1.4.3
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/README.md +1 -2
- data/doc/release_notes/1_4_2.md +20 -0
- data/doc/release_notes/1_4_3.md +11 -0
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/adapters/webmock.rb +2 -0
- data/lib/httpx/callbacks.rb +2 -2
- data/lib/httpx/connection/http2.rb +32 -17
- data/lib/httpx/connection.rb +37 -38
- data/lib/httpx/errors.rb +3 -4
- data/lib/httpx/loggable.rb +13 -6
- data/lib/httpx/plugins/callbacks.rb +1 -0
- data/lib/httpx/plugins/circuit_breaker.rb +1 -0
- data/lib/httpx/plugins/expect.rb +1 -1
- data/lib/httpx/plugins/internal_telemetry.rb +21 -1
- data/lib/httpx/plugins/retries.rb +1 -1
- data/lib/httpx/request.rb +17 -1
- data/lib/httpx/resolver/native.rb +86 -48
- data/lib/httpx/resolver/resolver.rb +7 -6
- data/lib/httpx/response.rb +9 -4
- data/lib/httpx/selector.rb +33 -19
- data/lib/httpx/session.rb +3 -5
- data/lib/httpx/timers.rb +16 -1
- data/lib/httpx/transcoder/multipart/encoder.rb +2 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/callbacks.rbs +2 -2
- data/sig/connection/http2.rbs +4 -0
- data/sig/connection.rbs +3 -4
- data/sig/errors.rbs +3 -3
- data/sig/loggable.rbs +2 -2
- data/sig/plugins/query.rbs +18 -0
- data/sig/pool.rbs +2 -0
- data/sig/request.rbs +7 -0
- data/sig/resolver/native.rbs +4 -1
- data/sig/response.rbs +8 -3
- data/sig/selector.rbs +1 -0
- data/sig/timers.rbs +15 -4
- data/sig/transcoder/json.rbs +1 -1
- data/sig/transcoder/multipart.rbs +1 -1
- data/sig/transcoder/utils/deflater.rbs +0 -1
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36f5b3d4da61a1a6c86602205a6eda217f51b40411865589587a09553eb263cb
|
4
|
+
data.tar.gz: 9b705a6b8bc7ebf1ec2e308ae6b49bfcc3ede818bbca0dcf4b2fb82dde1cace6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72759cee17931e45580673c119fffd7339afdfe149f6a4a14afa410d11c47b0d84146a70660b5ca8ff63b1d0b6c1d16a85008416348cd48cddd3f9a9c94f3c10
|
7
|
+
data.tar.gz: 1233281adc13e03e5b754ef6d5d830e84335f5f8b3cc90dea33e27c9f5751f2e3f7d20e1d6064b9273678612a3e4505d8d54b3038b85855bc25a72c6d73d914c
|
data/README.md
CHANGED
@@ -157,7 +157,6 @@ All Rubies greater or equal to 2.7, and always latest JRuby and Truffleruby.
|
|
157
157
|
|
158
158
|
* Discuss your contribution in an issue
|
159
159
|
* Fork it
|
160
|
-
* Make your changes, add some tests
|
161
|
-
* Ensure all tests pass (`docker-compose -f docker-compose.yml -f docker-compose-ruby-{RUBY_VERSION}.yml run httpx bundle exec rake test`)
|
160
|
+
* Make your changes, add some tests (follow the instructions from [here](test/README.md))
|
162
161
|
* Open a Merge Request (that's Pull Request in Github-ish)
|
163
162
|
* Wait for feedback
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# 1.4.2
|
2
|
+
|
3
|
+
## Bugfixes
|
4
|
+
|
5
|
+
* faraday: use default reason when none is matched by Net::HTTP::STATUS_CODES
|
6
|
+
* native resolver: keep sending DNS queries if the socket is available, to avoid busy loops on select
|
7
|
+
* native resolver fixes for Happy Eyeballs v2
|
8
|
+
* do not apply resolution delay if the IPv4 IP was not resolved via DNS
|
9
|
+
* ignore ALIAS if DNS response carries IP answers
|
10
|
+
* do not try to query for names already awaiting answer from the resolver
|
11
|
+
* make sure all types of errors are propagated to connections
|
12
|
+
* make sure next candidate is picked up if receiving NX_DOMAIN_NOT_FOUND error from resolver
|
13
|
+
* raise error happening before any request is flushed to respective connections (avoids loop on non-actionable selector termination).
|
14
|
+
* fix "NoMethodError: undefined method `after' for nil:NilClass", happening for requests flushed into persistent connections which errored, and were retried in a different connection before triggering the timeout callbacks from the previously-closed connection.
|
15
|
+
|
16
|
+
|
17
|
+
## Chore
|
18
|
+
|
19
|
+
* Refactor of timers to allow for explicit and more performant single timer interval cancellation.
|
20
|
+
* default log message restructured to include info about process, thread and caller.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# 1.4.3
|
2
|
+
|
3
|
+
## Bugfixes
|
4
|
+
|
5
|
+
* `webmock` adapter: reassign headers to signature after callbacks are called (these may change the headers before virtual send).
|
6
|
+
* do not close request (and its body) right after sending, instead only on response close
|
7
|
+
* prevents retries from failing under the `:retries` plugin
|
8
|
+
* fixes issue when using `faraday-multipart` request bodies
|
9
|
+
* retry request with HTTP/1 when receiving an HTTP/2 GOAWAY frame with `HTTP_1_1_REQUIRED` error code.
|
10
|
+
* fix wrong method call on HTTP/2 PING frame with unrecognized code.
|
11
|
+
* fix EOFError issues on connection termination for long running connections which may have already been terminated by peer and were wrongly trying to complete the HTTP/2 termination handshake.
|
@@ -122,6 +122,8 @@ module WebMock
|
|
122
122
|
request.transition(:done)
|
123
123
|
request.response = response
|
124
124
|
request.emit(:response, response)
|
125
|
+
request_signature.headers = request.headers.to_h
|
126
|
+
|
125
127
|
response << mock_response.body.dup unless response.is_a?(HTTPX::ErrorResponse)
|
126
128
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
127
129
|
if WebMock::CallbackRegistry.any_callbacks?
|
data/lib/httpx/callbacks.rb
CHANGED
@@ -4,7 +4,7 @@ module HTTPX
|
|
4
4
|
module Callbacks
|
5
5
|
def on(type, &action)
|
6
6
|
callbacks(type) << action
|
7
|
-
|
7
|
+
action
|
8
8
|
end
|
9
9
|
|
10
10
|
def once(type, &block)
|
@@ -12,10 +12,10 @@ module HTTPX
|
|
12
12
|
block.call(*args, &callback)
|
13
13
|
:delete
|
14
14
|
end
|
15
|
-
self
|
16
15
|
end
|
17
16
|
|
18
17
|
def emit(type, *args)
|
18
|
+
log { "emit #{type.inspect} callbacks" } if respond_to?(:log)
|
19
19
|
callbacks(type).delete_if { |pr| :delete == pr.call(*args) } # rubocop:disable Style/YodaCondition
|
20
20
|
end
|
21
21
|
|
@@ -16,6 +16,12 @@ module HTTPX
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
class PingError < Error
|
20
|
+
def initialize
|
21
|
+
super(0, :ping_error)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
19
25
|
class GoawayError < Error
|
20
26
|
def initialize
|
21
27
|
super(0, :no_error)
|
@@ -125,7 +131,7 @@ module HTTPX
|
|
125
131
|
end
|
126
132
|
|
127
133
|
def handle_error(ex, request = nil)
|
128
|
-
if ex.
|
134
|
+
if ex.is_a?(OperationTimeoutError) && !@handshake_completed && @connection.state != :closed
|
129
135
|
@connection.goaway(:settings_timeout, "closing due to settings timeout")
|
130
136
|
emit(:close_handshake)
|
131
137
|
settings_ex = SettingsTimeoutError.new(ex.timeout, ex.message)
|
@@ -311,17 +317,20 @@ module HTTPX
|
|
311
317
|
@streams.delete(request)
|
312
318
|
|
313
319
|
if error
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
320
|
+
case error
|
321
|
+
when :http_1_1_required
|
322
|
+
emit(:error, request, error)
|
323
|
+
else
|
324
|
+
ex = Error.new(stream.id, error)
|
325
|
+
ex.set_backtrace(caller)
|
326
|
+
response = ErrorResponse.new(request, ex)
|
327
|
+
request.response = response
|
328
|
+
emit(:response, request, response)
|
329
|
+
end
|
319
330
|
else
|
320
331
|
response = request.response
|
321
332
|
if response && response.is_a?(Response) && response.status == 421
|
322
|
-
|
323
|
-
ex.set_backtrace(caller)
|
324
|
-
emit(:error, request, ex)
|
333
|
+
emit(:error, request, :http_1_1_required)
|
325
334
|
else
|
326
335
|
emit(:response, request, response)
|
327
336
|
end
|
@@ -352,7 +361,12 @@ module HTTPX
|
|
352
361
|
is_connection_closed = @connection.state == :closed
|
353
362
|
if error
|
354
363
|
@buffer.clear if is_connection_closed
|
355
|
-
|
364
|
+
case error
|
365
|
+
when :http_1_1_required
|
366
|
+
while (request = @pending.shift)
|
367
|
+
emit(:error, request, error)
|
368
|
+
end
|
369
|
+
when :no_error
|
356
370
|
ex = GoawayError.new
|
357
371
|
@pending.unshift(*@streams.keys)
|
358
372
|
@drains.clear
|
@@ -360,8 +374,11 @@ module HTTPX
|
|
360
374
|
else
|
361
375
|
ex = Error.new(0, error)
|
362
376
|
end
|
363
|
-
|
364
|
-
|
377
|
+
|
378
|
+
if ex
|
379
|
+
ex.set_backtrace(caller)
|
380
|
+
handle_error(ex)
|
381
|
+
end
|
365
382
|
end
|
366
383
|
return unless is_connection_closed && @streams.empty?
|
367
384
|
|
@@ -403,11 +420,9 @@ module HTTPX
|
|
403
420
|
end
|
404
421
|
|
405
422
|
def on_pong(ping)
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
close(:protocol_error, "ping payload did not match")
|
410
|
-
end
|
423
|
+
raise PingError unless @pings.delete(ping.to_s)
|
424
|
+
|
425
|
+
emit(:pong)
|
411
426
|
end
|
412
427
|
end
|
413
428
|
end
|
data/lib/httpx/connection.rb
CHANGED
@@ -101,8 +101,6 @@ module HTTPX
|
|
101
101
|
@inflight = 0
|
102
102
|
@keep_alive_timeout = @options.timeout[:keep_alive_timeout]
|
103
103
|
|
104
|
-
@intervals = []
|
105
|
-
|
106
104
|
self.addresses = @options.addresses if @options.addresses
|
107
105
|
end
|
108
106
|
|
@@ -337,15 +335,7 @@ module HTTPX
|
|
337
335
|
end
|
338
336
|
|
339
337
|
def handle_socket_timeout(interval)
|
340
|
-
|
341
|
-
|
342
|
-
unless @intervals.empty?
|
343
|
-
# remove the intervals which will elapse
|
344
|
-
|
345
|
-
return
|
346
|
-
end
|
347
|
-
|
348
|
-
error = HTTPX::TimeoutError.new(interval, "timed out while waiting on select")
|
338
|
+
error = OperationTimeoutError.new(interval, "timed out while waiting on select")
|
349
339
|
error.set_backtrace(caller)
|
350
340
|
on_error(error)
|
351
341
|
end
|
@@ -379,18 +369,20 @@ module HTTPX
|
|
379
369
|
force_reset(true)
|
380
370
|
end
|
381
371
|
|
382
|
-
private
|
383
|
-
|
384
|
-
def connect
|
385
|
-
transition(:open)
|
386
|
-
end
|
387
|
-
|
388
372
|
def disconnect
|
373
|
+
return unless @current_session && @current_selector
|
374
|
+
|
389
375
|
emit(:close)
|
390
376
|
@current_session = nil
|
391
377
|
@current_selector = nil
|
392
378
|
end
|
393
379
|
|
380
|
+
private
|
381
|
+
|
382
|
+
def connect
|
383
|
+
transition(:open)
|
384
|
+
end
|
385
|
+
|
394
386
|
def consume
|
395
387
|
return unless @io
|
396
388
|
|
@@ -431,6 +423,8 @@ module HTTPX
|
|
431
423
|
siz = @io.read(@window_size, @read_buffer)
|
432
424
|
log(level: 3, color: :cyan) { "IO READ: #{siz} bytes... (wsize: #{@window_size}, rbuffer: #{@read_buffer.bytesize})" }
|
433
425
|
unless siz
|
426
|
+
@write_buffer.clear
|
427
|
+
|
434
428
|
ex = EOFError.new("descriptor closed")
|
435
429
|
ex.set_backtrace(caller)
|
436
430
|
on_error(ex)
|
@@ -485,6 +479,8 @@ module HTTPX
|
|
485
479
|
end
|
486
480
|
log(level: 3, color: :cyan) { "IO WRITE: #{siz} bytes..." }
|
487
481
|
unless siz
|
482
|
+
@write_buffer.clear
|
483
|
+
|
488
484
|
ex = EOFError.new("descriptor closed")
|
489
485
|
ex.set_backtrace(caller)
|
490
486
|
on_error(ex)
|
@@ -616,9 +612,9 @@ module HTTPX
|
|
616
612
|
parser.on(:timeout) do |tout|
|
617
613
|
@timeout = tout
|
618
614
|
end
|
619
|
-
parser.on(:error) do |request,
|
620
|
-
case
|
621
|
-
when
|
615
|
+
parser.on(:error) do |request, error|
|
616
|
+
case error
|
617
|
+
when :http_1_1_required
|
622
618
|
current_session = @current_session
|
623
619
|
current_selector = @current_selector
|
624
620
|
parser.close
|
@@ -628,11 +624,15 @@ module HTTPX
|
|
628
624
|
other_connection.merge(self)
|
629
625
|
request.transition(:idle)
|
630
626
|
other_connection.send(request)
|
631
|
-
|
632
|
-
|
633
|
-
request
|
634
|
-
request.
|
627
|
+
next
|
628
|
+
when OperationTimeoutError
|
629
|
+
# request level timeouts should take precedence
|
630
|
+
next unless request.active_timeouts.empty?
|
635
631
|
end
|
632
|
+
|
633
|
+
response = ErrorResponse.new(request, error)
|
634
|
+
request.response = response
|
635
|
+
request.emit(:response, response)
|
636
636
|
end
|
637
637
|
end
|
638
638
|
|
@@ -654,12 +654,14 @@ module HTTPX
|
|
654
654
|
error.set_backtrace(e.backtrace)
|
655
655
|
handle_connect_error(error) if connecting?
|
656
656
|
@state = :closed
|
657
|
+
purge_after_closed
|
657
658
|
disconnect
|
658
659
|
rescue TLSError, ::HTTP2::Error::ProtocolError, ::HTTP2::Error::HandshakeError => e
|
659
660
|
# connect errors, exit gracefully
|
660
661
|
handle_error(e)
|
661
662
|
handle_connect_error(e) if connecting?
|
662
663
|
@state = :closed
|
664
|
+
purge_after_closed
|
663
665
|
disconnect
|
664
666
|
end
|
665
667
|
|
@@ -812,7 +814,7 @@ module HTTPX
|
|
812
814
|
end
|
813
815
|
|
814
816
|
def on_error(error, request = nil)
|
815
|
-
if error.
|
817
|
+
if error.is_a?(OperationTimeoutError)
|
816
818
|
|
817
819
|
# inactive connections do not contribute to the select loop, therefore
|
818
820
|
# they should not fail due to such errors.
|
@@ -857,7 +859,7 @@ module HTTPX
|
|
857
859
|
|
858
860
|
return if read_timeout.nil? || read_timeout.infinite?
|
859
861
|
|
860
|
-
set_request_timeout(request, read_timeout, :done, :response) do
|
862
|
+
set_request_timeout(:read_timeout, request, read_timeout, :done, :response) do
|
861
863
|
read_timeout_callback(request, read_timeout)
|
862
864
|
end
|
863
865
|
end
|
@@ -867,7 +869,7 @@ module HTTPX
|
|
867
869
|
|
868
870
|
return if write_timeout.nil? || write_timeout.infinite?
|
869
871
|
|
870
|
-
set_request_timeout(request, write_timeout, :headers, %i[done response]) do
|
872
|
+
set_request_timeout(:write_timeout, request, write_timeout, :headers, %i[done response]) do
|
871
873
|
write_timeout_callback(request, write_timeout)
|
872
874
|
end
|
873
875
|
end
|
@@ -877,7 +879,7 @@ module HTTPX
|
|
877
879
|
|
878
880
|
return if request_timeout.nil? || request_timeout.infinite?
|
879
881
|
|
880
|
-
set_request_timeout(request, request_timeout, :headers, :complete) do
|
882
|
+
set_request_timeout(:request_timeout, request, request_timeout, :headers, :complete) do
|
881
883
|
read_timeout_callback(request, request_timeout, RequestTimeoutError)
|
882
884
|
end
|
883
885
|
end
|
@@ -902,21 +904,18 @@ module HTTPX
|
|
902
904
|
on_error(error, request)
|
903
905
|
end
|
904
906
|
|
905
|
-
def set_request_timeout(request, timeout, start_event, finish_events, &callback)
|
906
|
-
request.
|
907
|
-
|
907
|
+
def set_request_timeout(label, request, timeout, start_event, finish_events, &callback)
|
908
|
+
request.set_timeout_callback(start_event) do
|
909
|
+
timer = @current_selector.after(timeout, callback)
|
910
|
+
request.active_timeouts << label
|
908
911
|
|
909
912
|
Array(finish_events).each do |event|
|
910
913
|
# clean up request timeouts if the connection errors out
|
911
|
-
request.
|
912
|
-
|
913
|
-
|
914
|
-
@intervals.delete(interval) if interval.no_callbacks?
|
915
|
-
end
|
914
|
+
request.set_timeout_callback(event) do
|
915
|
+
timer.cancel
|
916
|
+
request.active_timeouts.delete(label)
|
916
917
|
end
|
917
918
|
end
|
918
|
-
|
919
|
-
@intervals << interval
|
920
919
|
end
|
921
920
|
end
|
922
921
|
|
data/lib/httpx/errors.rb
CHANGED
@@ -77,6 +77,9 @@ module HTTPX
|
|
77
77
|
# Error raised when there was a timeout while resolving a domain to an IP.
|
78
78
|
class ResolveTimeoutError < TimeoutError; end
|
79
79
|
|
80
|
+
# Error raise when there was a timeout waiting for readiness of the socket the request is related to.
|
81
|
+
class OperationTimeoutError < TimeoutError; end
|
82
|
+
|
80
83
|
# Error raised when there was an error while resolving a domain to an IP.
|
81
84
|
class ResolveError < Error; end
|
82
85
|
|
@@ -112,8 +115,4 @@ module HTTPX
|
|
112
115
|
@response.status
|
113
116
|
end
|
114
117
|
end
|
115
|
-
|
116
|
-
# error raised when a request was sent a server which can't reproduce a response, and
|
117
|
-
# has therefore returned an HTTP response using the 421 status code.
|
118
|
-
class MisdirectedRequestError < HTTPError; end
|
119
118
|
end
|
data/lib/httpx/loggable.rb
CHANGED
@@ -15,20 +15,27 @@ module HTTPX
|
|
15
15
|
|
16
16
|
USE_DEBUG_LOG = ENV.key?("HTTPX_DEBUG")
|
17
17
|
|
18
|
-
def log(level: @options.debug_level, color: nil, &msg)
|
19
|
-
return unless
|
18
|
+
def log(level: @options.debug_level, color: nil, debug_level: @options.debug_level, debug: @options.debug, &msg)
|
19
|
+
return unless debug_level >= level
|
20
20
|
|
21
|
-
debug_stream =
|
21
|
+
debug_stream = debug || ($stderr if USE_DEBUG_LOG)
|
22
22
|
|
23
23
|
return unless debug_stream
|
24
24
|
|
25
|
-
|
25
|
+
klass = self.class
|
26
|
+
|
27
|
+
until (class_name = klass.name)
|
28
|
+
klass = klass.superclass
|
29
|
+
end
|
30
|
+
|
31
|
+
message = +"(pid:#{Process.pid} tid:#{Thread.current.object_id}, self:#{class_name}##{object_id}) "
|
32
|
+
message << msg.call << "\n"
|
26
33
|
message = "\e[#{COLORS[color]}m#{message}\e[0m" if color && debug_stream.respond_to?(:isatty) && debug_stream.isatty
|
27
34
|
debug_stream << message
|
28
35
|
end
|
29
36
|
|
30
|
-
def log_exception(ex, level: @options.debug_level, color: nil)
|
31
|
-
log(level: level, color: color) { ex.full_message }
|
37
|
+
def log_exception(ex, level: @options.debug_level, color: nil, debug_level: @options.debug_level, debug: @options.debug)
|
38
|
+
log(level: level, color: color, debug_level: debug_level, debug: debug) { ex.full_message }
|
32
39
|
end
|
33
40
|
end
|
34
41
|
end
|
data/lib/httpx/plugins/expect.rb
CHANGED
@@ -84,7 +84,7 @@ module HTTPX
|
|
84
84
|
|
85
85
|
return if expect_timeout.nil? || expect_timeout.infinite?
|
86
86
|
|
87
|
-
set_request_timeout(request, expect_timeout, :expect, %i[body response]) do
|
87
|
+
set_request_timeout(:expect_timeout, request, expect_timeout, :expect, %i[body response]) do
|
88
88
|
# expect timeout expired
|
89
89
|
if request.state == :expect && !request.expects?
|
90
90
|
Expect.no_expect_store << request.origin
|
@@ -13,6 +13,12 @@ module HTTPX
|
|
13
13
|
# by the end user in $http_init_time, different diff metrics can be shown. The "point of time" is calculated
|
14
14
|
# using the monotonic clock.
|
15
15
|
module InternalTelemetry
|
16
|
+
DEBUG_LEVEL = 3
|
17
|
+
|
18
|
+
def self.extra_options(options)
|
19
|
+
options.merge(debug_level: 3)
|
20
|
+
end
|
21
|
+
|
16
22
|
module TrackTimeMethods
|
17
23
|
private
|
18
24
|
|
@@ -28,7 +34,19 @@ module HTTPX
|
|
28
34
|
after_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
29
35
|
# $http_init_time = after_time
|
30
36
|
elapsed = after_time - prev_time
|
31
|
-
|
37
|
+
# klass = self.class
|
38
|
+
|
39
|
+
# until (class_name = klass.name)
|
40
|
+
# klass = klass.superclass
|
41
|
+
# end
|
42
|
+
log(
|
43
|
+
level: DEBUG_LEVEL,
|
44
|
+
color: :red,
|
45
|
+
debug_level: @options ? @options.debug_level : DEBUG_LEVEL,
|
46
|
+
debug: nil
|
47
|
+
) do
|
48
|
+
"[ELAPSED TIME]: #{label}: #{elapsed} (ms)" << "\e[0m"
|
49
|
+
end
|
32
50
|
end
|
33
51
|
end
|
34
52
|
|
@@ -88,6 +106,7 @@ module HTTPX
|
|
88
106
|
|
89
107
|
module RequestMethods
|
90
108
|
def self.included(klass)
|
109
|
+
klass.prepend Loggable
|
91
110
|
klass.prepend TrackTimeMethods
|
92
111
|
super
|
93
112
|
end
|
@@ -114,6 +133,7 @@ module HTTPX
|
|
114
133
|
|
115
134
|
module PoolMethods
|
116
135
|
def self.included(klass)
|
136
|
+
klass.prepend Loggable
|
117
137
|
klass.prepend TrackTimeMethods
|
118
138
|
super
|
119
139
|
end
|
@@ -167,7 +167,7 @@ module HTTPX
|
|
167
167
|
unless response.headers.key?("accept-ranges") &&
|
168
168
|
response.headers["accept-ranges"] == "bytes" && # there's nothing else supported though...
|
169
169
|
(original_body = response.body)
|
170
|
-
response.
|
170
|
+
response.body.close
|
171
171
|
return
|
172
172
|
end
|
173
173
|
|
data/lib/httpx/request.rb
CHANGED
@@ -45,9 +45,14 @@ module HTTPX
|
|
45
45
|
|
46
46
|
attr_writer :persistent
|
47
47
|
|
48
|
+
attr_reader :active_timeouts
|
49
|
+
|
48
50
|
# will be +true+ when request body has been completely flushed.
|
49
51
|
def_delegator :@body, :empty?
|
50
52
|
|
53
|
+
# closes the body
|
54
|
+
def_delegator :@body, :close
|
55
|
+
|
51
56
|
# initializes the instance with the given +verb+ (an upppercase String, ex. 'GEt'),
|
52
57
|
# an absolute or relative +uri+ (either as String or URI::HTTP object), the
|
53
58
|
# request +options+ (instance of HTTPX::Options) and an optional Hash of +params+.
|
@@ -100,6 +105,7 @@ module HTTPX
|
|
100
105
|
@response = nil
|
101
106
|
@peer_address = nil
|
102
107
|
@persistent = @options.persistent
|
108
|
+
@active_timeouts = []
|
103
109
|
end
|
104
110
|
|
105
111
|
# the read timeout defined for this requet.
|
@@ -245,8 +251,10 @@ module HTTPX
|
|
245
251
|
@body.rewind
|
246
252
|
@response = nil
|
247
253
|
@drainer = nil
|
254
|
+
@active_timeouts.clear
|
248
255
|
when :headers
|
249
256
|
return unless @state == :idle
|
257
|
+
|
250
258
|
when :body
|
251
259
|
return unless @state == :headers ||
|
252
260
|
@state == :expect
|
@@ -268,7 +276,6 @@ module HTTPX
|
|
268
276
|
when :done
|
269
277
|
return if @state == :expect
|
270
278
|
|
271
|
-
@body.close
|
272
279
|
end
|
273
280
|
@state = nextstate
|
274
281
|
emit(@state, self)
|
@@ -279,6 +286,15 @@ module HTTPX
|
|
279
286
|
def expects?
|
280
287
|
@headers["expect"] == "100-continue" && @informational_status == 100 && !@response
|
281
288
|
end
|
289
|
+
|
290
|
+
def set_timeout_callback(event, &callback)
|
291
|
+
clb = once(event, &callback)
|
292
|
+
|
293
|
+
# reset timeout callbacks when requests get rerouted to a different connection
|
294
|
+
once(:idle) do
|
295
|
+
callbacks(event).delete(clb)
|
296
|
+
end
|
297
|
+
end
|
282
298
|
end
|
283
299
|
end
|
284
300
|
|