httpx 0.18.6 → 0.18.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6784fbd393b5caed888e6c4d1a421cde9c7aca49f35baaafbf13f10a68e9d02
4
- data.tar.gz: ddd5bb8793fa72b19e462b411f5eaaaf553f30d589a68dfdde64224c49d902f6
3
+ metadata.gz: ab9b9577b0e266b140e21030307b3f2436af346a13f1e0931af05020ba42f7e6
4
+ data.tar.gz: c5d043448ef41b0532c08d1622540d80c68511ef59cffcc810a6f8bd92f348d5
5
5
  SHA512:
6
- metadata.gz: 949f18741f10eaa57463b8764569e69cdfb1ca6f4eefa30bbdcf142cbbd8b61b360d9bd78898a816a4ebd9e15d4ffd1c0d8282033a459826919ce8132d5b105f
7
- data.tar.gz: e4430eea967c9f5628d51e6150bc4f63e704eaed2bd61fda191f3539a3f102e00932cc8f63ddb735c33bbf21e2694bb23fed5eaea588159e71fa6f484016c150
6
+ metadata.gz: 8b4ec58f2ab031d23f28a86bc47b40d0f0d79eea9aea64590b0cc3d07269738513de1364608e0c0282a6956d816b78b900520dbad4daab1f73522b8b7f73d138
7
+ data.tar.gz: f2d2c297b530bfb3567ebcd1678bad1d729187dd75c9107839c925def1a708c4648fe80df614a01af02bce309594e256e274e042f3c6b8347182aebff1df9935
@@ -3,8 +3,8 @@
3
3
  ## Improvements
4
4
 
5
5
  * ruby 3.1 is now officially supported.
6
- * when user sets a `Host` header for an HTTP/2 request, this will be used in the `:authority` HTTP/2 pseudo-header, instead of silently ignored (mimicking what "curl" does).
6
+ * when a user sets a `Host` header for an HTTP/2 request, this will be used in the `:authority` HTTP/2 pseudo-header, instead of silently ignored (mimicking what "curl" does).
7
7
 
8
8
  ## Bugfixes
9
9
 
10
- * fixed "throw outside of catch block" error happening when pipelining requests on an HTTP/1 connnection and resulting in a timeout.
10
+ * fixed "throw outside of catch block" error happening when pipelining requests on an HTTP/1 connection and resulting in a timeout.
@@ -0,0 +1,5 @@
1
+ # 0.18.6
2
+
3
+ ## Bugfixes
4
+
5
+ * multipart plugin: fixed `filemagic` integration by rewinding the file after mime-type detection.
@@ -297,10 +297,6 @@ module HTTPX
297
297
  extra_headers
298
298
  end
299
299
 
300
- def headline_uri(request)
301
- request.path
302
- end
303
-
304
300
  def handle(request)
305
301
  catch(:buffer_full) do
306
302
  request.transition(:headers)
@@ -314,8 +310,12 @@ module HTTPX
314
310
  end
315
311
  end
316
312
 
313
+ def join_headline(request)
314
+ "#{request.verb.to_s.upcase} #{request.path} HTTP/#{@version.join(".")}"
315
+ end
316
+
317
317
  def join_headers(request)
318
- headline = "#{request.verb.to_s.upcase} #{headline_uri(request)} HTTP/#{@version.join(".")}"
318
+ headline = join_headline(request)
319
319
  @buffer << headline << CRLF
320
320
  log(color: :yellow) { "<- HEADLINE: #{headline.chomp.inspect}" }
321
321
  extra_headers = set_protocol_headers(request)
@@ -158,10 +158,6 @@ module HTTPX
158
158
  end
159
159
  end
160
160
 
161
- def headline_uri(request)
162
- request.path
163
- end
164
-
165
161
  def handle(request, stream)
166
162
  catch(:buffer_full) do
167
163
  request.transition(:headers)
@@ -213,7 +209,7 @@ module HTTPX
213
209
  {
214
210
  ":scheme" => request.scheme,
215
211
  ":method" => request.verb.to_s.upcase,
216
- ":path" => headline_uri(request),
212
+ ":path" => request.path,
217
213
  ":authority" => request.authority,
218
214
  }
219
215
  end
