httpx 0.15.4 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/httpx/session.rb CHANGED
@@ -11,18 +11,17 @@ module HTTPX
11
11
  @options = self.class.default_options.merge(options)
12
12
  @responses = {}
13
13
  @persistent = @options.persistent
14
- wrap(&blk) if block_given?
14
+ wrap(&blk) if blk
15
15
  end
16
16
 
17
17
  def wrap
18
- return unless block_given?
19
-
20
18
  begin
21
19
  prev_persistent = @persistent
22
20
  @persistent = true
23
21
  yield self
24
22
  ensure
25
23
  @persistent = prev_persistent
24
+ close unless @persistent
26
25
  end
27
26
  end
28
27
 
@@ -31,8 +30,10 @@ module HTTPX
31
30
  end
32
31
 
33
32
  def request(*args, **options)
33
+ raise ArgumentError, "must perform at least one request" if args.empty?
34
+
34
35
  requests = args.first.is_a?(Request) ? args : build_requests(*args, options)
35
- responses = send_requests(*requests, options)
36
+ responses = send_requests(*requests)
36
37
  return responses.first if responses.size == 1
37
38
 
38
39
  responses
@@ -40,7 +41,8 @@ module HTTPX
40
41
 
41
42
  def build_request(verb, uri, options = EMPTY_HASH)
42
43
  rklass = @options.request_class
43
- request = rklass.new(verb, uri, @options.merge(options).merge(persistent: @persistent))
44
+ options = @options.merge(options) unless options.is_a?(Options)
45
+ request = rklass.new(verb, uri, options.merge(persistent: @persistent))
44
46
  request.on(:response, &method(:on_response).curry(2)[request])
45
47
  request.on(:promise, &method(:on_promise))
46
48
  request
@@ -174,37 +176,38 @@ module HTTPX
174
176
  end
175
177
  end
176
178
 
177
- def send_requests(*requests, options)
178
- request_options = @options.merge(options)
179
-
180
- connections = _send_requests(requests, request_options)
181
- receive_requests(requests, connections, request_options)
179
+ def send_requests(*requests)
180
+ connections = _send_requests(requests)
181
+ receive_requests(requests, connections)
182
182
  end
183
183
 
184
- def _send_requests(requests, options)
184
+ def _send_requests(requests)
185
185
  connections = []
186
186
 
187
187
  requests.each do |request|
188
188
  error = catch(:resolve_error) do
189
- connection = find_connection(request, connections, options)
189
+ connection = find_connection(request, connections, request.options)
190
190
  connection.send(request)
191
191
  end
192
192
  next unless error.is_a?(ResolveError)
193
193
 
194
- request.emit(:response, ErrorResponse.new(request, error, options))
194
+ request.emit(:response, ErrorResponse.new(request, error, request.options))
195
195
  end
196
196
 
197
197
  connections
198
198
  end
199
199
 
200
- def receive_requests(requests, connections, options)
200
+ def receive_requests(requests, connections)
201
201
  responses = []
202
202
 
203
203
  begin
204
204
  # guarantee ordered responses
205
205
  loop do
206
206
  request = requests.first
207
- pool.next_tick until (response = fetch_response(request, connections, options))
207
+
208
+ return responses unless request
209
+
210
+ pool.next_tick until (response = fetch_response(request, connections, request.options))
208
211
 
209
212
  responses << response
210
213
  requests.shift
@@ -218,13 +221,17 @@ module HTTPX
218
221
  # opportunity to traverse the requests, hence we're returning only a fraction of the errors
219
222
  # we were supposed to. This effectively fetches the existing responses and return them.
220
223
  while (request = requests.shift)
221
- responses << fetch_response(request, connections, options)
224
+ responses << fetch_response(request, connections, request.options)
222
225
  end
223
226
  break
224
227
  end
225
228
  responses
226
229
  ensure
227
- close(connections) unless @persistent
230
+ if @persistent
231
+ pool.deactivate(connections)
232
+ else
233
+ close(connections)
234
+ end
228
235
  end
229
236
  end
230
237
 
@@ -247,9 +254,8 @@ module HTTPX
247
254
  if !@plugins.include?(pl)
248
255
  @plugins << pl
249
256
  pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies)
257
+
250
258
  @default_options = @default_options.dup
