httpx 0.15.4 → 0.18.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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/0_16_0.md +93 -0
  3. data/doc/release_notes/0_16_1.md +5 -0
  4. data/doc/release_notes/0_17_0.md +49 -0
  5. data/doc/release_notes/0_18_0.md +69 -0
  6. data/lib/httpx/adapters/datadog.rb +1 -1
  7. data/lib/httpx/adapters/faraday.rb +8 -14
  8. data/lib/httpx/adapters/webmock.rb +9 -3
  9. data/lib/httpx/altsvc.rb +2 -2
  10. data/lib/httpx/buffer.rb +1 -1
  11. data/lib/httpx/callbacks.rb +1 -1
  12. data/lib/httpx/chainable.rb +18 -11
  13. data/lib/httpx/connection/http1.rb +21 -13
  14. data/lib/httpx/connection/http2.rb +20 -25
  15. data/lib/httpx/connection.rb +73 -77
  16. data/lib/httpx/domain_name.rb +1 -1
  17. data/lib/httpx/errors.rb +11 -11
  18. data/lib/httpx/extensions.rb +50 -4
  19. data/lib/httpx/headers.rb +1 -1
  20. data/lib/httpx/io/ssl.rb +3 -3
  21. data/lib/httpx/io/tls.rb +8 -8
  22. data/lib/httpx/loggable.rb +5 -5
  23. data/lib/httpx/options.rb +108 -81
  24. data/lib/httpx/parser/http1.rb +11 -7
  25. data/lib/httpx/plugins/aws_sdk_authentication.rb +42 -18
  26. data/lib/httpx/plugins/aws_sigv4.rb +19 -20
  27. data/lib/httpx/plugins/compression.rb +17 -14
  28. data/lib/httpx/plugins/cookies/cookie.rb +4 -2
  29. data/lib/httpx/plugins/cookies/jar.rb +21 -2
  30. data/lib/httpx/plugins/cookies.rb +20 -7
  31. data/lib/httpx/plugins/digest_authentication.rb +19 -15
  32. data/lib/httpx/plugins/expect.rb +26 -18
  33. data/lib/httpx/plugins/follow_redirects.rb +9 -9
  34. data/lib/httpx/plugins/grpc/call.rb +4 -1
  35. data/lib/httpx/plugins/grpc/message.rb +2 -2
  36. data/lib/httpx/plugins/grpc.rb +72 -46
  37. data/lib/httpx/plugins/h2c.rb +7 -3
  38. data/lib/httpx/plugins/internal_telemetry.rb +8 -8
  39. data/lib/httpx/plugins/multipart/decoder.rb +187 -0
  40. data/lib/httpx/plugins/multipart/mime_type_detector.rb +3 -3
  41. data/lib/httpx/plugins/multipart/part.rb +2 -2
  42. data/lib/httpx/plugins/multipart.rb +16 -2
  43. data/lib/httpx/plugins/ntlm_authentication.rb +12 -10
  44. data/lib/httpx/plugins/proxy/socks4.rb +2 -1
  45. data/lib/httpx/plugins/proxy/socks5.rb +2 -1
  46. data/lib/httpx/plugins/proxy/ssh.rb +20 -13
  47. data/lib/httpx/plugins/proxy.rb +10 -10
  48. data/lib/httpx/plugins/response_cache/store.rb +55 -0
  49. data/lib/httpx/plugins/response_cache.rb +88 -0
  50. data/lib/httpx/plugins/retries.rb +46 -23
  51. data/lib/httpx/plugins/stream.rb +3 -4
  52. data/lib/httpx/plugins/upgrade.rb +7 -6
  53. data/lib/httpx/pool.rb +39 -13
  54. data/lib/httpx/registry.rb +2 -2
  55. data/lib/httpx/request.rb +16 -25
  56. data/lib/httpx/resolver/https.rb +4 -8
  57. data/lib/httpx/resolver/native.rb +19 -5
  58. data/lib/httpx/resolver/resolver_mixin.rb +2 -1
  59. data/lib/httpx/resolver/system.rb +2 -0
  60. data/lib/httpx/resolver.rb +2 -2
  61. data/lib/httpx/response.rb +91 -48
  62. data/lib/httpx/selector.rb +11 -24
  63. data/lib/httpx/session.rb +41 -23
  64. data/lib/httpx/session2.rb +23 -0
  65. data/lib/httpx/timers.rb +84 -0
  66. data/lib/httpx/transcoder/body.rb +3 -2
  67. data/lib/httpx/transcoder/chunker.rb +2 -1
  68. data/lib/httpx/transcoder/form.rb +20 -0
  69. data/lib/httpx/transcoder/json.rb +12 -0
  70. data/lib/httpx/transcoder.rb +62 -1
  71. data/lib/httpx/utils.rb +10 -2
  72. data/lib/httpx/version.rb +1 -1
  73. data/lib/httpx.rb +7 -3
  74. data/sig/buffer.rbs +3 -1
  75. data/sig/chainable.rbs +31 -29
  76. data/sig/connection/http1.rbs +11 -5
  77. data/sig/connection/http2.rbs +16 -5
  78. data/sig/connection.rbs +31 -13
  79. data/sig/errors.rbs +35 -1
  80. data/sig/headers.rbs +20 -19
  81. data/sig/httpx.rbs +4 -1
  82. data/sig/loggable.rbs +3 -1
  83. data/sig/options.rbs +45 -34
  84. data/sig/parser/http1.rbs +3 -3
  85. data/sig/plugins/authentication.rbs +1 -1
  86. data/sig/plugins/aws_sdk_authentication.rbs +25 -3
  87. data/sig/plugins/aws_sigv4.rbs +13 -5
  88. data/sig/plugins/basic_authentication.rbs +1 -1
  89. data/sig/plugins/compression.rbs +4 -6
  90. data/sig/plugins/cookies/cookie.rbs +5 -7
  91. data/sig/plugins/cookies/jar.rbs +9 -10
  92. data/sig/plugins/cookies.rbs +4 -5
  93. data/sig/plugins/digest_authentication.rbs +2 -3
  94. data/sig/plugins/expect.rbs +2 -4
  95. data/sig/plugins/follow_redirects.rbs +3 -5
  96. data/sig/plugins/grpc.rbs +4 -7
  97. data/sig/plugins/h2c.rbs +0 -2
  98. data/sig/plugins/multipart.rbs +64 -10
  99. data/sig/plugins/ntlm_authentication.rbs +2 -3
  100. data/sig/plugins/persistent.rbs +3 -8
  101. data/sig/plugins/proxy/ssh.rbs +4 -4
  102. data/sig/plugins/proxy.rbs +13 -13
  103. data/sig/plugins/push_promise.rbs +0 -2
  104. data/sig/plugins/response_cache.rbs +35 -0
  105. data/sig/plugins/retries.rbs +7 -8
  106. data/sig/plugins/stream.rbs +1 -1
  107. data/sig/plugins/upgrade.rbs +2 -3
  108. data/sig/pool.rbs +7 -2
  109. data/sig/registry.rbs +1 -1
  110. data/sig/request.rbs +11 -8
  111. data/sig/resolver/native.rbs +10 -5
  112. data/sig/resolver/resolver_mixin.rbs +4 -5
  113. data/sig/resolver/system.rbs +4 -0
  114. data/sig/resolver.rbs +7 -0
  115. data/sig/response.rbs +26 -13
  116. data/sig/selector.rbs +11 -9
  117. data/sig/session.rbs +22 -23
  118. data/sig/timers.rbs +32 -0
  119. data/sig/transcoder/body.rbs +6 -1
  120. data/sig/transcoder/chunker.rbs +8 -2
  121. data/sig/transcoder/form.rbs +3 -1
  122. data/sig/transcoder/json.rbs +2 -0
  123. data/sig/transcoder.rbs +13 -5
  124. data/sig/utils.rbs +6 -0
  125. metadata +18 -18
  126. data/lib/httpx/request2.rb +0 -14