@@ -44,7 +44,7 @@ module HTTPX
44
44
 
45
45
  def_delegator :@write_buffer, :empty?
46
46
 
47
- attr_reader :origin, :state, :pending, :options
47
+ attr_reader :origin, :origins, :state, :pending, :options
48
48
 
49
49
  attr_writer :timers
50
50
 
@@ -489,6 +489,18 @@ module HTTPX
489
489
  end
490
490
 
491
491
  def transition(nextstate)
492
+ handle_transition(nextstate)
493
+ rescue Errno::ECONNREFUSED,
494
+ Errno::EADDRNOTAVAIL,
495
+ Errno::EHOSTUNREACH,
496
+ TLSError => e
497
+ # connect errors, exit gracefully
498
+ handle_error(e)
499
+ @state = :closed
500
+ emit(:close)
501
+ end
502
+
503
+ def handle_transition(nextstate)
492
504
  case nextstate
493
505
  when :idle
494
506
  @timeout = @current_timeout = @options.timeout[:connect_timeout]
@@ -525,14 +537,6 @@ module HTTPX
525
537
  emit(:activate)
526
538
  end
527
539
  @state = nextstate
528
- rescue Errno::ECONNREFUSED,
529
- Errno::EADDRNOTAVAIL,
530
- Errno::EHOSTUNREACH,
531
- TLSError => e
532
- # connect errors, exit gracefully
533
- handle_error(e)
534
- @state = :closed
535
- emit(:close)
536
540
  end
537
541
 
538
542
  def purge_after_closed
@@ -550,6 +554,10 @@ module HTTPX
550
554
  ex.set_backtrace(error.backtrace)
551
555
  error = ex
552
556
  else
557
+ # inactive connections do not contribute to the select loop, therefore
558
+ # they should fail due to such errors.
559
+ return if @state == :inactive
560
+
553
561
  if @timeout
554
562
  @timeout -= error.timeout
555
563
  return unless @timeout <= 0
data/lib/httpx/io/tcp.rb CHANGED
@@ -57,7 +57,9 @@ module HTTPX
57
57
  @io = build_socket
58
58
  end
59
59
  try_connect
60
- rescue Errno::EHOSTUNREACH => e
60
+ rescue Errno::ECONNREFUSED,
61
+ Errno::EADDRNOTAVAIL,
62
+ Errno::EHOSTUNREACH => e
61
63
  raise e if @ip_index <= 0
62
64
 
63
65
  @ip_index -= 1
@@ -81,7 +81,7 @@ module HTTPX
81
81
  super
82
82
  end
83
83
 
84
- def transition(nextstate)
84
+ def handle_transition(nextstate)
85
85
  state = @state
86
86
  super
87
87
  meter_elapsed_time("Connection##{object_id}[#{@origin}]: #{state} -> #{nextstate}") if nextstate == @state
@@ -14,9 +14,13 @@ module HTTPX
14
14
  def call(file, _)
15
15
  return nil if file.eof? # FileMagic returns "application/x-empty" for empty files
16
16
 
17
- FileMagic.open(FileMagic::MAGIC_MIME_TYPE) do |filemagic|
17
+ mime = FileMagic.open(FileMagic::MAGIC_MIME_TYPE) do |filemagic|
18
18
  filemagic.buffer(file.read(MAGIC_NUMBER))
19
19
  end
20
+
21
+ file.rewind
22
+
23
+ mime
20
24
  end
21
25
  elsif defined?(Marcel)
22
26
  def call(file, filename)
@@ -13,7 +13,7 @@ module HTTPX
13
13
 
14
14
  private
15
15
 
16
- def transition(nextstate)
16
+ def handle_transition(nextstate)
17
17
  return super unless @options.proxy && @options.proxy.uri.scheme == "http"
18
18
 
19
19
  case nextstate
@@ -23,7 +23,8 @@ module HTTPX
23
23
  @io.connect
24
24
  return unless @io.connected?
25
25
 
26
- @parser = ConnectProxyParser.new(@write_buffer, @options.merge(max_concurrent_requests: 1))
26
+ @parser = registry(@io.protocol).new(@write_buffer, @options.merge(max_concurrent_requests: 1))
27
+ @parser.extend(ProxyParser)
27
28
  @parser.once(:response, &method(:__http_on_connect))