251
- @default_options = pl.extra_options(@default_options, &block) if pl.respond_to?(:extra_options)
252
- @default_options = @default_options.merge(options) if options
253
259
 
254
260
  include(pl::InstanceMethods) if defined?(pl::InstanceMethods)
255
261
  extend(pl::ClassMethods) if defined?(pl::ClassMethods)
@@ -266,14 +272,26 @@ module HTTPX
266
272
  opts.response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
267
273
  opts.response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
268
274
  opts.connection_class.__send__(:include, pl::ConnectionMethods) if defined?(pl::ConnectionMethods)
275
+ if defined?(pl::OptionsMethods)
276
+ opts.options_class.__send__(:include, pl::OptionsMethods)
277
+
278
+ (pl::OptionsMethods.instance_methods - Object.instance_methods).each do |meth|
279
+ opts.options_class.method_added(meth)
280
+ end
281
+ @default_options = opts.options_class.new(opts)
282
+ end
283
+
284
+ @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
285
+ @default_options = @default_options.merge(options) if options
286
+
269
287
  pl.configure(self, &block) if pl.respond_to?(:configure)
270
288
 
271
289
  @default_options.freeze
272
290
  elsif options
273
291
  # this can happen when two plugins are loaded, an one of them calls the other under the hood,
274
292
  # albeit changing some default.
275
- @default_options = @default_options.dup
276
- @default_options = @default_options.merge(options)
293
+ @default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
294
+ @default_options = @default_options.merge(options) if options
277
295
 
278
296
  @default_options.freeze
279
297
  end
@@ -283,8 +301,8 @@ module HTTPX
283
301
  # :nocov:
284
302
  def plugins(pls)
285
303
  warn ":#{__method__} is deprecated, use :plugin instead"
286
- pls.each do |pl, *args|
287
- plugin(pl, *args)
304
+ pls.each do |pl|
305
+ plugin(pl)
288
306
  end
289
307
  self
290
308
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "session"
4
+ module HTTPX
5
+ class Session
6
+ def initialize(options = EMPTY_HASH, &blk)
7
+ @options = self.class.default_options.merge(options)
8
+ @responses = {}
9
+ @persistent = @options.persistent
10
+ wrap(&blk) if blk
11
+ end
12
+
13
+ def wrap
14
+ begin
15
+ prev_persistent = @persistent
16
+ @persistent = true
17
+ yield self
18
+ ensure
19
+ @persistent = prev_persistent
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ class Timers
5
+ def initialize
6
+ @intervals = []
7
+ end
8
+
9
+ def after(interval_in_secs, &blk)
10
+ return unless interval_in_secs
11
+
12
+ # I'm assuming here that most requests will have the same
13
+ # request timeout, as in most cases they share common set of
14
+ # options. A user setting different request timeouts for 100s of
15
+ # requests will already have a hard time dealing with that.
16
+ unless (interval = @intervals.find { |t| t == interval_in_secs })
17
+ interval = Interval.new(interval_in_secs)
18
+ @intervals << interval
19
+ @intervals.sort!
20
+ end
21
+
22
+ interval << blk
23
+ end
24
+
25
+ def wait_interval
26
+ return if @intervals.empty?
27
+
28
+ @next_interval_at = Utils.now
29
+
30
+ @intervals.first.interval
31
+ end
32
+
33
+ def fire(error = nil)
34
+ raise error if error && error.timeout != @intervals.first
35
+ return if @intervals.empty? || !@next_interval_at
36
+
37
+ elapsed_time = Utils.elapsed_time(@next_interval_at)
38
+
39
+ @intervals.delete_if { |interval| interval.elapse(elapsed_time) <= 0 }
40
+ end
41
+
42
+ def cancel
43
+ @intervals.clear
44
+ end
45
+
46
+ class Interval
47
+ include Comparable
48
+
49
+ attr_reader :interval
50
+
51
+ def initialize(interval)
52
+ @interval = interval
53
+ @callbacks = []
54
+ end
55
+
56
+ def <=>(other)
57
+ @interval <=> other.interval
58
+ end
59
+
60
+ def ==(other)
61
+ return @interval == other if other.is_a?(Numeric)
62
+
63
+ @interval == other.to_f # rubocop:disable Lint/FloatComparison
64
+ end
65
+
66
+ def to_f
67
+ @interval
68
+ end
69
+
70
+ def <<(callback)
71
+ @callbacks << callback
72
+ end
73
+
74
+ def elapse(elapsed)
75
+ @interval -= elapsed
76
+
77
+ @callbacks.each(&:call) if @interval <= 0
78
+
79
+ @interval
80
+ end
81
+ end
82
+ private_constant :Interval
83
+ end
84
+ end
@@ -4,11 +4,12 @@ require "forwardable"
4
4
 
