httpx 1.2.1 → 1.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e5ee54988be76a44ae512da359d83c502f8a43073f244a116a8fdc45fa7b87d
4
- data.tar.gz: e3c08652a8d08eadbd1ef14b20005f93ff4131a712f8234c3eab94c7fce07167
3
+ metadata.gz: 8803154870d8bd0f45f67ce543072fcc42d789400ca0c9251d3ea99f5f214562
4
+ data.tar.gz: 87024f70caa91f93711b6a185a8e3dc7b8987d695472abd13a5a4cb92243d37c
5
5
  SHA512:
6
- metadata.gz: 58f16e523d23215d89a8c873a5ce12491b52726073c334c4d9800e17e40dca8111ad43ab2467c37939a19bebbaa000c8db144fdbba87cc3d22cb699687df6699
7
- data.tar.gz: 64dd9bb70af4173339019b62fa9f54fdf3f22c4bf593b51fb3de624844ac8a599a51b49cae10623aee8b8cff24af4dee69e39bedfec7da3d1ae229d733632e9c
6
+ metadata.gz: ba28ac993c5b17d4d13db24240214a40cfbae5eac5fad40e6420e42725356a289ee33fcb02492bc382d2c26ce93a0696acf7f5f8d64ddf430136ee829f717b70
7
+ data.tar.gz: 93c174e3d210681f1c76127f7a3a69adf43d8a5b3c31432ae0b6e08abd96ca7d189399081efeed710f8c43566e3290931d04b2c38df7de0251508933b2fca129
@@ -0,0 +1,10 @@
1
+ # 1.2.2
2
+
3
+ ## Bugfixes
4
+
5
+ * only raise "unknown option" error when option is not supported, not anymore when error happens in the setup of a support option.
6
+ * usage of `HTTPX::Session#wrap` within a thread with other sessions using the `:persistent` plugin won't inadvertedly terminate its open connections.
7
+ * terminate connections on `IOError` (`SocketError` does not cover them).
8
+ * terminate connections on HTTP/2 protocol and handshake errors, which happen during establishment or termination of a HTTP/2 connection (they were being previously kept around, although they'd irrecoverable).
9
+ * `:oauth` plugin: fixing check preventing the OAuth metadata server integration path to be exercised.
10
+ * fix instantiation of the options headers object with the wrong headers class.
@@ -0,0 +1,16 @@
1
+ # 1.2.3
2
+
3
+ ## Improvements
4
+
5
+ * `:retries` plugin: allow `:max_retries` set to 0 (allows for a soft disable of retries when using the faraday adapter).
6
+
7
+ ## Bugfixes
8
+
9
+ * `:oauth` plugin: fix for default auth method being ignored when setting grant type and scope as options only.
10
+ * ensure happy eyeballs-initiated cloned connections also set session callbacks (caused issues when server would respond with a 421 response, an event requiring a valid internal callback).
11
+ * native resolver cleanly transitions from tcp to udp after truncated DNS query (causing issues on follow-up CNAME resolution).
12
+ * elapsing timeouts now guard against mutation of callbacks while looping (prevents skipping callbacks in situations where a previous one would remove itself from the collection).
13
+
14
+ ## Chore
15
+
16
+ * datadog adapter: do not call `.lazy` on options (avoids deprecation warning, to be removed in ddtrace 2.0)
@@ -169,14 +169,14 @@ module Datadog::Tracing
169
169
  "httpx"
170
170
  )
171
171
  end
172
- o.lazy
172
+ o.lazy unless Gem::Version.new(DDTrace::VERSION::STRING) >= Gem::Version.new("1.13.0")
173
173
  end
174
174
  else
175
175
  option :service_name do |o|
176
176
  o.default do
177
177
  ENV.fetch("DD_TRACE_HTTPX_SERVICE_NAME", "httpx")
178
178
  end
179
- o.lazy
179
+ o.lazy unless Gem::Version.new(DDTrace::VERSION::STRING) >= Gem::Version.new("1.13.0")
180
180
  end