28
29
  @parser.on(:close) { transition(:closing) }
29
30
  __http_proxy_connect
@@ -36,7 +37,7 @@ module HTTPX
36
37
  @parser.close
37
38
  @parser = nil
38
39
  when :idle
39
- @parser = ProxyParser.new(@write_buffer, @options)
40
+ @parser.callbacks.clear
40
41
  set_parser_callbacks(@parser)
41
42
  end
42
43
  end
@@ -54,7 +55,7 @@ module HTTPX
54
55
  @inflight += 1
55
56
  parser.send(connect_request)
56
57
  else
57
- transition(:connected)
58
+ handle_transition(:connected)
58
59
  end
59
60
  end
60
61
 
@@ -76,9 +77,11 @@ module HTTPX
76
77
  end
77
78
  end
78
79
 
79
- class ProxyParser < Connection::HTTP1
80
- def headline_uri(request)
81
- request.uri.to_s
80
+ module ProxyParser
81
+ def join_headline(request)
82
+ return super if request.verb == :connect
83
+
84
+ "#{request.verb.to_s.upcase} #{request.uri} HTTP/#{@version.join(".")}"
82
85
  end
83
86
 
84
87
  def set_protocol_headers(request)
@@ -91,22 +94,6 @@ module HTTPX
91
94
  end
92
95
  end
93
96
 
94
- class ConnectProxyParser < ProxyParser
95
- attr_reader :pending
96
-
97
- def headline_uri(request)
98
- return super unless request.verb == :connect
99
-
100
- tunnel = request.path
101
- log { "establishing HTTP proxy tunnel to #{tunnel}" }
102
- tunnel
103
- end
104
-
105
- def empty?
106
- @requests.reject { |r| r.verb == :connect }.empty? || @requests.all? { |request| !request.response.nil? }
107
- end
108
- end
109
-
110
97
  class ConnectRequest < Request
111
98
  def initialize(uri, _options)
112
99
  super(:connect, uri, {})
@@ -27,7 +27,7 @@ module HTTPX
27
27
 
28
28
  private
29
29
 
30
- def transition(nextstate)
30
+ def handle_transition(nextstate)
31
31
  return super unless @options.proxy && PROTOCOLS.include?(@options.proxy.uri.scheme)
32
32
 
33
33
  case nextstate
@@ -46,7 +46,7 @@ module HTTPX
46
46
 
47
47
  private
48
48
 
49
- def transition(nextstate)
49
+ def handle_transition(nextstate)
50
50
  return super unless @options.proxy && @options.proxy.uri.scheme == "socks5"
51
51
 
52
52
  case nextstate
@@ -85,7 +85,7 @@ module HTTPX
85
85
  end
86
86
  uris
87
87
  end
88
- options.proxy.merge(uri: @_proxy_uris.first) unless @_proxy_uris.empty?
88
+ { uri: @_proxy_uris.first } unless @_proxy_uris.empty?
89
89
  end
90
90
 
91
91
  def find_connection(request, connections, options)
@@ -109,8 +109,10 @@ module HTTPX
109
109
  return super unless proxy
110
110
 
111
111
  connection = options.connection_class.new("tcp", uri, options)
112
- pool.init_connection(connection, options)
113
- connection
112
+ catch(:coalesced) do
113
+ pool.init_connection(connection, options)
114
+ connection
115
+ end
114
116
  end
115
117
 
116
118
  def fetch_response(request, connections, options)
@@ -181,11 +183,20 @@ module HTTPX
181
183
  super && @options.proxy == options.proxy
182
184
  end
183
185
 
184
- # should not coalesce connections here, as the IP is the IP of the proxy
185
- def coalescable?(*)
186
+ def coalescable?(connection)
186
187
  return super unless @options.proxy
187
188
 
188
- false
189
+ if @io.protocol == "h2" &&
190
+ @origin.scheme == "https" &&
191
+ connection.origin.scheme == "https" &&
192
+ @io.can_verify_peer?
193
+ # in proxied connections, .origin is the proxy ; Given names
194
+ # are stored in .origins, this is what is used.
195
+ origin = URI(connection.origins.first)
196
+ @io.verify_hostname(origin.host)
197
+ else
198
+ @origin == connection.origin
199
+ end
189
200
  end