5
5
  module HTTPX::Transcoder
6
6
  module Body
7
- Error = Class.new(HTTPX::Error)
7
+ class Error < HTTPX::Error; end
8
8
 
9
9
  module_function
10
10
 
11
11
  class Encoder
12
+ using HTTPX::ArrayExtensions
12
13
  extend Forwardable
13
14
 
14
15
  def_delegator :@raw, :to_s
@@ -21,7 +22,7 @@ module HTTPX::Transcoder
21
22
  if @raw.respond_to?(:bytesize)
22
23
  @raw.bytesize
23
24
  elsif @raw.respond_to?(:to_ary)
24
- @raw.map(&:bytesize).reduce(0, :+)
25
+ @raw.sum(&:bytesize)
25
26
  elsif @raw.respond_to?(:size)
26
27
  @raw.size || Float::INFINITY
27
28
  elsif @raw.respond_to?(:length)
@@ -4,7 +4,8 @@ require "forwardable"
4
4
 
5
5
  module HTTPX::Transcoder
6
6
  module Chunker
7
- Error = Class.new(HTTPX::Error)
7
+ class Error < HTTPX::Error; end
8
+
8
9
  CRLF = "\r\n".b
9
10
 
10
11
  class Encoder
@@ -7,6 +7,8 @@ module HTTPX::Transcoder
7
7
  module Form
8
8
  module_function
9
9
 
10
+ PARAM_DEPTH_LIMIT = 32
11
+
10
12
  class Encoder
11
13
  extend Forwardable
12
14
 
@@ -31,9 +33,27 @@ module HTTPX::Transcoder
31
33
  end
32
34
  end
33
35
 
36
+ module Decoder
37
+ module_function
38
+
39
+ def call(response, _)
40
+ URI.decode_www_form(response.to_s).each_with_object({}) do |(field, value), params|
41
+ HTTPX::Transcoder.normalize_query(params, field, value, PARAM_DEPTH_LIMIT)
42
+ end
43
+ end
44
+ end
45
+
34
46
  def encode(form)
35
47
  Encoder.new(form)
36
48
  end
49
+
50
+ def decode(response)
51
+ content_type = response.content_type.mime_type
52
+
53
+ raise HTTPX::Error, "invalid form mime type (#{content_type})" unless content_type == "application/x-www-form-urlencoded"
54
+
55
+ Decoder
56
+ end
37
57
  end
38
58
  register "form", Form
39
59
  end
@@ -5,6 +5,10 @@ require "json"
5
5
 
6
6
  module HTTPX::Transcoder
7
7
  module JSON
8
+ JSON_REGEX = %r{\bapplication/(?:vnd\.api\+)?json\b}i.freeze
9
+
10
+ using HTTPX::RegexpExtensions unless Regexp.method_defined?(:match?)
11
+
8
12
  module_function
9
13
 
10
14
  class Encoder
@@ -27,6 +31,14 @@ module HTTPX::Transcoder
27
31
  def encode(json)
28
32
  Encoder.new(json)
29
33
  end
34
+
35
+ def decode(response)
36
+ content_type = response.content_type.mime_type
37
+
38
+ raise HTTPX::Error, "invalid json mime type (#{content_type})" unless JSON_REGEX.match?(content_type)
39
+
40
+ ::JSON.method(:parse)
41
+ end
30
42
  end
31
43
  register "json", JSON
32
44
  end
@@ -4,7 +4,11 @@ module HTTPX
4
4
  module Transcoder
5
5
  extend Registry
6
6
 
7
- def self.normalize_keys(key, value, cond = nil, &block)
7
+ using RegexpExtensions unless Regexp.method_defined?(:match?)
8
+
9
+ module_function
10
+
11
+ def normalize_keys(key, value, cond = nil, &block)
8
12
  if (cond && cond.call(value))
