httpx 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/httpx/session.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
+ # Class implementing the APIs being used publicly.
5
+ #
6
+ # HTTPX.get(..) #=> delegating to an internal HTTPX::Session object.
7
+ # HTTPX.plugin(..).get(..) #=> creating an intermediate HTTPX::Session with plugin, then sending the GET request
4
8
  class Session
5
9
  include Loggable
6
10
  include Chainable
@@ -8,6 +12,10 @@ module HTTPX
8
12
 
9
13
  EMPTY_HASH = {}.freeze
10
14
 
15
+ # initializes the session with a set of +options+, which will be shared by all
16
+ # requests sent from it.
17
+ #
18
+ # When pass a block, it'll yield itself to it, then closes after the block is evaluated.
11
19
  def initialize(options = EMPTY_HASH, &blk)
12
20
  @options = self.class.default_options.merge(options)
13
21
  @responses = {}
@@ -15,6 +23,11 @@ module HTTPX
15
23
  wrap(&blk) if blk
16
24
  end
17
25
 
26
+ # Yields itself the block, then closes it after the block is evaluated.
27
+ #
28
+ # session.wrap do |http|
29
+ # http.get("https://wikipedia.com")
30
+ # end # wikipedia connection closes here
18
31
  def wrap
19
32
  begin
20
33
  prev_persistent = @persistent
@@ -26,10 +39,31 @@ module HTTPX
26
39
  end
27
40
  end
28
41
 
42
+ # closes all the active connections from the session
29
43
  def close(*args)
30
44
  pool.close(*args)
31
45
  end
32
46
 
47
+ # performs one, or multple requests; it accepts:
48
+ #
49
+ # 1. one or multiple HTTPX::Request objects;
50
+ # 2. an HTTP verb, then a sequence of URIs or URI/options tuples;
51
+ # 3. one or multiple HTTP verb / uri / (optional) options tuples;
52
+ #
53
+ # when present, the set of +options+ kwargs is applied to all of the
54
+ # sent requests.
55
+ #
56
+ # respectively returns a single HTTPX::Response response, or all of them in an Array, in the same order.
57
+ #
58
+ # resp1 = session.request(req1)
59
+ # resp1, resp2 = session.request(req1, req2)
60
+ # resp1 = session.request("GET", "https://server.org/a")
61
+ # resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"])
62
+ # resp1, resp2 = session.request(["GET", "https://server.org/a"], ["GET", "https://server.org/b"])
63
+ # resp1 = session.request("POST", "https://server.org/a", form: { "foo" => "bar" })
64
+ # resp1, resp2 = session.request(["POST", "https://server.org/a", form: { "foo" => "bar" }], ["GET", "https://server.org/b"])
65
+ # resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"], headers: { "x-api-token" => "TOKEN" })
66
+ #
33
67
  def request(*args, **options)
34
68
  raise ArgumentError, "must perform at least one request" if args.empty?
35
69
 
@@ -40,10 +74,17 @@ module HTTPX
40
74
  responses
41
75
  end
42
76
 
77
+ # returns a HTTP::Request instance built from the HTTP +verb+, the request +uri+, and
78
+ # the optional set of request-specific +options+. This request **must** be sent through
79
+ # the same session it was built from.
80
+ #
81
+ # req = session.build_request("GET", "https://server.com")
82
+ # resp = session.request(req)
43
83
  def build_request(verb, uri, options = EMPTY_HASH)
44
84
  rklass = @options.request_class
45
85
  options = @options.merge(options) unless options.is_a?(Options)
46
- request = rklass.new(verb, uri, options.merge(persistent: @persistent))
86
+ request = rklass.new(verb, uri, options)
87
+ request.persistent = @persistent
47
88
  request.on(:response, &method(:on_response).curry(2)[request])
48
89
  request.on(:promise, &method(:on_promise))
49
90
 
@@ -76,23 +117,29 @@ module HTTPX
76
117
 
77
118
  private
78
119
 
120
+ # returns the HTTPX::Pool object which manages the networking required to
121
+ # perform requests.
79
122
  def pool
80
123
  Thread.current[:httpx_connection_pool] ||= Pool.new
81
124
  end
82
125
 
126
+ # callback executed when a response for a given request has been received.
83
127
  def on_response(request, response)
84
128
  @responses[request] = response
85
129
  end
86
130
 
131
+ # callback executed when an HTTP/2 promise frame has been received.
87
132
  def on_promise(_, stream)
88
133
  log(level: 2) { "#{stream.id}: refusing stream!" }
