httpx 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/0_18_0.md +69 -0
  3. data/lib/httpx/adapters/datadog.rb +1 -1
  4. data/lib/httpx/adapters/faraday.rb +5 -3
  5. data/lib/httpx/adapters/webmock.rb +7 -1
  6. data/lib/httpx/altsvc.rb +2 -2
  7. data/lib/httpx/chainable.rb +3 -3
  8. data/lib/httpx/connection/http1.rb +3 -3
  9. data/lib/httpx/connection/http2.rb +6 -4
  10. data/lib/httpx/connection.rb +67 -70
  11. data/lib/httpx/domain_name.rb +1 -1
  12. data/lib/httpx/extensions.rb +50 -4
  13. data/lib/httpx/io/ssl.rb +1 -1
  14. data/lib/httpx/io/tls.rb +7 -7
  15. data/lib/httpx/loggable.rb +5 -5
  16. data/lib/httpx/options.rb +7 -7
  17. data/lib/httpx/plugins/aws_sdk_authentication.rb +42 -18
  18. data/lib/httpx/plugins/aws_sigv4.rb +9 -11
  19. data/lib/httpx/plugins/compression.rb +5 -3
  20. data/lib/httpx/plugins/cookies/jar.rb +1 -1
  21. data/lib/httpx/plugins/expect.rb +7 -3
  22. data/lib/httpx/plugins/grpc/message.rb +2 -2
  23. data/lib/httpx/plugins/grpc.rb +3 -3
  24. data/lib/httpx/plugins/internal_telemetry.rb +8 -8
  25. data/lib/httpx/plugins/multipart.rb +2 -2
  26. data/lib/httpx/plugins/response_cache/store.rb +55 -0
  27. data/lib/httpx/plugins/response_cache.rb +88 -0
  28. data/lib/httpx/plugins/retries.rb +22 -3
  29. data/lib/httpx/plugins/stream.rb +1 -1
  30. data/lib/httpx/pool.rb +39 -13
  31. data/lib/httpx/request.rb +6 -6
  32. data/lib/httpx/resolver/https.rb +5 -7
  33. data/lib/httpx/resolver/native.rb +4 -2
  34. data/lib/httpx/resolver/system.rb +2 -0
  35. data/lib/httpx/resolver.rb +2 -2
  36. data/lib/httpx/response.rb +23 -14
  37. data/lib/httpx/selector.rb +5 -17
  38. data/lib/httpx/session.rb +7 -2
  39. data/lib/httpx/session2.rb +1 -1
  40. data/lib/httpx/timers.rb +84 -0
  41. data/lib/httpx/transcoder/body.rb +2 -1
  42. data/lib/httpx/transcoder/form.rb +1 -1
  43. data/lib/httpx/transcoder/json.rb +1 -1
  44. data/lib/httpx/utils.rb +8 -0
  45. data/lib/httpx/version.rb +1 -1
  46. data/lib/httpx.rb +1 -0
  47. data/sig/chainable.rbs +1 -0
  48. data/sig/connection.rbs +12 -6
  49. data/sig/plugins/aws_sdk_authentication.rbs +22 -4
  50. data/sig/plugins/response_cache.rbs +35 -0
  51. data/sig/plugins/retries.rbs +3 -0
  52. data/sig/pool.rbs +6 -0
  53. data/sig/resolver/native.rbs +3 -4
  54. data/sig/resolver/system.rbs +2 -0
  55. data/sig/response.rbs +3 -2
  56. data/sig/timers.rbs +32 -0
  57. data/sig/utils.rbs +4 -0
  58. metadata +10 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6b2befec2e4b0093acd45f7ef9ef448ad41516510710616aded46934f1e3981