9
13
  block.call(key.to_s, value)
10
14
  elsif value.respond_to?(:to_ary)
@@ -23,6 +27,63 @@ module HTTPX
23
27
  block.call(key.to_s, value)
24
28
  end
25
29
  end
30
+
31
+ # based on https://github.com/rack/rack/blob/d15dd728440710cfc35ed155d66a98dc2c07ae42/lib/rack/query_parser.rb#L82
32
+ def normalize_query(params, name, v, depth)
33
+ raise Error, "params depth surpasses what's supported" if depth <= 0
34
+
35
+ name =~ /\A[\[\]]*([^\[\]]+)\]*/
36
+ k = Regexp.last_match(1) || ""
37
+ after = Regexp.last_match ? Regexp.last_match.post_match : ""
38
+
39
+ if k.empty?
40
+ return Array(v) if !v.empty? && name == "[]"
41
+
42
+ return
43
+ end
44
+
45
+ case after
46
+ when ""
47
+ params[k] = v
48
+ when "["
49
+ params[name] = v
50
+ when "[]"
51
+ params[k] ||= []
52
+ raise Error, "expected Array (got #{params[k].class}) for param '#{k}'" unless params[k].is_a?(Array)
53
+
54
+ params[k] << v
55
+ when /^\[\]\[([^\[\]]+)\]$/, /^\[\](.+)$/
56
+ child_key = Regexp.last_match(1)
57
+ params[k] ||= []
58
+ raise Error, "expected Array (got #{params[k].class}) for param '#{k}'" unless params[k].is_a?(Array)
59
+
60
+ if params[k].last.is_a?(Hash) && !params_hash_has_key?(params[k].last, child_key)
61
+ normalize_query(params[k].last, child_key, v, depth - 1)
62
+ else
63
+ params[k] << normalize_query({}, child_key, v, depth - 1)
64
+ end
65
+ else
66
+ params[k] ||= {}
67
+ raise Error, "expected Hash (got #{params[k].class}) for param '#{k}'" unless params[k].is_a?(Hash)
68
+
69
+ params[k] = normalize_query(params[k], after, v, depth - 1)
70
+ end
71
+
72
+ params
73
+ end
74
+
75
+ def params_hash_has_key?(hash, key)
76
+ return false if /\[\]/.match?(key)
77
+
78
+ key.split(/[\[\]]+/).inject(hash) do |h, part|
79
+ next h if part == ""
80
+ return false unless h.is_a?(Hash) && h.key?(part)
81
+
82
+ h[part]
83
+ end
84
+
85
+ true
86
+ end
26
87
  end
27
88
  end
28
89
 
data/lib/httpx/utils.rb CHANGED
@@ -6,6 +6,14 @@ module HTTPX
6
6
 
7
7
  module_function
8
8
 
9
+ def now
10
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
11
+ end
12
+
13
+ def elapsed_time(monotonic_timestamp)
14
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - monotonic_timestamp
15
+ end
16
+
9
17
  # The value of this field can be either an HTTP-date or a number of
10
18
  # seconds to delay after the response is received.
11
19
  def parse_retry_after(retry_after)
@@ -28,9 +36,9 @@ module HTTPX
28
36
  URIParser = URI::RFC2396_Parser.new
29
37
 
30
38
  def to_uri(uri)
31
- return Kernel.URI(uri) unless uri.is_a?(String) && !uri.ascii_only?
39
+ return URI(uri) unless uri.is_a?(String) && !uri.ascii_only?
32
40
 
33
- uri = Kernel.URI(URIParser.escape(uri))
41
+ uri = URI(URIParser.escape(uri))
34
42
 
35
43
  non_ascii_hostname = URIParser.unescape(uri.host)
36
44
 
data/lib/httpx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "0.15.4"
4
+ VERSION = "0.18.0"
5
5
  end
data/lib/httpx.rb CHANGED
@@ -13,6 +13,7 @@ require "httpx/callbacks"
13
13
  require "httpx/loggable"
14
14
  require "httpx/registry"
15
15
  require "httpx/transcoder"
16
+ require "httpx/timers"
16
17
  require "httpx/pool"
17
18
  require "httpx/headers"
18
19
  require "httpx/request"