89
134
  stream.refuse
90
135
  end
91
136
 
137
+ # returns the corresponding HTTP::Response to the given +request+ if it has been received.
92
138
  def fetch_response(request, _, _)
93
139
  @responses.delete(request)
94
140
  end
95
141
 
142
+ # returns the HTTPX::Connection through which the +request+ should be sent through.
96
143
  def find_connection(request, connections, options)
97
144
  uri = request.uri
98
145
 
@@ -104,6 +151,8 @@ module HTTPX
104
151
  connection
105
152
  end
106
153
 
154
+ # sets the callbacks on the +connection+ required to process certain specific
155
+ # connection lifecycle events which deal with request rerouting.
107
156
  def set_connection_callbacks(connection, connections, options)
108
157
  connection.only(:misdirected) do |misdirected_request|
109
158
  other_connection = connection.create_idle(ssl: { alpn_protocols: %w[http/1.1] })
@@ -131,6 +180,7 @@ module HTTPX
131
180
  end
132
181
  end
133
182
 
183
+ # returns an HTTPX::Connection for the negotiated Alternative Service (or none).
134
184
  def build_altsvc_connection(existing_connection, connections, alt_origin, origin, alt_params, options)
135
185
  # do not allow security downgrades on altsvc negotiation
136
186
  return if existing_connection.origin.scheme == "https" && alt_origin.scheme != "https"
@@ -166,6 +216,7 @@ module HTTPX
166
216
  nil
167
217
  end
168
218
 
219
+ # returns a set of HTTPX::Request objects built from the given +args+ and +options+.
169
220
  def build_requests(*args, options)
170
221
  request_options = @options.merge(options)
171
222
 
@@ -189,6 +240,7 @@ module HTTPX
189
240
  requests
190
241
  end
191
242
 
243
+ # returns a new HTTPX::Connection object for the given +uri+ and set of +options+.
192
244
  def build_connection(uri, options)
193
245
  type = options.transport || begin
194
246
  case uri.scheme
@@ -216,11 +268,13 @@ module HTTPX
216
268
  end
217
269
  end
218
270
 
271
+ # sends an array of HTTPX::Request +requests+, returns the respective array of HTTPX::Response objects.
219
272
  def send_requests(*requests)
220
273
  connections = _send_requests(requests)
221
274
  receive_requests(requests, connections)
222
275
  end
223
276
 
277
+ # sends an array of HTTPX::Request objects
224
278
  def _send_requests(requests)
225
279
  connections = []
226
280
 
@@ -237,6 +291,7 @@ module HTTPX
237
291
  connections
238
292
  end
239
293
 
294
+ # returns the array of HTTPX::Response objects corresponding to the array of HTTPX::Request +requests+.
240
295
  def receive_requests(requests, connections)
241
296
  # @type var responses: Array[response]
242
297
  responses = []
@@ -290,6 +345,11 @@ module HTTPX
290
345
  klass.instance_variable_set(:@callbacks, @callbacks.dup)
291
346
  end
292
347
 
348
+ # returns a new HTTPX::Session instance, with the plugin pointed by +pl+ loaded.
349
+ #
350
+ # session_with_retries = session.plugin(:retries)
351
+ # session_with_custom = session.plugin(CustomPlugin)
352
+ #
293
353
  def plugin(pl, options = nil, &block)
294
354
  # raise Error, "Cannot add a plugin to a frozen config" if frozen?
295
355
  pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
data/lib/httpx/timers.rb CHANGED
@@ -6,20 +6,25 @@ module HTTPX
6
6
  @intervals = []
7
7
  end
8
8
 
9
- def after(interval_in_secs, &blk)
9
+ def after(interval_in_secs, cb = nil, &blk)
10
10
  return unless interval_in_secs
11
11
 
12
+ callback = cb || blk
13
+
12
14
  # I'm assuming here that most requests will have the same
13
15
  # request timeout, as in most cases they share common set of
14
16
  # options. A user setting different request timeouts for 100s of
15
17
  # requests will already have a hard time dealing with that.
16
- unless (interval = @intervals.find { |t| t == interval_in_secs })
18
+ unless (interval = @intervals.find { |t| t.interval == interval_in_secs })
17
19
  interval = Interval.new(interval_in_secs)
20
+ interval.on_empty { @intervals.delete(interval) }
18
21
  @intervals << interval
19
22
  @intervals.sort!
20
23
  end
21
24
 
22
- interval << blk
25
+ interval << callback
26
+
27
+ interval
23
28
  end