@@ -69,10 +69,10 @@ module HTTPX
69
69
  end
70
70
 
71
71
  @inflight = 0
72
- @keep_alive_timeout = options.timeout[:keep_alive_timeout]
73
- @keep_alive_timer = nil
72
+ @keep_alive_timeout = @options.timeout[:keep_alive_timeout]
73
+ @total_timeout = @options.timeout[:total_timeout]
74
74
 
75
- self.addresses = options.addresses if options.addresses
75
+ self.addresses = @options.addresses if @options.addresses
76
76
  end
77
77
 
78
78
  # this is a semi-private method, to be used by the resolver
@@ -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
@@ -313,7 +333,7 @@ module HTTPX
313
333
 
314
334
  # exit #consume altogether if all outstanding requests have been dealt with
315
335
  return if @pending.size.zero? && @inflight.zero?
316
- end unless (interests.nil? || interests == :w || @state == :closing) && !epiped
336
+ end unless ((ints = interests).nil? || ints == :w || @state == :closing) && !epiped
317
337
 
318
338
  #
319
339
  # tight write loop.
@@ -360,19 +380,18 @@ module HTTPX
360
380
  break if interests == :r || @state == :closing || @state == :closed
361
381
 
362
382
  write_drained = false
363
- end unless interests == :r
383
+ end unless (ints = interests) == :r
364
384
 