@@ -20,6 +21,7 @@ require "httpx/response"
20
21
  require "httpx/options"
21
22
  require "httpx/chainable"
22
23
 
24
+ require "mutex_m"
23
25
  # Top-Level Namespace
24
26
  #
25
27
  module HTTPX
@@ -28,15 +30,16 @@ module HTTPX
28
30
  #
29
31
  module Plugins
30
32
  @plugins = {}
33
+ @plugins.extend(Mutex_m)
31
34
 
32
35
  # Loads a plugin based on a name. If the plugin hasn't been loaded, tries to load
33
36
  # it from the load path under "httpx/plugins/" directory.
34
37
  #
35
38
  def self.load_plugin(name)
36
39
  h = @plugins
37
- unless (plugin = h[name])
40
+ unless (plugin = h.synchronize { h[name] })
38
41
  require "httpx/plugins/#{name}"
39
- raise "Plugin #{name} hasn't been registered" unless (plugin = h[name])
42
+ raise "Plugin #{name} hasn't been registered" unless (plugin = h.synchronize { h[name] })
40
43
  end
41
44
  plugin
42
45
  end
@@ -44,7 +47,8 @@ module HTTPX
44
47
  # Registers a plugin (+mod+) in the central store indexed by +name+.
45
48
  #
46
49
  def self.register_plugin(name, mod)
47
- @plugins[name] = mod
50
+ h = @plugins
51
+ h.synchronize { h[name] = mod }
48
52
  end
49
53
  end
50
54
 
data/sig/buffer.rbs CHANGED
@@ -1,5 +1,7 @@
1
1
  module HTTPX
2
2
  class Buffer
3
+ extend Forwardable
4
+
3
5
  include _ToS
4
6
  include _ToStr
5
7
 
@@ -11,7 +13,7 @@ module HTTPX
11
13
  def shift!: (Integer) -> void
12
14
 
13
15
  # delegated
14
- def <<: (string data) -> void
16
+ def <<: (string data) -> String
15
17
  def empty?: () -> bool
16
18
  def bytesize: () -> Integer
17
19
  def clear: () -> void
data/sig/chainable.rbs CHANGED
@@ -1,43 +1,45 @@
1
1
  module HTTPX
2
2
  module Chainable
3
- def request: (*untyped, **untyped) -> (response | Array[response])
3
+ def request: (*Request, **untyped) -> Array[response]
4
+ | (Request, **untyped) -> response
5
+ | (verb | string, uri | [uri], **untyped) -> response
6
+ | (Array[[verb | string, uri] | [verb | string, uri, options]], **untyped) -> Array[response]
7
+ | (verb | string, _Each[uri | [uri, options]], **untyped) -> Array[response]
8
+
4
9
  def accept: (String) -> Session
5
10
  def wrap: () { (Session) -> void } -> void
6
- | () -> void
7
11
 
8
12
  def with: (options) -> Session
9
- | (options) { (Session) -> Session} -> Session
10
-
11
-
12
-
13
+ | (options) { (Session) -> void } -> void
13
14
 