181
181
  end
182
182
 
@@ -522,14 +522,15 @@ module HTTPX
522
522
  Errno::ENETUNREACH,
523
523
  Errno::EPIPE,
524
524
  Errno::ENOENT,
525
- SocketError => e
525
+ SocketError,
526
+ IOError => e
526
527
  # connect errors, exit gracefully
527
528
  error = ConnectionError.new(e.message)
528
529
  error.set_backtrace(e.backtrace)
529
530
  connecting? && callbacks_for?(:connect_error) ? emit(:connect_error, error) : handle_error(error)
530
531
  @state = :closed
531
532
  emit(:close)
532
- rescue TLSError => e
533
+ rescue TLSError, HTTP2Next::Error::ProtocolError, HTTP2Next::Error::HandshakeError => e
533
534
  # connect errors, exit gracefully
534
535
  handle_error(e)
535
536
  connecting? && callbacks_for?(:connect_error) ? emit(:connect_error, e) : handle_error(e)
data/lib/httpx/io/tcp.rb CHANGED
@@ -78,7 +78,8 @@ module HTTPX
78
78
  rescue Errno::ECONNREFUSED,
79
79
  Errno::EADDRNOTAVAIL,
80
80
  Errno::EHOSTUNREACH,
81
- SocketError => e
81
+ SocketError,
82
+ IOError => e
82
83
  raise e if @ip_index <= 0
83
84
 
84
85
  log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
data/lib/httpx/options.rb CHANGED
@@ -47,13 +47,13 @@ module HTTPX
47
47
  write_timeout: WRITE_TIMEOUT,
48
48
  request_timeout: REQUEST_TIMEOUT,
49
49
  },
50
+ :headers_class => Class.new(Headers),
50
51
  :headers => {},
51
52
  :window_size => WINDOW_SIZE,
52
53
  :buffer_size => BUFFER_SIZE,
53
54
  :body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
54
55
  :request_class => Class.new(Request),
55
56
  :response_class => Class.new(Response),
56
- :headers_class => Class.new(Headers),
57
57
  :request_body_class => Class.new(Request::Body),
58
58
  :response_body_class => Class.new(Response::Body),
59
59
  :connection_class => Class.new(Connection),
@@ -154,7 +154,7 @@ module HTTPX
154
154
  end
155
155
 
156
156
  def option_headers(value)
157
- Headers.new(value)
157
+ headers_class.new(value)
158
158
  end
159
159
 
160
160
  def option_timeout(value)
@@ -342,12 +342,11 @@ module HTTPX
342
342
  defaults.each do |k, v|
343
343
  next if v.nil?
344
344
 
345
- begin
346
- value = __send__(:"option_#{k}", v)
347
- instance_variable_set(:"@#{k}", value)
348
- rescue NoMethodError
349
- raise Error, "unknown option: #{k}"
350
- end
345
+ option_method_name = :"option_#{k}"
346
+ raise Error, "unknown option: #{k}" unless respond_to?(option_method_name)
347
+
348
+ value = __send__(option_method_name, v)
349
+ instance_variable_set(:"@#{k}", value)
351
350
  end
352
351
  end
353
352
  end
@@ -16,7 +16,7 @@ module HTTPX
16
16
  SUPPORTED_AUTH_METHODS = %w[client_secret_basic client_secret_post].freeze
17
17
 
18
18
  class OAuthSession
19
- attr_reader :token_endpoint_auth_method, :grant_type, :client_id, :client_secret, :access_token, :refresh_token, :scope
19
+ attr_reader :grant_type, :client_id, :client_secret, :access_token, :refresh_token, :scope
20
20
 
21
21
  def initialize(
22
22
  issuer:,
@@ -28,7 +28,7 @@ module HTTPX
28
28
  token_endpoint: nil,
29
29
  response_type: nil,
30
30
  grant_type: nil,
31
- token_endpoint_auth_method: "client_secret_basic"
31
+ token_endpoint_auth_method: nil
32
32
  )