365
385
  send_pending if @state == :open
366
386
 
367
387
  # return if socket is drained
368
- next unless (interests != :r || read_drained) &&
369
- (interests != :w || write_drained)
388
+ next unless (ints != :r || read_drained) && (ints != :w || write_drained)
370
389
 
371
390
  # gotta go back to the event loop. It happens when:
372
391
  #
373
392
  # * the socket is drained of bytes or it's not the interest of the conn to read;
374
393
  # * theres nothing more to write, or it's not in the interest of the conn to write;
375
- log(level: 3) { "(#{interests}): WAITING FOR EVENTS..." }
394
+ log(level: 3) { "(#{ints}): WAITING FOR EVENTS..." }
376
395
  return
377
396
  end
378
397
  end
@@ -380,9 +399,7 @@ module HTTPX
380
399
 
381
400
  def send_pending
382
401
  while !@write_buffer.full? && (request = @pending.shift)
383
- @inflight += 1
384
- @keep_alive_timer.pause if @keep_alive_timer
385
- parser.send(request)
402
+ send_request_to_parser(request)
386
403
  end
387
404
  end
388
405
 
@@ -390,6 +407,15 @@ module HTTPX
390
407
  @parser ||= build_parser
391
408
  end
392
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
+
393
419
  def build_parser(protocol = @io.protocol)
394
420
  parser = registry(protocol).new(@write_buffer, @options)
395
421
  set_parser_callbacks(parser)
@@ -401,7 +427,8 @@ module HTTPX
401
427
  AltSvc.emit(request, response) do |alt_origin, origin, alt_params|
402
428
  emit(:altsvc, alt_origin, origin, alt_params)
403
429
  end
404
- handle_response
430
+ @response_received_at = Utils.now
431
+ @inflight -= 1
405
432
  request.emit(:response, response)
406
433
  end
407
434
  parser.on(:altsvc) do |alt_origin, origin, alt_params|
@@ -421,7 +448,7 @@ module HTTPX
421
448
  end
422
449
  parser.on(:close) do |force|
423
450
  transition(:closing)
424
- if force
451
+ if force || @state == :idle
425
452
  transition(:closed)
426
453
  emit(:close)
427
454
  end
@@ -467,15 +494,17 @@ module HTTPX
467
494
  when :open
468
495
  return if @state == :closed
469
496
 
470
- total_timeout
471
-
472
497
  @io.connect
473
498
  return unless @io.connected?
474
499
 
500
+ @connected_at = Utils.now
501
+
475
502
  send_pending
476
503
 
477
504
  @timeout = @current_timeout = parser.timeout
478
505
  emit(:open)
506
+ when :inactive
507
+ return unless @state == :open
479
508
  when :closing
480
509
  return unless @state == :open
481
510
 
@@ -483,15 +512,15 @@ module HTTPX
483
512
  return unless @state == :closing
484
513
  return unless @write_buffer.empty?
485
514
 
486
- if @total_timeout
487
- @total_timeout.cancel
488
- remove_instance_variable(:@total_timeout)
489
- end
490
-
491
515
  purge_after_closed
492
516
  when :already_open
493
517
  nextstate = :open
494
518
  send_pending
519
+ when :active
520
+ return unless @state == :inactive
521
+
522
+ nextstate = :open
523
+ emit(:activate)
495
524
  end
496
525
  @state = nextstate
497
526
  rescue Errno::ECONNREFUSED,
@@ -507,44 +536,24 @@ module HTTPX
507
536
  def purge_after_closed
508
537
  @io.close if @io
509
538
  @read_buffer.clear
510
- if @keep_alive_timer
511
- @keep_alive_timer.cancel
512
- remove_instance_variable(:@keep_alive_timer)
513
- end
514
-
515
539
  remove_instance_variable(:@timeout) if defined?(@timeout)
516
540
  end
517
541
 
518
- def handle_response
519
- @inflight -= 1
520
- return unless @inflight.zero?
521
-
522
- if @keep_alive_timer
523
- @keep_alive_timer.resume
524
- @keep_alive_timer.reset
525
- else
526
- @keep_alive_timer = @timers.after(@keep_alive_timeout) do
527
- unless @inflight.zero?
528
- log { "(#{@origin}): keep alive timeout expired" }
529
- parser.ping
530
- end
531
- end
532
- end
533
- end
534
-
535
542
  def on_error(error)
