httpx 0.17.0 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/doc/release_notes/0_18_0.md +69 -0
- data/lib/httpx/adapters/datadog.rb +1 -1
- data/lib/httpx/adapters/faraday.rb +5 -3
- data/lib/httpx/adapters/webmock.rb +7 -1
- data/lib/httpx/altsvc.rb +2 -2
- data/lib/httpx/chainable.rb +3 -3
- data/lib/httpx/connection/http1.rb +3 -3
- data/lib/httpx/connection/http2.rb +6 -4
- data/lib/httpx/connection.rb +67 -70
- data/lib/httpx/domain_name.rb +1 -1
- data/lib/httpx/extensions.rb +50 -4
- data/lib/httpx/io/ssl.rb +1 -1
- data/lib/httpx/io/tls.rb +7 -7
- data/lib/httpx/loggable.rb +5 -5
- data/lib/httpx/options.rb +7 -7
- data/lib/httpx/plugins/aws_sdk_authentication.rb +42 -18
- data/lib/httpx/plugins/aws_sigv4.rb +9 -11
- data/lib/httpx/plugins/compression.rb +5 -3
- data/lib/httpx/plugins/cookies/jar.rb +1 -1
- data/lib/httpx/plugins/expect.rb +7 -3
- data/lib/httpx/plugins/grpc/message.rb +2 -2
- data/lib/httpx/plugins/grpc.rb +3 -3
- data/lib/httpx/plugins/internal_telemetry.rb +8 -8
- data/lib/httpx/plugins/multipart.rb +2 -2
- data/lib/httpx/plugins/response_cache/store.rb +55 -0
- data/lib/httpx/plugins/response_cache.rb +88 -0
- data/lib/httpx/plugins/retries.rb +22 -3
- data/lib/httpx/plugins/stream.rb +1 -1
- data/lib/httpx/pool.rb +39 -13
- data/lib/httpx/request.rb +6 -6
- data/lib/httpx/resolver/https.rb +5 -7
- data/lib/httpx/resolver/native.rb +4 -2
- data/lib/httpx/resolver/system.rb +2 -0
- data/lib/httpx/resolver.rb +2 -2
- data/lib/httpx/response.rb +23 -14
- data/lib/httpx/selector.rb +5 -17
- data/lib/httpx/session.rb +7 -2
- data/lib/httpx/session2.rb +1 -1
- data/lib/httpx/timers.rb +84 -0
- data/lib/httpx/transcoder/body.rb +2 -1
- data/lib/httpx/transcoder/form.rb +1 -1
- data/lib/httpx/transcoder/json.rb +1 -1
- data/lib/httpx/utils.rb +8 -0
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +1 -0
- data/sig/chainable.rbs +1 -0
- data/sig/connection.rbs +12 -6
- data/sig/plugins/aws_sdk_authentication.rbs +22 -4
- data/sig/plugins/response_cache.rbs +35 -0
- data/sig/plugins/retries.rbs +3 -0
- data/sig/pool.rbs +6 -0
- data/sig/resolver/native.rbs +3 -4
- data/sig/resolver/system.rbs +2 -0
- data/sig/response.rbs +3 -2
- data/sig/timers.rbs +32 -0
- data/sig/utils.rbs +4 -0
- metadata +10 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 372f89cdf05727a32d23467503299ae77831cb5d23356467dc0c7f3a22bbfd0c
|
4
|
+
data.tar.gz: bbb3df9079bf4f5a449f37f34dd6b1d3208a978e8a8eaa7fdd69ea9d1829ac6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38211af1e56fbc823ad0780198579ff11d4fa4b5b64677af95e78361f8b274d0dc43b124697358f1a0b17c2d45e4cdd620f97ca983af7fa60ce59515e9b51785
|
7
|
+
data.tar.gz: 2c9d48f3ad7a499046ab94ac3ee1831f1623ce44990de0f08320ac6e5ce3767ca938381cd7b96c3799477f201a811aa5c446d62f88bd58c6e1e0afd84c53af75
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# 0.18.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### Response Cache
|
6
|
+
|
7
|
+
https://gitlab.com/honeyryderchuck/httpx/-/wikis/Response-Cache
|
8
|
+
|
9
|
+
The `:response_cache` plugin handles transparent usage of HTTP caching and conditional requests to improve performance and bandwidth usage.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
client = HTTPX.plugin(:response_cache)
|
13
|
+
r1 = client.get("https://nghttp2.org/httpbin/cache")
|
14
|
+
r2 = client.get("https://nghttp2.org/httpbin/cache")
|
15
|
+
|
16
|
+
r1.status #=> 200
|
17
|
+
r2.status #=> 304
|
18
|
+
r1.body == r2.body #=> true
|
19
|
+
```
|
20
|
+
|
21
|
+
### jitter on "retry-after"
|
22
|
+
|
23
|
+
On the `:retries` plugin, jitter calculation is now applied to the value in seconds defined by user after which a request should be retried (i.e. if `:retry_after` option is set to `2`, the retry interval may be `1.5422312` seconds, for example). This is important to avoid cases of synchronized "thundering herd", where server rejects requests, but they all get retried at the same time because the retry interval is exactly the same.
|
24
|
+
|
25
|
+
You can override the jitter calculation function by using the [:retry_jitter](https://gitlab.com/honeyryderchuck/httpx/-/wikis/Retries#retry_jitter) option:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
HTTPX.plugin(:retries, retry_after: 2, retry_jitter: ->(interval) { interval + rand }) # interval is 3
|
29
|
+
```
|
30
|
+
|
31
|
+
You can opt out of this by setting `HTTPX_NO_JITTER=1` environment variable.
|
32
|
+
|
33
|
+
### Response#error
|
34
|
+
|
35
|
+
`HTTPX::Response#error` was added, to match `HTTPX::Response#error`. It returns an exception for 4xx/5xx responses (`HTTPX::HTTPError`), `nil` otherwise. It allows for end users to write such code:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
if (response = HTTPX.get(uri)).error
|
39
|
+
# success
|
40
|
+
else
|
41
|
+
#error
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Improvements
|
46
|
+
|
47
|
+
* `webmock` adapter: added support for "stub_http_request#to_timeout" (https://gitlab.com/honeyryderchuck/httpx/-/merge_requests/165).
|
48
|
+
|
49
|
+
## timers not a dependency
|
50
|
+
|
51
|
+
The functionality provided by the `timers` gem was replaced by a simpler custom implementation. Although powerful, its complexity was somewhat unnecessary for `httpx`'s simpler event loop, where user-defined timeouts are usually the same for a given batch of requests. The removal of `timers` reduces the number of dependencies to 1, which is `http-2-next` and is maintained by me.
|
52
|
+
|
53
|
+
## AWS plugins
|
54
|
+
|
55
|
+
* `aws_sdk_authentication` plugin: removed implementation relying on `aws-sdk-s3`, replacing it with an `aws-sdk-core` relying implementation, which only uses credentials strategies and region discovery (the whole point of this SDK is to use a minimal subset of AWS SDK).
|
56
|
+
|
57
|
+
|
58
|
+
## Bugfixes
|
59
|
+
|
60
|
+
* Fixed Error class declaration on response decoders when mime type is invalid (https://gitlab.com/honeyryderchuck/httpx/-/merge_requests/166).
|
61
|
+
* `ErrorResponse#to_s` now removes ANSI escape sequences from error backtraces.
|
62
|
+
* Persistent connections were kept around both in the pool and in the selector; the first is necessary, but the second caused busy loop scenarios all over; they are now removed when no requests are being handled.
|
63
|
+
* Connections which failed connection handshake were removed from the pool, but not from the selector list, causing busy loop scenarios in a few cases; this has been fixed.
|
64
|
+
* Fixed issue where HTTP/2 streams were being closed twice (and signaling it also twice), messing connection accounting in the pool.
|
65
|
+
* DoH resolver was always subscribed to the default thread "connection pool", which broke scenarios were session was patched to use its custom pool; it now ensures that it subscribes to the pool it was created in.
|
66
|
+
* `:aws_sigv4` plugin: removed require of `aws-sdk-s3`, left there by mistake (the whole point of the plugin is to run without the AWS SDK).
|
67
|
+
## Chore
|
68
|
+
|
69
|
+
* `HTTPX::ErrorResponse#status` is now deprecated.
|
@@ -22,6 +22,8 @@ module Faraday
|
|
22
22
|
# :nocov:
|
23
23
|
|
24
24
|
module RequestMixin
|
25
|
+
using ::HTTPX::HashExtensions
|
26
|
+
|
25
27
|
private
|
26
28
|
|
27
29
|
def build_request(env)
|
@@ -38,7 +40,7 @@ module Faraday
|
|
38
40
|
timeout_options = {
|
39
41
|
connect_timeout: env.request.open_timeout,
|
40
42
|
operation_timeout: env.request.timeout,
|
41
|
-
}.
|
43
|
+
}.compact
|
42
44
|
|
43
45
|
options = {
|
44
46
|
ssl: {},
|
@@ -101,7 +103,7 @@ module Faraday
|
|
101
103
|
end
|
102
104
|
|
103
105
|
def on_response(&blk)
|
104
|
-
if
|
106
|
+
if blk
|
105
107
|
@on_response = lambda do |response|
|
106
108
|
blk.call(response)
|
107
109
|
end
|
@@ -112,7 +114,7 @@ module Faraday
|
|
112
114
|
end
|
113
115
|
|
114
116
|
def on_complete(&blk)
|
115
|
-
if
|
117
|
+
if blk
|
116
118
|
@on_complete = blk
|
117
119
|
self
|
118
120
|
else
|
@@ -86,7 +86,9 @@ module WebMock
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def _build_from_webmock_response(request, webmock_response)
|
89
|
-
return
|
89
|
+
return _build_error_response(request, HTTPX::TimeoutError.new(1, "Timed out")) if webmock_response.should_timeout
|
90
|
+
|
91
|
+
return _build_error_response(request, webmock_response.exception) if webmock_response.exception
|
90
92
|
|
91
93
|
response = request.options.response_class.new(request,
|
92
94
|
webmock_response.status[0],
|
@@ -95,6 +97,10 @@ module WebMock
|
|
95
97
|
response << webmock_response.body.dup
|
96
98
|
response
|
97
99
|
end
|
100
|
+
|
101
|
+
def _build_error_response(request, exception)
|
102
|
+
HTTPX::ErrorResponse.new(request, exception, request.options)
|
103
|
+
end
|
98
104
|
end
|
99
105
|
end
|
100
106
|
|
data/lib/httpx/altsvc.rb
CHANGED
@@ -10,14 +10,14 @@ module HTTPX
|
|
10
10
|
module_function
|
11
11
|
|
12
12
|
def cached_altsvc(origin)
|
13
|
-
now =
|
13
|
+
now = Utils.now
|
14
14
|
@altsvc_mutex.synchronize do
|
15
15
|
lookup(origin, now)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
def cached_altsvc_set(origin, entry)
|
20
|
-
now =
|
20
|
+
now = Utils.now
|
21
21
|
@altsvc_mutex.synchronize do
|
22
22
|
return if @altsvcs[origin].any? { |altsvc| altsvc["origin"] == entry["origin"] }
|
23
23
|
|
data/lib/httpx/chainable.rb
CHANGED
@@ -4,9 +4,9 @@ module HTTPX
|
|
4
4
|
module Chainable
|
5
5
|
%i[head get post put delete trace options connect patch].each do |meth|
|
6
6
|
class_eval(<<-MOD, __FILE__, __LINE__ + 1)
|
7
|
-
def #{meth}(*uri, **options)
|
8
|
-
request(:#{meth}, uri, **options)
|
9
|
-
end
|
7
|
+
def #{meth}(*uri, **options) # def get(*uri, **options)
|
8
|
+
request(:#{meth}, uri, **options) # request(:get, uri, **options)
|
9
|
+
end # end
|
10
10
|
MOD
|
11
11
|
end
|
12
12
|
|
@@ -283,10 +283,10 @@ module HTTPX
|
|
283
283
|
# on the last request of the possible batch (either allowed max requests,
|
284
284
|
# or if smaller, the size of the batch itself)
|
285
285
|
requests_limit = [@max_requests, @requests.size].min
|
286
|
-
if request
|
287
|
-
"keep-alive"
|
288
|
-
else
|
286
|
+
if request == @requests[requests_limit - 1]
|
289
287
|
"close"
|
288
|
+
else
|
289
|
+
"keep-alive"
|
290
290
|
end
|
291
291
|
end
|
292
292
|
|
@@ -291,11 +291,13 @@ module HTTPX
|
|
291
291
|
end
|
292
292
|
|
293
293
|
def on_stream_refuse(stream, request, error)
|
294
|
-
stream.close
|
295
294
|
on_stream_close(stream, request, error)
|
295
|
+
stream.close
|
296
296
|
end
|
297
297
|
|
298
298
|
def on_stream_close(stream, request, error)
|
299
|
+
return if error == :stream_closed && !@streams.key?(request)
|
300
|
+
|
299
301
|
log(level: 2) { "#{stream.id}: closing stream" }
|
300
302
|
@drains.delete(request)
|
301
303
|
@streams.delete(request)
|
@@ -388,10 +390,10 @@ module HTTPX
|
|
388
390
|
end
|
389
391
|
|
390
392
|
def on_pong(ping)
|
391
|
-
if
|
392
|
-
close(:protocol_error, "ping payload did not match")
|
393
|
-
else
|
393
|
+
if @pings.delete(ping.to_s)
|
394
394
|
emit(:pong)
|
395
|
+
else
|
396
|
+
close(:protocol_error, "ping payload did not match")
|
395
397
|
end
|
396
398
|
end
|
397
399
|
end
|
data/lib/httpx/connection.rb
CHANGED
@@ -70,7 +70,7 @@ module HTTPX
|
|
70
70
|
|
71
71
|
@inflight = 0
|
72
72
|
@keep_alive_timeout = @options.timeout[:keep_alive_timeout]
|
73
|
-
@
|
73
|
+
@total_timeout = @options.timeout[:total_timeout]
|
74
74
|
|
75
75
|
self.addresses = @options.addresses if @options.addresses
|
76
76
|
end
|
@@ -200,11 +200,9 @@ module HTTPX
|
|
200
200
|
end
|
201
201
|
|
202
202
|
def close
|
203
|
-
|
204
|
-
return unless @keep_alive_timer
|
203
|
+
transition(:active) if @state == :inactive
|
205
204
|
|
206
|
-
@
|
207
|
-
remove_instance_variable(:@keep_alive_timer)
|
205
|
+
@parser.close if @parser
|
208
206
|
end
|
209
207
|
|
210
208
|
def reset
|
@@ -216,26 +214,40 @@ module HTTPX
|
|
216
214
|
def send(request)
|
217
215
|
if @parser && !@write_buffer.full?
|
218
216
|
request.headers["alt-used"] = @origin.authority if match_altsvcs?(request.uri)
|
219
|
-
|
217
|
+
|
218
|
+
if @response_received_at && @keep_alive_timeout &&
|
219
|
+
Utils.elapsed_time(@response_received_at) > @keep_alive_timeout
|
220
220
|
# when pushing a request into an existing connection, we have to check whether there
|
221
221
|
# is the possibility that the connection might have extended the keep alive timeout.
|
222
222
|
# for such cases, we want to ping for availability before deciding to shovel requests.
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
end
|
228
|
-
|
229
|
-
@keep_alive_timer.pause
|
223
|
+
@pending << request
|
224
|
+
parser.ping
|
225
|
+
transition(:active) if @state == :inactive
|
226
|
+
return
|
230
227
|
end
|
231
|
-
|
232
|
-
|
228
|
+
|
229
|
+
send_request_to_parser(request)
|
233
230
|
else
|
234
231
|
@pending << request
|
235
232
|
end
|
236
233
|
end
|
237
234
|
|
238
235
|
def timeout
|
236
|
+
if @total_timeout
|
237
|
+
return @total_timeout unless @connected_at
|
238
|
+
|
239
|
+
elapsed_time = @total_timeout - Utils.elapsed_time(@connected_at)
|
240
|
+
|
241
|
+
if elapsed_time.negative?
|
242
|
+
ex = TotalTimeoutError.new(@total_timeout, "Timed out after #{@total_timeout} seconds")
|
243
|
+
ex.set_backtrace(caller)
|
244
|
+
on_error(@total_timeout)
|
245
|
+
return
|
246
|
+
end
|
247
|
+
|
248
|
+
return elapsed_time
|
249
|
+
end
|
250
|
+
|
239
251
|
return @timeout if defined?(@timeout)
|
240
252
|
|
241
253
|
return @options.timeout[:connect_timeout] if @state == :idle
|
@@ -243,6 +255,14 @@ module HTTPX
|
|
243
255
|
@options.timeout[:operation_timeout]
|
244
256
|
end
|
245
257
|
|
258
|
+
def deactivate
|
259
|
+
transition(:inactive)
|
260
|
+
end
|
261
|
+
|
262
|
+
def open?
|
263
|
+
@state == :open || @state == :inactive
|
264
|
+
end
|
265
|
+
|
246
266
|
private
|
247
267
|
|
248
268
|
def connect
|
@@ -379,9 +399,7 @@ module HTTPX
|
|
379
399
|
|
380
400
|
def send_pending
|
381
401
|
while !@write_buffer.full? && (request = @pending.shift)
|
382
|
-
|
383
|
-
@keep_alive_timer.pause if @keep_alive_timer
|
384
|
-
parser.send(request)
|
402
|
+
send_request_to_parser(request)
|
385
403
|
end
|
386
404
|
end
|
387
405
|
|
@@ -389,6 +407,15 @@ module HTTPX
|
|
389
407
|
@parser ||= build_parser
|
390
408
|
end
|
391
409
|
|
410
|
+
def send_request_to_parser(request)
|
411
|
+
@inflight += 1
|
412
|
+
parser.send(request)
|
413
|
+
|
414
|
+
return unless @state == :inactive
|
415
|
+
|
416
|
+
transition(:active)
|
417
|
+
end
|
418
|
+
|
392
419
|
def build_parser(protocol = @io.protocol)
|
393
420
|
parser = registry(protocol).new(@write_buffer, @options)
|
394
421
|
set_parser_callbacks(parser)
|
@@ -400,7 +427,8 @@ module HTTPX
|
|
400
427
|
AltSvc.emit(request, response) do |alt_origin, origin, alt_params|
|
401
428
|
emit(:altsvc, alt_origin, origin, alt_params)
|
402
429
|
end
|
403
|
-
|
430
|
+
@response_received_at = Utils.now
|
431
|
+
@inflight -= 1
|
404
432
|
request.emit(:response, response)
|
405
433
|
end
|
406
434
|
parser.on(:altsvc) do |alt_origin, origin, alt_params|
|
@@ -420,7 +448,7 @@ module HTTPX
|
|
420
448
|
end
|
421
449
|
parser.on(:close) do |force|
|
422
450
|
transition(:closing)
|
423
|
-
if force
|
451
|
+
if force || @state == :idle
|
424
452
|
transition(:closed)
|
425
453
|
emit(:close)
|
426
454
|
end
|
@@ -466,15 +494,17 @@ module HTTPX
|
|
466
494
|
when :open
|
467
495
|
return if @state == :closed
|
468
496
|
|
469
|
-
total_timeout
|
470
|
-
|
471
497
|
@io.connect
|
472
498
|
return unless @io.connected?
|
473
499
|
|
500
|
+
@connected_at = Utils.now
|
501
|
+
|
474
502
|
send_pending
|
475
503
|
|
476
504
|
@timeout = @current_timeout = parser.timeout
|
477
505
|
emit(:open)
|
506
|
+
when :inactive
|
507
|
+
return unless @state == :open
|
478
508
|
when :closing
|
479
509
|
return unless @state == :open
|
480
510
|
|
@@ -482,15 +512,15 @@ module HTTPX
|
|
482
512
|
return unless @state == :closing
|
483
513
|
return unless @write_buffer.empty?
|
484
514
|
|
485
|
-
if @total_timeout
|
486
|
-
@total_timeout.cancel
|
487
|
-
remove_instance_variable(:@total_timeout)
|
488
|
-
end
|
489
|
-
|
490
515
|
purge_after_closed
|
491
516
|
when :already_open
|
492
517
|
nextstate = :open
|
493
518
|
send_pending
|
519
|
+
when :active
|
520
|
+
return unless @state == :inactive
|
521
|
+
|
522
|
+
nextstate = :open
|
523
|
+
emit(:activate)
|
494
524
|
end
|
495
525
|
@state = nextstate
|
496
526
|
rescue Errno::ECONNREFUSED,
|
@@ -506,44 +536,24 @@ module HTTPX
|
|
506
536
|
def purge_after_closed
|
507
537
|
@io.close if @io
|
508
538
|
@read_buffer.clear
|
509
|
-
if @keep_alive_timer
|
510
|
-
@keep_alive_timer.cancel
|
511
|
-
remove_instance_variable(:@keep_alive_timer)
|
512
|
-
end
|
513
|
-
|
514
539
|
remove_instance_variable(:@timeout) if defined?(@timeout)
|
515
540
|
end
|
516
541
|
|
517
|
-
def handle_response
|
518
|
-
@inflight -= 1
|
519
|
-
return unless @inflight.zero?
|
520
|
-
|
521
|
-
if @keep_alive_timer
|
522
|
-
@keep_alive_timer.resume
|
523
|
-
@keep_alive_timer.reset
|
524
|
-
else
|
525
|
-
@keep_alive_timer = @timers.after(@keep_alive_timeout) do
|
526
|
-
unless @inflight.zero?
|
527
|
-
log { "(#{@origin}): keep alive timeout expired" }
|
528
|
-
parser.ping
|
529
|
-
end
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
542
|
def on_error(error)
|
535
543
|
if error.instance_of?(TimeoutError)
|
536
|
-
if @timeout
|
537
|
-
@timeout -= error.timeout
|
538
|
-
return unless @timeout <= 0
|
539
|
-
end
|
540
544
|
|
541
|
-
if @total_timeout && @
|
542
|
-
|
545
|
+
if @total_timeout && @connected_at &&
|
546
|
+
Utils.elapsed_time(@connected_at) > @total_timeout
|
547
|
+
ex = TotalTimeoutError.new(@total_timeout, "Timed out after #{@total_timeout} seconds")
|
543
548
|
ex.set_backtrace(error.backtrace)
|
544
549
|
error = ex
|
545
|
-
|
546
|
-
|
550
|
+
else
|
551
|
+
if @timeout
|
552
|
+
@timeout -= error.timeout
|
553
|
+
return unless @timeout <= 0
|
554
|
+
end
|
555
|
+
|
556
|
+
error = error.to_connection_error if connecting?
|
547
557
|
end
|
548
558
|
end
|
549
559
|
handle_error(error)
|
@@ -558,18 +568,5 @@ module HTTPX
|
|
558
568
|
request.emit(:response, response)
|
559
569
|
end
|
560
570
|
end
|
561
|
-
|
562
|
-
def total_timeout
|
563
|
-
total = @options.timeout[:total_timeout]
|
564
|
-
|
565
|
-
return unless total
|
566
|
-
|
567
|
-
@total_timeout ||= @timers.after(total) do
|
568
|
-
ex = TotalTimeoutError.new(total, "Timed out after #{total} seconds")
|
569
|
-
ex.set_backtrace(caller)
|
570
|
-
on_error(ex)
|
571
|
-
@parser.close if @parser
|
572
|
-
end
|
573
|
-
end
|
574
571
|
end
|
575
572
|
end
|
data/lib/httpx/domain_name.rb
CHANGED
data/lib/httpx/extensions.rb
CHANGED
@@ -54,6 +54,51 @@ module HTTPX
|
|
54
54
|
Numeric.__send__(:include, NegMethods)
|
55
55
|
end
|
56
56
|
|
57
|
+
module HashExtensions
|
58
|
+
refine Hash do
|
59
|
+
def compact
|
60
|
+
h = {}
|
61
|
+
each do |key, value|
|
62
|
+
h[key] = value unless value == nil
|
63
|
+
end
|
64
|
+
h
|
65
|
+
end unless Hash.method_defined?(:compact)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module ArrayExtensions
|
70
|
+
refine Array do
|
71
|
+
|
72
|
+
def filter_map
|
73
|
+
return to_enum(:filter_map) unless block_given?
|
74
|
+
|
75
|
+
each_with_object([]) do |item, res|
|
76
|
+
processed = yield(item)
|
77
|
+
res << processed if processed
|
78
|
+
end
|
79
|
+
end unless Array.method_defined?(:filter_map)
|
80
|
+
|
81
|
+
def sum(accumulator = 0, &block)
|
82
|
+
values = block_given? ? map(&block) : self
|
83
|
+
values.inject(accumulator, :+)
|
84
|
+
end unless Array.method_defined?(:sum)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module IOExtensions
|
89
|
+
refine IO do
|
90
|
+
# provides a fallback for rubies where IO#wait isn't implemented,
|
91
|
+
# but IO#wait_readable and IO#wait_writable are.
|
92
|
+
def wait(timeout = nil, _mode = :read_write)
|
93
|
+
r, w = IO.select([self], [self], nil, timeout)
|
94
|
+
|
95
|
+
return unless r || w
|
96
|
+
|
97
|
+
self
|
98
|
+
end unless IO.method_defined?(:wait) && IO.instance_method(:wait).arity == 2
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
57
102
|
module RegexpExtensions
|
58
103
|
# If you wonder why this is there: the oauth feature uses a refinement to enhance the
|
59
104
|
# Regexp class locally with #match? , but this is never tested, because ActiveSupport
|
@@ -77,13 +122,14 @@ module HTTPX
|
|
77
122
|
end
|
78
123
|
|
79
124
|
def authority
|
80
|
-
|
81
|
-
|
82
|
-
|
125
|
+
return host if port == default_port
|
126
|
+
|
127
|
+
"#{host}:#{port}"
|
128
|
+
end unless URI::HTTP.method_defined?(:authority)
|
83
129
|
|
84
130
|
def origin
|
85
131
|
"#{scheme}://#{authority}"
|
86
|
-
end
|
132
|
+
end unless URI::HTTP.method_defined?(:origin)
|
87
133
|
|
88
134
|
def altsvc_match?(uri)
|
89
135
|
uri = URI.parse(uri)
|
data/lib/httpx/io/ssl.rb
CHANGED
@@ -134,7 +134,7 @@ module HTTPX
|
|
134
134
|
server_cert = @io.peer_cert
|
135
135
|
|
136
136
|
"#{super}\n\n" \
|
137
|
-
|
137
|
+
"SSL connection using #{@io.ssl_version} / #{Array(@io.cipher).first}\n" \
|
138
138
|
"ALPN, server accepted to use #{protocol}\n" \
|
139
139
|
"Server certificate:\n" \
|
140
140
|
" subject: #{server_cert.subject}\n" \
|
data/lib/httpx/io/tls.rb
CHANGED
@@ -194,15 +194,15 @@ module HTTPX
|
|
194
194
|
server_cert = @peer_cert
|
195
195
|
|
196
196
|
"#{super}\n\n" \
|
197
|
-
|
198
|
-
|
197
|
+
"SSL connection using #{@ctx.ssl_version} / #{Array(@ctx.cipher).first}\n" \
|
198
|
+
"ALPN, server accepted to use #{protocol}\n" +
|
199
199
|
(if server_cert
|
200
200
|
"Server certificate:\n" \
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
201
|
+
" subject: #{server_cert.subject}\n" \
|
202
|
+
" start date: #{server_cert.not_before}\n" \
|
203
|
+
" expire date: #{server_cert.not_after}\n" \
|
204
|
+
" issuer: #{server_cert.issuer}\n" \
|
205
|
+
" SSL certificate verify ok."
|
206
206
|
else
|
207
207
|
"SSL certificate verify failed."
|
208
208
|
end
|
data/lib/httpx/loggable.rb
CHANGED
@@ -24,15 +24,13 @@ module HTTPX
|
|
24
24
|
debug_stream << message
|
25
25
|
end
|
26
26
|
|
27
|
-
if
|
27
|
+
if Exception.instance_methods.include?(:full_message)
|
28
28
|
|
29
29
|
def log_exception(ex, level: @options.debug_level, color: nil)
|
30
30
|
return unless @options.debug
|
31
31
|
return unless @options.debug_level >= level
|
32
32
|
|
33
|
-
|
34
|
-
message << "\n" << ex.backtrace.join("\n") unless ex.backtrace.nil?
|
35
|
-
log(level: level, color: color) { message }
|
33
|
+
log(level: level, color: color) { ex.full_message }
|
36
34
|
end
|
37
35
|
|
38
36
|
else
|
@@ -41,7 +39,9 @@ module HTTPX
|
|
41
39
|
return unless @options.debug
|
42
40
|
return unless @options.debug_level >= level
|
43
41
|
|
44
|
-
|
42
|
+
message = +"#{ex.message} (#{ex.class})"
|
43
|
+
message << "\n" << ex.backtrace.join("\n") unless ex.backtrace.nil?
|
44
|
+
log(level: level, color: color) { message }
|
45
45
|
end
|
46
46
|
|
47
47
|
end
|
data/lib/httpx/options.rb
CHANGED
@@ -81,9 +81,9 @@ module HTTPX
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def def_option(optname, *args, &block)
|
84
|
-
if args.size.zero? && !
|
84
|
+
if args.size.zero? && !block
|
85
85
|
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
86
|
-
def option_#{optname}(v); v; end
|
86
|
+
def option_#{optname}(v); v; end # def option_smth(v); v; end
|
87
87
|
OUT
|
88
88
|
return
|
89
89
|
end
|
@@ -93,15 +93,15 @@ module HTTPX
|
|
93
93
|
|
94
94
|
def deprecated_def_option(optname, layout = nil, &interpreter)
|
95
95
|
warn "DEPRECATION WARNING: using `def_option(#{optname})` for setting options is deprecated. " \
|
96
|
-
|
96
|
+
"Define module OptionsMethods and `def option_#{optname}(val)` instead."
|
97
97
|
|
98
98
|
if layout
|
99
99
|
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
100
|
-
def option_#{optname}(value)
|
101
|
-
#{layout}
|
102
|
-
end
|
100
|
+
def option_#{optname}(value) # def option_origin(v)
|
101
|
+
#{layout} # URI(v)
|
102
|
+
end # end
|
103
103
|
OUT
|
104
|
-
elsif
|
104
|
+
elsif interpreter
|
105
105
|
define_method(:"option_#{optname}") do |value|
|
106
106
|
instance_exec(value, &interpreter)
|
107
107
|
end
|