33
33
  @issuer = URI(issuer)
34
34
  @client_id = client_id
@@ -43,10 +43,10 @@ module HTTPX
43
43
  end
44
44
  @access_token = access_token
45
45
  @refresh_token = refresh_token
46
- @token_endpoint_auth_method = String(token_endpoint_auth_method)
46
+ @token_endpoint_auth_method = String(token_endpoint_auth_method) if token_endpoint_auth_method
47
47
  @grant_type = grant_type || (@refresh_token ? "refresh_token" : "client_credentials")
48
48
 
49
- unless SUPPORTED_AUTH_METHODS.include?(@token_endpoint_auth_method)
49
+ unless @token_endpoint_auth_method.nil? || SUPPORTED_AUTH_METHODS.include?(@token_endpoint_auth_method)
50
50
  raise Error, "#{@token_endpoint_auth_method} is not a supported auth method"
51
51
  end
52
52
 
@@ -59,10 +59,14 @@ module HTTPX
59
59
  @token_endpoint || "#{@issuer}/token"
60
60
  end
61
61
 
62
+ def token_endpoint_auth_method
63
+ @token_endpoint_auth_method || "client_secret_basic"
64
+ end
65
+
62
66
  def load(http)
63
- return unless @token_endpoint && @token_endpoint_auth_method && @grant_type && @scope
67
+ return if @grant_type && @scope
64
68
 
65
- metadata = http.get("#{issuer}/.well-known/oauth-authorization-server").raise_for_status.json
69
+ metadata = http.get("#{@issuer}/.well-known/oauth-authorization-server").raise_for_status.json
66
70
 
67
71
  @token_endpoint = metadata["token_endpoint"]
68
72
  @scope = metadata["scopes_supported"]
@@ -70,6 +74,7 @@ module HTTPX
70
74
  @token_endpoint_auth_method = Array(metadata["token_endpoint_auth_methods_supported"]).find do |am|
71
75
  SUPPORTED_AUTH_METHODS.include?(am)
72
76
  end
77
+ nil
73
78
  end
74
79
 
75
80
  def merge(other)
@@ -122,11 +127,11 @@ module HTTPX
122
127
 
123
128
  # auth
124
129
  case oauth_session.token_endpoint_auth_method
125
- when "client_secret_basic"
126
- headers["authorization"] = Authentication::Basic.new(oauth_session.client_id, oauth_session.client_secret).authenticate
127
130
  when "client_secret_post"
128
131
  form_post["client_id"] = oauth_session.client_id
129
132
  form_post["client_secret"] = oauth_session.client_secret
133
+ when "client_secret_basic"
134
+ headers["authorization"] = Authentication::Basic.new(oauth_session.client_id, oauth_session.client_secret).authenticate
130
135
  end
131
136
 
132
137
  case grant_type
@@ -58,7 +58,7 @@ module HTTPX
58
58
 
59
59
  def option_max_retries(value)
60
60
  num = Integer(value)
61
- raise TypeError, ":max_retries must be positive" unless num.positive?
61
+ raise TypeError, ":max_retries must be positive" unless num >= 0
62
62
 
63
63
  num
64
64
  end
data/lib/httpx/pool.rb CHANGED
@@ -19,6 +19,17 @@ module HTTPX
19
19
  @connections = []
20
20
  end
21
21
 
22
+ def wrap
23
+ connections = @connections
24
+ @connections = []
25
+
26
+ begin
27
+ yield self
28
+ ensure
29
+ @connections.unshift(*connections)
30
+ end
31
+ end
32
+
22
33
  def empty?
23
34
  @connections.empty?
24
35
  end
@@ -168,6 +179,7 @@ module HTTPX
168
179
  connection.once(:connect_error) do |err|
169
180
  if new_connection.connecting?
170
181
  new_connection.merge(connection)
182
+ connection.emit(:cloned, new_connection)
171
183
  connection.force_reset
172
184
  else
173
185
  connection.__send__(:handle_error, err)