24
29
 
25
30
  def wait_interval
@@ -41,11 +46,6 @@ module HTTPX
41
46
  @next_interval_at = nil if @intervals.empty?
42
47
  end
43
48
 
44
- def cancel
45
- @next_interval_at = nil
46
- @intervals.clear
47
- end
48
-
49
49
  class Interval
50
50
  include Comparable
51
51
 
@@ -54,6 +54,11 @@ module HTTPX
54
54
  def initialize(interval)
55
55
  @interval = interval
56
56
  @callbacks = []
57
+ @on_empty = nil
58
+ end
59
+
60
+ def on_empty(&blk)
61
+ @on_empty = blk
57
62
  end
58
63
 
59
64
  def <=>(other)
@@ -74,6 +79,26 @@ module HTTPX
74
79
  @callbacks << callback
75
80
  end
76
81
 
82
+ if RUBY_ENGINE == "jruby" && JRUBY_VERSION < "9.4.5.0"
83
+ # https://github.com/jruby/jruby/issues/7976
84
+ def delete(callback)
85
+ @callbacks.delete(callback)
86
+ end
87
+ else
88
+ def delete(callback)
89
+ @callbacks.delete(callback)
90
+ @on_empty.call if @callbacks.empty?
91
+ end
92
+ end
93
+
94
+ def no_callbacks?
95
+ @callbacks.empty?
96
+ end
97
+
98
+ def elapsed?
99
+ @interval <= 0
100
+ end
101
+
77
102
  def elapse(elapsed)
78
103
  @interval -= elapsed
79
104
 
@@ -6,7 +6,7 @@ module HTTPX::Transcoder
6
6
  module JSON
7
7
  module_function
8
8
 
9
- JSON_REGEX = %r{\bapplication/(?:vnd\.api\+)?json\b}i.freeze
9
+ JSON_REGEX = %r{\bapplication/(?:vnd\.api\+|hal\+)?json\b}i.freeze
10
10
 
11
11
  class Encoder
12
12
  extend Forwardable
@@ -0,0 +1,19 @@
1
+ module HTTPX
2
+ module Transcoder
3
+ class Inflater
4
+ def initialize(bytesize)
5
+ @bytesize = bytesize
6
+ end
7
+
8
+ def call(chunk)
9
+ buffer = @inflater.inflate(chunk)
10
+ @bytesize -= chunk.bytesize
11
+ if @bytesize <= 0
12
+ buffer << @inflater.finish
13
+ @inflater.close
14
+ end
15
+ buffer
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/httpx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "1.0.2"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -53,7 +53,7 @@ module HTTPX
53
53
 
54
54
  def ping: () -> void
55
55
 
56
- def timeout: () -> Numeric
56
+ def timeout: () -> Numeric?
57
57
 
58
58
  private
59
59
 
@@ -38,7 +38,7 @@ module HTTPX
38
38
 
39
39
  alias reset init_connection
40
40
 
41
- def timeout: () -> Numeric
41
+ def timeout: () -> Numeric?
42
42
 
43
43
  private
44
44
 
data/sig/connection.rbs CHANGED
@@ -40,6 +40,7 @@ module HTTPX
40
40
  @parser: HTTP1 | HTTP2 | _Parser
41
41
  @connected_at: Float
42
42
  @response_received_at: Float
43
+ @intervals: Array[Timers::Interval]
43
44
 
44
45
  def addresses: () -> Array[ipaddr]?
45
46
 
@@ -89,7 +90,7 @@ module HTTPX
89
90
 
90
91
  def open?: () -> bool
91
92
 
92
- def raise_timeout_error: (Numeric interval) -> void
93
+ def handle_socket_timeout: (Numeric interval) -> void
93
94
 
94
95
  private
95
96
 
@@ -129,6 +130,8 @@ module HTTPX
129
130
 
130
131
  def read_timeout_callback: (Request request, Numeric read_timeout, ?singleton(RequestTimeoutError) error_type) -> void
131
132
 
133
+ def set_request_timeout: (Request request, Numeric timeout, Symbol start_event, Symbol | Array[Symbol] finish_events) { () -> void } -> void
134
+
132
135
  def self.parser_type: (String protocol) -> (singleton(HTTP1) | singleton(HTTP2))
133
136
  end
134
137
  end
data/sig/io/tcp.rbs CHANGED
@@ -2,7 +2,7 @@ module HTTPX
2
2
  class TCP
3
3
  include Loggable
4
4
 
5
- attr_reader ip: IPAddr?
5
+ attr_reader ip: ipaddr?
6
6
 