190
201
 
191
202
  def send(request)
@@ -234,7 +245,7 @@ module HTTPX
234
245
  end
235
246
  end
236
247
 
237
- def transition(nextstate)
248
+ def handle_transition(nextstate)
238
249
  return super unless @options.proxy
239
250
 
240
251
  case nextstate
@@ -29,7 +29,7 @@ module HTTPX
29
29
  attr_writer :pool
30
30
 
31
31
  def initialize(options)
32
- @options = Options.new(options)
32
+ @options = HTTPX::Options.new(options)
33
33
  @resolver_options = DEFAULTS.merge(@options.resolver_options)
34
34
  @_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
35
35
  @queries = {}
@@ -50,7 +50,7 @@ module HTTPX
50
50
  attr_reader :state
51
51
 
52
52
  def initialize(options)
53
- @options = Options.new(options)
53
+ @options = HTTPX::Options.new(options)
54
54
  @ns_index = 0
55
55
  @resolver_options = DEFAULTS.merge(@options.resolver_options)
56
56
  @nameserver = @resolver_options[:nameserver]
@@ -200,6 +200,7 @@ module HTTPX
200
200
  hostname, connection = @queries.first
201
201
  if @_record_types[hostname].empty?
202
202
  @queries.delete(hostname)
203
+ @timeouts.delete(hostname)
203
204
  @connections.delete(connection)
204
205
  ex = NativeResolveError.new(connection, hostname, e.message)
205
206
  ex.set_backtrace(e.backtrace)
@@ -213,6 +214,7 @@ module HTTPX
213
214
  if @_record_types[hostname].empty?
214
215
  @queries.delete(hostname)
215
216
  @_record_types.delete(hostname)
217
+ @timeouts.delete(hostname)
216
218
  @connections.delete(connection)
217
219
 
218
220
  raise NativeResolveError.new(connection, hostname)
@@ -236,13 +238,18 @@ module HTTPX
236
238
  end
237
239
 
238
240
  if address.key?("alias") # CNAME
239
- if early_resolve(connection, hostname: address["alias"])
241
+ # clean up intermediate queries
242
+ @timeouts.delete(address["name"]) unless connection.origin.host == address["name"]
243
+
244
+ if catch(:coalesced) { early_resolve(connection, hostname: address["alias"]) }
245
+ @timeouts.delete(connection.origin.host)
240
246
  @connections.delete(connection)
241
247
  else
242
248
  resolve(connection, address["alias"])
243
249
  return
244
250
  end
245
251
  else
252
+ @timeouts.delete(connection.origin.host)
246
253
  @connections.delete(connection)
247
254
  Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options[:cache]
248
255
  emit_addresses(connection, addresses.map { |addr| addr["data"] })
@@ -32,7 +32,7 @@ module HTTPX
32
32
  end
33
33
  log { "resolver: answer #{connection.origin.host}: #{addresses.inspect}" }
34
34
  connection.addresses = addresses
35
- catch(:coalesced) { emit(:resolve, connection) }
35
+ emit(:resolve, connection)
36
36
  end
37
37
 
38
38
  def early_resolve(connection, hostname: connection.origin.host)
@@ -15,7 +15,7 @@ module HTTPX
15
15
  attr_reader :state
16
16
 
17
17
  def initialize(options)
18
- @options = Options.new(options)
18
+ @options = HTTPX::Options.new(options)
19
19
  @resolver_options = @options.resolver_options
20
20
  @state = :idle
21
21
  resolv_options = @resolver_options.dup
data/lib/httpx/session.rb CHANGED
@@ -207,7 +207,7 @@ module HTTPX
207
207
 
208
208
  return responses unless request
209
209
 
210
- pool.next_tick until (response = fetch_response(request, connections, request.options))
210
+ catch(:coalesced) { pool.next_tick } until (response = fetch_response(request, connections, request.options))
211
211
 
212
212
  responses << response
213
213
  requests.shift
@@ -309,18 +309,4 @@ module HTTPX
309
309
  # :nocov:
310
310
  end
311
311
  end