@@ -184,6 +196,7 @@ module HTTPX
184
196
  if connection.connecting?
185
197
  # main connection has the requests
186
198
  connection.merge(new_connection)
199
+ new_connection.emit(:cloned, connection)
187
200
  new_connection.force_reset
188
201
  else
189
202
  new_connection.__send__(:handle_error, err)
data/lib/httpx/request.rb CHANGED
@@ -61,7 +61,7 @@ module HTTPX
61
61
  @uri = origin.merge("#{base_path}#{@uri}")
62
62
  end
63
63
 
64
- @headers = @options.headers_class.new(@options.headers)
64
+ @headers = @options.headers.dup
65
65
  @headers["user-agent"] ||= USER_AGENT
66
66
  @headers["accept"] ||= "*/*"
67
67
 
@@ -187,10 +187,10 @@ module HTTPX
187
187
  next unless @large_packet.full?
188
188
 
189
189
  parse(@large_packet.to_s)
190
-
191
190
  @socket_type = @resolver_options.fetch(:socket_type, :udp)
192
191
  @large_packet = nil
193
- transition(:closed)
192
+ transition(:idle)
193
+ transition(:open)
194
194
  return
195
195
  else
196
196
  size = @read_buffer[0, 2].unpack1("n")
@@ -7,10 +7,18 @@ require "fileutils"
7
7
  require "forwardable"
8
8
 
9
9
  module HTTPX
10
- # Defines a HTTP response is handled internally, with a few properties exposed as attributes,
11
- # implements (indirectly, via the +body+) the IO write protocol to internally buffer payloads,
12
- # implements the IO reader protocol in order for users to buffer/stream it, acts as an enumerable
10
+ # Defines a HTTP response is handled internally, with a few properties exposed as attributes.
11
+ #
12
+ # It delegates the following methods to the corresponding HTTPX::Request:
13
+ #
14
+ # * HTTPX::Request#uri
15
+ # * HTTPX::Request#peer_address
16
+ #
17
+ # It implements (indirectly, via the +body+) the IO write protocol to internally buffer payloads.
18
+ #
19
+ # It implements the IO reader protocol in order for users to buffer/stream it, acts as an enumerable
13
20
  # (of payload chunks).
21
+ #
14
22
  class Response
15
23
  extend Forwardable
16
24
  include Callbacks
@@ -21,7 +29,13 @@ module HTTPX
21
29
  # an HTTPX::Headers object containing the response HTTP headers.
22
30
  attr_reader :headers
23
31
 
24
- # a HTTPX::Response::Body object wrapping the response body.
32
+ # a HTTPX::Response::Body object wrapping the response body. The following methods are delegated to it:
33
+ #
34
+ # * HTTPX::Response::Body#to_s
35
+ # * HTTPX::Response::Body#to_str
36
+ # * HTTPX::Response::Body#read
37
+ # * HTTPX::Response::Body#copy_to
38
+ # * HTTPX::Response::Body#close
25
39
  attr_reader :body
26
40
 
27
41
  # The HTTP protocol version used to fetch the response.
data/lib/httpx/session.rb CHANGED
@@ -28,13 +28,15 @@ module HTTPX
28
28
  # http.get("https://wikipedia.com")
29
29
  # end # wikipedia connection closes here
30
30
  def wrap
31
- begin
32
- prev_persistent = @persistent
33
- @persistent = true
34
- yield self
35
- ensure
36
- @persistent = prev_persistent
37
- close unless @persistent
31
+ prev_persistent = @persistent
32
+ @persistent = true
33
+ pool.wrap do
34
+ begin
35
+ yield self
36
+ ensure
37
+ @persistent = prev_persistent
38
+ close unless @persistent
39
+ end
38
40
  end
39
41
  end
40
42
 
@@ -136,7 +138,7 @@ module HTTPX
136
138
 
137
139
  # sets the callbacks on the +connection+ required to process certain specific
138
140
  # connection lifecycle events which deal with request rerouting.