7
7
  attr_reader port: Integer
8
8
 
data/sig/options.rbs CHANGED
@@ -12,7 +12,7 @@ module HTTPX
12
12
  DEFAULT_OPTIONS: Hash[Symbol, untyped]
13
13
 
14
14
  type timeout_type = :connect_timeout | :settings_timeout | :operation_timeout | :keep_alive_timeout | :read_timeout | :write_timeout | :request_timeout
15
- type timeout = Hash[timeout_type, Numeric]
15
+ type timeout = Hash[timeout_type, Numeric?]
16
16
 
17
17
  def self.new: (?options) -> instance
18
18
 
@@ -32,7 +32,7 @@ module HTTPX
32
32
  attr_reader max_concurrent_requests: Integer?
33
33
 
34
34
  # max_requests
35
- attr_reader max_requests: Integer?
35
+ attr_reader max_requests: Numeric?
36
36
 
37
37
  # window_size
38
38
  attr_reader window_size: Integer
data/sig/pool.rbs CHANGED
@@ -45,7 +45,7 @@ module HTTPX
45
45
 
46
46
  def coalesce_connections: (Connection coalescable, Connection coalescing) -> void
47
47
 
48
- def next_timeout: () -> (Integer | Float | nil)
48
+ def next_timeout: () -> Numeric?
49
49
 
50
50
  def find_resolver_for: (Connection) { (Resolver::Resolver resolver) -> void } -> resolver_manager
51
51
  end
data/sig/request/body.rbs CHANGED
@@ -1,7 +1,5 @@
1
1
  module HTTPX
2
2
  class Request::Body
3
- attr_reader threshold_size: Integer?
4
-
5
3
  @headers: Headers
6
4
  @body: body_encoder?
7
5
  @unbounded_body: bool
data/sig/request.rbs CHANGED
@@ -15,6 +15,10 @@ module HTTPX
15
15
  attr_reader response: response?
16
16
  attr_reader drain_error: StandardError?
17
17
 
18
+ attr_accessor peer_address: ipaddr?
19
+
20
+ attr_writer persistent: bool
21
+
18
22
  @trailers: Headers?
19
23
  @informational_status: Integer?
20
24
  @query: String?
@@ -50,11 +54,13 @@ module HTTPX
50
54
 
51
55
  def trailers?: () -> boolish
52
56
 
53
- def read_timeout: () -> Numeric
57
+ def persistent?: () -> bool
58
+
59
+ def read_timeout: () -> Numeric?
54
60
 
55
- def write_timeout: () -> Numeric
61
+ def write_timeout: () -> Numeric?
56
62
 
57
- def request_timeout: () -> Numeric
63
+ def request_timeout: () -> Numeric?
58
64
 
59
65
  private
60
66
 
@@ -34,7 +34,7 @@ module HTTPX
34
34
 
35
35
  def timeout: () -> Numeric?
36
36
 
37
- def raise_timeout_error: (Numeric interval) -> void
37
+ def handle_socket_timeout: (Numeric interval) -> void
38
38
 
39
39
  private
40
40
 
data/sig/resolver.rbs CHANGED
@@ -2,7 +2,7 @@ module HTTPX
2
2
  type ipaddr = IPAddr | String
3
3
 
4
4
  module Resolver
5
- RESOLVE_TIMEOUT: Integer | Float
5
+ RESOLVE_TIMEOUT: Integer
6
6
 
7
7
  @lookup_mutex: Thread::Mutex
8
8
 
@@ -11,7 +11,6 @@ module HTTPX
11
11
  @headers: Headers
12
12
  @options: Options
13
13
  @state: :idle | :memory | :buffer | :closed
14
- @threshold_size: Integer
15
14
  @window_size: Integer
16
15
  @length: Integer
17
16
  @buffer: StringIO | Tempfile | nil
data/sig/response.rbs CHANGED
@@ -25,22 +25,28 @@ module HTTPX
25
25
  @content_type: ContentType
26
26
 
27
27
  def copy_to: (_ToPath | _Writer destination) -> void
28
+
28
29
  def close: () -> void
30
+
29
31
  def uri: () -> URI::Generic
30
32
 
33
+ def peer_address: () -> ipaddr?
34
+
31
35
  def merge_headers: (_Each[[String, headers_value]]) -> void
36
+
32
37
  def bodyless?: () -> bool
38
+
33
39
  def content_type: () -> ContentType
40
+
34
41
  def complete?: () -> bool
35
42
 