14
- def plugin: (:authentication) -> Plugins::sessionAuthentication
15
- | (:basic_authentication) -> Plugins::sessionBasicAuthentication
16
- | (:digest_authentication) -> Plugins::sessionDigestAuthentication
17
- | (:ntlm_authentication) -> Plugins::sessionNTLMAuthentication
18
- | (:aws_sdk_authentication) -> Plugins::sessionAwsSdkAuthentication
19
- | (:compression) -> Session
20
- | (:cookies) -> Plugins::sessionCookies
21
- | (:expect) -> Session
22
- | (:follow_redirects) -> Plugins::sessionFollowRedirects
23
- | (:upgrade) -> Session
24
- | (:h2c) -> Session
25
- | (:multipart) -> Session
26
- | (:persistent) -> Plugins::sessionPersistent
27
- | (:proxy) -> Plugins::sessionProxy
28
- | (:push_promise) -> Plugins::sessionPushPromise
29
- | (:retries) -> Plugins::sessionRetries
30
- | (:rate_limiter) -> Session
31
- | (:stream) -> Plugins::sessionStream
32
- | (:aws_sigv4) -> Plugins::awsSigV4Session
33
- | (:grpc) -> Plugins::grpcSession
34
- | (Symbol | Module, ?options?) { (Class) -> void } -> Session
35
- | (Symbol | Module, ?options?) -> Session
15
+ def plugin: (:authentication, ?options) -> Plugins::sessionAuthentication
16
+ | (:basic_authentication, ?options) -> Plugins::sessionBasicAuthentication
17
+ | (:digest_authentication, ?options) -> Plugins::sessionDigestAuthentication
18
+ | (:ntlm_authentication, ?options) -> Plugins::sessionNTLMAuthentication
19
+ | (:aws_sdk_authentication, ?options) -> Plugins::sessionAwsSdkAuthentication
20
+ | (:compression, ?options) -> Session
21
+ | (:cookies, ?options) -> Plugins::sessionCookies
22
+ | (:expect, ?options) -> Session
23
+ | (:follow_redirects, ?options) -> Plugins::sessionFollowRedirects
24
+ | (:upgrade, ?options) -> Session
25
+ | (:h2c, ?options) -> Session
26
+ | (:multipart, ?options) -> Session
27
+ | (:persistent, ?options) -> Plugins::sessionPersistent
28
+ | (:proxy, ?options) -> Plugins::sessionProxy
29
+ | (:push_promise, ?options) -> Plugins::sessionPushPromise
30
+ | (:retries, ?options) -> Plugins::sessionRetries
31
+ | (:rate_limiter, ?options) -> Session
32
+ | (:stream, ?options) -> Plugins::sessionStream
33
+ | (:aws_sigv4, ?options) -> Plugins::awsSigV4Session
34
+ | (:grpc, ?options) -> Plugins::grpcSession
35
+ | (:response_cache, ?options) -> Plugins::sessionResponseCache
36
+ | (Symbol | Module, ?options) { (Class) -> void } -> Session
37
+ | (Symbol | Module, ?options) -> Session
36
38
 
37
39
  private
38
40
 
39
41
  def default_options: () -> Options
40
42
  def branch: (options) -> Session
41
- | (options) { (Session) -> Session } -> Session
43
+ | (options) { (Session) -> void } -> Session
42
44
  end
43
45
  end
@@ -3,13 +3,17 @@ module HTTPX
3
3
  include Callbacks
4
4
  include Loggable
5
5
 
6
+ UPCASED: Hash[String, String]
7
+ MAX_REQUESTS: Integer
8
+ CRLF: String
9
+
6
10
  attr_reader pending: Array[Request]
7
11
  attr_reader requests: Array[Request]
8
12
 
9
13
  @options: Options
10
14
  @max_concurrent_requests: Integer
11
15
  @max_requests: Integer
12
- @parser: HTTP1
16
+ @parser: Parser::HTTP1
13
17
  @buffer: Buffer
14
18
 
15
19
  def interests: () -> io_interests?
@@ -30,11 +34,13 @@ module HTTPX
30
34
 
31
35
  def handle_error: (StandardError ex) -> void
32
36
 
37
+ def on_start: () -> void
38
+
33
39
  def on_headers: (Hash[String, Array[String]] headers) -> void
34
40
 
35
41
  def on_trailers: (Hash[String, Array[String]] headers) -> void
36
42
 
37
- def on_data: (string chunk) -> void
43
+ def on_data: (String chunk) -> void
38
44
 
39
45
  def on_complete: () -> void
40
46
 
@@ -42,7 +48,7 @@ module HTTPX
42
48
 
43
49
  def ping: () -> void
44
50
 
45
- def timeout: () -> Integer
51
+ def timeout: () -> Numeric
46
52
 
47
53
  private
48
54
 
@@ -54,7 +60,7 @@ module HTTPX
54
60
 
55
61
  def disable_pipelining: () -> void
56
62
 
57
- def set_protocol_headers: (Request) -> _Each[headers_key, String]
63
+ def set_protocol_headers: (Request) -> _Each[[String, String]]
58
64
 
59
65
  def headline_uri: (Request) -> String
60
66
 
@@ -64,7 +70,7 @@ module HTTPX
64
70
 
65
71
  def join_trailers: (Request request) -> void
66
72
 
67
- def join_headers2: (_Each[headers_key, String] headers) -> void
73
+ def join_headers2: (_Each[[String, String]] headers) -> void
68
74
 
69
75
  def join_body: (Request request) -> void
70
76