139
- def set_connection_callbacks(connection, connections, options)
141
+ def set_connection_callbacks(connection, connections, options, cloned: false)
140
142
  connection.only(:misdirected) do |misdirected_request|
141
143
  other_connection = connection.create_idle(ssl: { alpn_protocols: %w[http/1.1] })
142
144
  other_connection.merge(connection)
@@ -152,6 +154,10 @@ module HTTPX
152
154
  other_connection = build_altsvc_connection(connection, connections, alt_origin, origin, alt_params, options)
153
155
  connections << other_connection if other_connection
154
156
  end
157
+ connection.only(:cloned) do |cloned_conn|
158
+ set_connection_callbacks(cloned_conn, connections, options, cloned: true)
159
+ connections << cloned_conn
160
+ end unless cloned
155
161
  end
156
162
 
157
163
  # returns an HTTPX::Connection for the negotiated Alternative Service (or none).
data/lib/httpx/timers.rb CHANGED
@@ -97,7 +97,10 @@ module HTTPX
97
97
  def elapse(elapsed)
98
98
  @interval -= elapsed
99
99
 
100
- @callbacks.each(&:call) if @interval <= 0
100
+ if @interval <= 0
101
+ cb = @callbacks.dup
102
+ cb.each(&:call)
103
+ end
101
104
 
102
105
  @interval
103
106
  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.2.1"
4
+ VERSION = "1.2.3"
5
5
  end
@@ -15,8 +15,6 @@ module HTTPX
15
15
  SUPPORTED_AUTH_METHODS: ::Array[token_auth_method]
16
16
 
17
17
  class OAuthSession
18
- attr_reader token_endpoint_auth_method: token_auth_method
19
-
20
18
  attr_reader grant_type: grant_type
21
19
 
22
20
  attr_reader client_id: String
@@ -33,6 +31,8 @@ module HTTPX
33
31
 
34
32
  def token_endpoint: () -> String
35
33
 
34
+ def token_endpoint_auth_method: () -> token_auth_method
35
+
36
36
  def load: (Session http) -> void
37
37
 
38
38
  def merge: (instance | Hash[untyped, untyped] other) -> instance
data/sig/pool.rbs CHANGED
@@ -7,6 +7,8 @@ module HTTPX
7
7
  @selector: Selector
8
8
  @connections: Array[Connection]
9
9
 
10
+ def wrap: () { (instance) -> void } -> void
11
+
10
12
  def empty?: () -> void
11
13
 
12
14
  def next_tick: () -> void
data/sig/session.rbs CHANGED
@@ -31,7 +31,7 @@ module HTTPX
31
31
 
32
32
  def send_request: (Request request, Array[Connection] connections, ?Options options) -> void
33
33
 
34
- def set_connection_callbacks: (Connection connection, Array[Connection] connections, Options options) -> void
34
+ def set_connection_callbacks: (Connection connection, Array[Connection] connections, Options options, ?cloned: bool) -> void
35
35
 
36
36
  def set_request_callbacks: (Request request) -> void
37
37
 
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.2.1
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-13 00:00:00.000000000 Z
11
+ date: 2024-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2-next
@@ -139,6 +139,8 @@ extra_rdoc_files:
139
139
  - doc/release_notes/1_1_5.md
140
140
  - doc/release_notes/1_2_0.md
141
141
  - doc/release_notes/1_2_1.md
142
+ - doc/release_notes/1_2_2.md
143
+ - doc/release_notes/1_2_3.md
142
144
  files:
143
145
  - LICENSE.txt
144
146
  - README.md
@@ -249,6 +251,8 @@ files:
249
251
  - doc/release_notes/1_1_5.md
250
252
  - doc/release_notes/1_2_0.md
251
253
  - doc/release_notes/1_2_1.md
254
+ - doc/release_notes/1_2_2.md
255
+ - doc/release_notes/1_2_3.md
252
256
  - lib/httpx.rb
253
257
  - lib/httpx/adapters/datadog.rb
254
258
  - lib/httpx/adapters/faraday.rb