4
- data.tar.gz: a9858adfacbdc27e1097b98b958f7dd1614f1207c74ec4290a54268df6270f69
3
+ metadata.gz: 372f89cdf05727a32d23467503299ae77831cb5d23356467dc0c7f3a22bbfd0c
4
+ data.tar.gz: bbb3df9079bf4f5a449f37f34dd6b1d3208a978e8a8eaa7fdd69ea9d1829ac6c
5
5
  SHA512:
6
- metadata.gz: 86276d59efaf3a15efe0a27fbd59bff2d005bb3bab83ee9917599854bf46eba1bfbb016b9df55172c41799d1fe82195e4bb7d82c008c1996814ec2e393be71b3
7
- data.tar.gz: bd113e65cf5700f231992bb485f6c59511f114372d53078ea53c019a654e449e5012b2a1a19f889d79cee1eecd24345d3e03f3f9fa50aa6c69060138327e1d09
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.
@@ -64,7 +64,7 @@ module Datadog
64
64
  def finish(response)
65
65
  return unless @span
66
66
 
67
- if response.respond_to?(:error)
67
+ if response.is_a?(::HTTPX::ErrorResponse)
68
68
  @span.set_error(response.error)
69
69
  else
70
70
  @span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status.to_s)
@@ -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
- }.reject { |_, v| v.nil? }
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 block_given?
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 block_given?
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 ErrorResponse.new(request, webmock_response.exception, request.options) if webmock_response.exception
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 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
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 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
20
+ now = Utils.now
21
21
  @altsvc_mutex.synchronize do
22
22
  return if @altsvcs[origin].any? { |altsvc| altsvc["origin"] == entry["origin"] }
23
23
 
@@ -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 != @requests[requests_limit - 1]
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 !@pings.delete(ping.to_s)
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
@@ -70,7 +70,7 @@ module HTTPX
70
70
 
71
71
  @inflight = 0
72
72
  @keep_alive_timeout = @options.timeout[:keep_alive_timeout]
73
- @keep_alive_timer = nil
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
- @parser.close if @parser
204
- return unless @keep_alive_timer
203
+ transition(:active) if @state == :inactive
205
204
 
206
- @keep_alive_timer.cancel
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
- if @keep_alive_timer
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
- if @keep_alive_timer.fires_in.negative?
224
- @pending << request
225
- parser.ping
226
- return
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
- @inflight += 1
232
- parser.send(request)
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
- @inflight += 1
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
- handle_response
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 && @total_timeout.fires_in.negative?
542
- ex = TotalTimeoutError.new(@total_timeout.interval, "Timed out after #{@total_timeout.interval} seconds")
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
- elsif connecting?
546
- error = error.to_connection_error
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
@@ -123,7 +123,7 @@ module HTTPX
123
123
 
124
124
  # RFC 6265 #4.1.1
125
125
  # Domain-value must be a subdomain.
126
- @domain && self <= domain && domain <= @domain ? true : false
126
+ @domain && self <= domain && domain <= @domain
127
127
  end
128
128
 
129
129
  # def ==(other)
@@ -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
- port_string = port == default_port ? nil : ":#{port}"
81
- "#{host}#{port_string}"
82
- end
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
- "SSL connection using #{@io.ssl_version} / #{Array(@io.cipher).first}\n" \
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
- "SSL connection using #{@ctx.ssl_version} / #{Array(@ctx.cipher).first}\n" \
198
- "ALPN, server accepted to use #{protocol}\n" +
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
- " 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."
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
@@ -24,15 +24,13 @@ module HTTPX
24
24
  debug_stream << message
25
25
  end
26
26
 
27
- if !Exception.instance_methods.include?(:full_message)
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
- message = +"#{ex.message} (#{ex.class})"
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
- log(level: level, color: color) { ex.full_message }
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? && !block_given?
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
- "Define module OptionsMethods and `def option_#{optname}(val)` instead."
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 block_given?
104
+ elsif interpreter
105
105
  define_method(:"option_#{optname}") do |value|
106
106
  instance_exec(value, &interpreter)
107
107
  end