312
-
313
- unless ENV.grep(/https?_proxy$/i).empty?
314
- proxy_session = plugin(:proxy)
315
- ::HTTPX.send(:remove_const, :Session)
316
- ::HTTPX.send(:const_set, :Session, proxy_session.class)
317
- end
318
-
319
- # :nocov:
320
- if Session.default_options.debug_level > 2
321
- proxy_session = plugin(:internal_telemetry)
322
- ::HTTPX.send(:remove_const, :Session)
323
- ::HTTPX.send(:const_set, :Session, proxy_session.class)
324
- end
325
- # :nocov:
326
312
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ unless ENV.keys.grep(/\Ahttps?_proxy\z/i).empty?
5
+ proxy_session = plugin(:proxy)
6
+ remove_const(:Session)
7
+ const_set(:Session, proxy_session.class)
8
+ remove_const(:Options)
9
+ const_set(:Options, proxy_session.class.default_options.class)
10
+ end
11
+
12
+ # :nocov:
13
+ if Session.default_options.debug_level > 2
14
+ proxy_session = plugin(:internal_telemetry)
15
+ remove_const(:Session)
16
+ const_set(:Session, proxy_session.class)
17
+ end
18
+ # :nocov:
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 = "0.18.6"
4
+ VERSION = "0.18.7"
5
5
  end
data/lib/httpx.rb CHANGED
@@ -64,3 +64,4 @@ module HTTPX
64
64
  end
65
65
 
66
66
  require "httpx/session"
67
+ require "httpx/session_extensions"
@@ -67,8 +67,6 @@ module HTTPX
67
67
 
68
68
  def set_protocol_headers: (Request) -> _Each[[String, String]]
69
69
 
70
- def headline_uri: (Request) -> String
71
-
72
70
  def handle: (Request request) -> void
73
71
 
74
72
  def join_headers: (Request request) -> void
@@ -46,8 +46,6 @@ module HTTPX
46
46
 
47
47
  def send_pending: () -> void
48
48
 
49
- def headline_uri: (Request) -> String
50
-
51
49
  def set_protocol_headers: (Request) -> _Each[[String, String]]
52
50
 
53
51
  def handle: (Request request, HTTP2Next::Stream stream) -> void
@@ -56,6 +54,8 @@ module HTTPX
56
54
 
57
55
  def handle_stream: (HTTP2Next::Stream stream, Request request) -> void
58
56
 
57
+ def join_headline: (Request request) -> String
58
+
59
59
  def join_headers: (HTTP2Next::Stream stream, Request request) -> void
60
60
 
61
61
  def join_trailers: (HTTP2Next::Stream stream, Request request) -> void
data/sig/connection.rbs CHANGED
@@ -22,6 +22,7 @@ module HTTPX
22
22
  BUFFER_SIZE: Integer
23
23
 
24
24
  attr_reader origin: URI::Generic
25
+ attr_reader origins: Array[String]
25
26
  attr_reader state: Symbol
26
27
  attr_reader pending: Array[Request]
27
28
  attr_reader options: Options
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.6
4
+ version: 0.18.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
@@ -69,6 +69,7 @@ extra_rdoc_files:
69
69
  - doc/release_notes/0_18_4.md
70
70
  - doc/release_notes/0_18_5.md
71
71
  - doc/release_notes/0_18_6.md
72
+ - doc/release_notes/0_18_7.md
72
73
  - doc/release_notes/0_1_0.md
73
74
  - doc/release_notes/0_2_0.md
74
75
  - doc/release_notes/0_2_1.md
@@ -131,6 +132,7 @@ files:
131
132
  - doc/release_notes/0_18_4.md
132
133
  - doc/release_notes/0_18_5.md
133
134
  - doc/release_notes/0_18_6.md
135
+ - doc/release_notes/0_18_7.md
134
136
  - doc/release_notes/0_1_0.md
135
137
  - doc/release_notes/0_2_0.md
136
138
  - doc/release_notes/0_2_1.md
@@ -234,6 +236,7 @@ files:
234
236
  - lib/httpx/selector.rb
235
237
  - lib/httpx/session.rb
236
238
  - lib/httpx/session2.rb
239
+ - lib/httpx/session_extensions.rb
237
240
  - lib/httpx/timers.rb
238
241
  - lib/httpx/transcoder.rb
239
242
  - lib/httpx/transcoder/body.rb