536
543
  if error.instance_of?(TimeoutError)
537
- if @timeout
538
- @timeout -= error.timeout
539
- return unless @timeout <= 0
540
- end
541
544
 
542
- if @total_timeout && @total_timeout.fires_in.negative?
543
- 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")
544
548
  ex.set_backtrace(error.backtrace)
545
549
  error = ex
546
- elsif connecting?
547
- 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?
548
557
  end
549
558
  end
550
559
  handle_error(error)
@@ -559,18 +568,5 @@ module HTTPX
559
568
  request.emit(:response, response)
560
569
  end
561
570
  end
562
-
563
- def total_timeout
564
- total = @options.timeout[:total_timeout]
565
-
566
- return unless total
567
-
568
- @total_timeout ||= @timers.after(total) do
569
- ex = TotalTimeoutError.new(total, "Timed out after #{total} seconds")
570
- ex.set_backtrace(caller)
571
- on_error(ex)
572
- @parser.close if @parser
573
- end
574
- end
575
571
  end
576
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)
data/lib/httpx/errors.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- Error = Class.new(StandardError)
4
+ class Error < StandardError; end
5
5
 
6
- UnsupportedSchemeError = Class.new(Error)
6
+ class UnsupportedSchemeError < Error; end
7
7
 
8
- TimeoutError = Class.new(Error) do
8
+ class TimeoutError < Error
9
9
  attr_reader :timeout
10
10
 
11
11
  def initialize(timeout, message)
@@ -20,17 +20,17 @@ module HTTPX
20
20
  end
21
21
  end
22
22
 
23
- TotalTimeoutError = Class.new(TimeoutError)
23
+ class TotalTimeoutError < TimeoutError; end
24
24
 
25
- ConnectTimeoutError = Class.new(TimeoutError)
25
+ class ConnectTimeoutError < TimeoutError; end
26
26
 
27
- SettingsTimeoutError = Class.new(TimeoutError)
27
+ class SettingsTimeoutError < TimeoutError; end
28
28
 
29
- ResolveTimeoutError = Class.new(TimeoutError)
29
+ class ResolveTimeoutError < TimeoutError; end
30
30
 
31
- ResolveError = Class.new(Error)
31
+ class ResolveError < Error; end
32
32
 
33
- NativeResolveError = Class.new(ResolveError) do
33
+ class NativeResolveError < ResolveError
34
34
  attr_reader :connection, :host
35
35
 
36
36
  def initialize(connection, host, message = "Can't resolve #{host}")
@@ -40,7 +40,7 @@ module HTTPX
40
40
  end
41
41
  end
42
42
 
43
- HTTPError = Class.new(Error) do
43
+ class HTTPError < Error
44
44
  attr_reader :response
45
45
 
46
46
  def initialize(response)
@@ -53,5 +53,5 @@ module HTTPX
53
53
  end
54
54
  end
55
55
 
56
- MisdirectedRequestError = Class.new(HTTPError)
56
+ class MisdirectedRequestError < HTTPError; end
57
57
  end
@@ -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/headers.rb CHANGED
@@ -57,7 +57,7 @@ module HTTPX
57
57
  def merge(other)
58
58
  headers = dup
59
59
  other.each do |field, value|
60
- headers[field] = value
60
+ headers[downcased(field)] = value
61
61
  end
62
62
  headers
63
63
  end
data/lib/httpx/io/ssl.rb CHANGED
@@ -7,9 +7,9 @@ module HTTPX
7
7
 
8
8
  class SSL < TCP
9
9
  TLS_OPTIONS = if OpenSSL::SSL::SSLContext.instance_methods.include?(:alpn_protocols)
10
- { alpn_protocols: %w[h2 http/1.1] }
10
+ { alpn_protocols: %w[h2 http/1.1].freeze }.freeze
11
11
  else
12
- {}
12
+ {}.freeze
13
13
  end
14
14
 
15
15
  def initialize(_, _, options)
@@ -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
@@ -4,7 +4,7 @@ require "openssl"
4
4
 
5
5
  module HTTPX
6
6
  class TLS < TCP
7
- Error = Class.new(StandardError)
7
+ class Error < StandardError; end
8
8
 
9
9
  def initialize(_, _, options)
10
10
  super
@@ -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