36
43
  def json: (?json_options opts) -> untyped
37
44
 
38
45
  def form: () -> Hash[String, untyped]
39
46
 
40
- private
47
+ def initialize: (Request request, String | Integer status, String version, headers?) -> void
41
48
 
42
- def initialize: (Request request, String | Integer status, String version, headers?) -> untyped
43
- def no_data?: () -> bool
49
+ private
44
50
 
45
51
  def decode:(Transcoder::_Decode transcoder, ?untyped options) -> untyped
46
52
  end
@@ -78,6 +84,8 @@ module HTTPX
78
84
 
79
85
  def uri: () -> URI::Generic
80
86
 
87
+ def peer_address: () -> ipaddr?
88
+
81
89
  def close: () -> void
82
90
 
83
91
  private
data/sig/timers.rbs CHANGED
@@ -3,30 +3,40 @@ module HTTPX
3
3
  @intervals: Array[Interval]
4
4
  @next_interval_at: Float
5
5
 
6
- def after: (Numeric interval_in_secs) { () -> void } -> void
6
+ def after: (Numeric interval_in_secs, ^() -> void) -> Interval
7
+ | (Numeric interval_in_secs) { () -> void } -> Interval
7
8
 
8
9
  def wait_interval: () -> Numeric?
9
10
 
10
11
  def fire: (?TimeoutError error) -> void
11
12
 
12
- def cancel: () -> void
13
-
14
- private
15
-
16
13
  def initialize: () -> void
17
14
 
18
15
  class Interval
19
16
  include Comparable
20
17
 
18
+ type callback = ^() -> void
19
+
21
20
  attr_reader interval: Numeric
22
21
 
23
- @callbacks: Array[^() -> void]
22
+ @callbacks: Array[callback]
23
+ @on_empty: callback?
24
+
25
+
26
+ def on_empty: () { () -> void } -> void
24
27
 
25
28
  def to_f: () -> Float
26
29
 
27
- def <<: (^() -> void) -> void
30
+ def <<: (callback) -> void
31
+
32
+ def delete: (callback) -> void
28
33
 
29
34
  def elapse: (Numeric elapsed) -> Numeric
35
+
36
+ def elapsed?: () -> bool
37
+
38
+ def no_callbacks?: () -> bool
39
+
30
40
  private
31
41
 
32
42
  def initialize: (Numeric interval) -> void
@@ -0,0 +1,12 @@
1
+ module HTTPX
2
+ module Transcoder
3
+ class Inflater
4
+ @inflater: Zlib::Inflate
5
+ @bytesize: Integer
6
+
7
+ def initialize: (Integer | Float bytesize) -> void
8
+
9
+ def call: (String chunk) -> String
10
+ end
11
+ end
12
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-13 00:00:00.000000000 Z
11
+ date: 2023-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2-next
@@ -131,6 +131,7 @@ extra_rdoc_files:
131
131
  - doc/release_notes/1_0_0.md
132
132
  - doc/release_notes/1_0_1.md
133
133
  - doc/release_notes/1_0_2.md
134
+ - doc/release_notes/1_1_0.md
134
135
  files:
135
136
  - LICENSE.txt
136
137
  - README.md
@@ -233,6 +234,7 @@ files:
233
234
  - doc/release_notes/1_0_0.md
234
235
  - doc/release_notes/1_0_1.md
235
236
  - doc/release_notes/1_0_2.md
237
+ - doc/release_notes/1_1_0.md
236
238
  - lib/httpx.rb
237
239
  - lib/httpx/adapters/datadog.rb
238
240
  - lib/httpx/adapters/faraday.rb
@@ -334,6 +336,7 @@ files:
334
336
  - lib/httpx/transcoder/multipart/part.rb
335
337
  - lib/httpx/transcoder/utils/body_reader.rb
336
338
  - lib/httpx/transcoder/utils/deflater.rb
339
+ - lib/httpx/transcoder/utils/inflater.rb
337
340
  - lib/httpx/transcoder/xml.rb
338
341
  - lib/httpx/utils.rb
339
342
  - lib/httpx/version.rb
@@ -416,6 +419,7 @@ files:
416
419
  - sig/transcoder/multipart.rbs
417
420
  - sig/transcoder/utils/body_reader.rbs
418
421
  - sig/transcoder/utils/deflater.rbs
422
+ - sig/transcoder/utils/inflater.rbs
419
423
  - sig/transcoder/xml.rbs
420
424
  - sig/utils.rbs
421
425
  homepage: https://gitlab.com/os85/httpx