httpx 0.18.6 → 0.19.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/doc/release_notes/0_18_5.md +2 -2
- data/doc/release_notes/0_18_7.md +5 -0
- data/doc/release_notes/0_19_0.md +39 -0
- data/doc/release_notes/0_19_1.md +5 -0
- data/doc/release_notes/0_19_2.md +7 -0
- data/lib/httpx/adapters/faraday.rb +7 -3
- data/lib/httpx/connection/http1.rb +5 -5
- data/lib/httpx/connection/http2.rb +1 -5
- data/lib/httpx/connection.rb +22 -10
- data/lib/httpx/extensions.rb +16 -0
- data/lib/httpx/headers.rb +0 -2
- data/lib/httpx/io/tcp.rb +27 -6
- data/lib/httpx/options.rb +44 -11
- data/lib/httpx/plugins/cookies.rb +5 -7
- data/lib/httpx/plugins/internal_telemetry.rb +1 -1
- data/lib/httpx/plugins/multipart/mime_type_detector.rb +5 -1
- data/lib/httpx/plugins/proxy/http.rb +10 -23
- data/lib/httpx/plugins/proxy/socks4.rb +1 -1
- data/lib/httpx/plugins/proxy/socks5.rb +1 -1
- data/lib/httpx/plugins/proxy.rb +20 -12
- data/lib/httpx/plugins/retries.rb +1 -1
- data/lib/httpx/pool.rb +40 -20
- data/lib/httpx/resolver/https.rb +32 -42
- data/lib/httpx/resolver/multi.rb +79 -0
- data/lib/httpx/resolver/native.rb +28 -36
- data/lib/httpx/resolver/resolver.rb +93 -0
- data/lib/httpx/resolver/system.rb +175 -19
- data/lib/httpx/resolver.rb +37 -11
- data/lib/httpx/response.rb +4 -2
- data/lib/httpx/session.rb +1 -15
- data/lib/httpx/session_extensions.rb +26 -0
- data/lib/httpx/timers.rb +1 -1
- data/lib/httpx/transcoder/chunker.rb +0 -1
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +3 -0
- data/sig/connection/http1.rbs +0 -2
- data/sig/connection/http2.rbs +2 -2
- data/sig/connection.rbs +1 -0
- data/sig/errors.rbs +8 -0
- data/sig/headers.rbs +0 -2
- data/sig/httpx.rbs +4 -0
- data/sig/options.rbs +10 -7
- data/sig/parser/http1.rbs +14 -5
- data/sig/pool.rbs +17 -9
- data/sig/registry.rbs +3 -0
- data/sig/request.rbs +11 -0
- data/sig/resolver/https.rbs +15 -27
- data/sig/resolver/multi.rbs +7 -0
- data/sig/resolver/native.rbs +3 -12
- data/sig/resolver/resolver.rbs +36 -0
- data/sig/resolver/system.rbs +3 -9
- data/sig/resolver.rbs +12 -10
- data/sig/response.rbs +15 -5
- data/sig/selector.rbs +3 -3
- data/sig/timers.rbs +5 -2
- data/sig/transcoder/chunker.rbs +16 -5
- data/sig/transcoder/json.rbs +5 -0
- data/sig/transcoder.rbs +3 -1
- metadata +15 -4
- data/lib/httpx/resolver/resolver_mixin.rb +0 -75
- data/sig/resolver/resolver_mixin.rbs +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9e79c1b196931855e7af542bd611050a95648d2888d539cb20de5026c4a3ccf
|
4
|
+
data.tar.gz: 4cc919ede2c58d6bcf86433ddf4ceba9fdca5416186d5984fa2f29a92707668d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a35e9f740d6df65190a8e28cc2d2d8adfe9c208842290ceb0c8f6c9dd273e19066c7cc851d917f6daac663c205401e7df26916a0f41c01653e53488d404f669
|
7
|
+
data.tar.gz: 67203d583847abee46ac940ff82c11624298907e191ff0c6c5408b1cddf0c909ac8820de24f11ef1cc9ac7030e5d11e807668e9f991967fc4bb4654f92ddd3c8
|
data/README.md
CHANGED
@@ -140,11 +140,15 @@ In order to use HTTP/2 under JRuby, [check this link](https://gitlab.com/honeyry
|
|
140
140
|
* Doesn't work with ruby 2.4.0 for Windows (see [#36](https://gitlab.com/honeyryderchuck/httpx/issues/36)).
|
141
141
|
* Using `total_timeout` along with the `:persistent` plugin [does not work as you might expect](https://gitlab.com/honeyryderchuck/httpx/-/wikis/Timeouts#total_timeout).
|
142
142
|
|
143
|
+
## Versioning Policy
|
144
|
+
|
145
|
+
Although 0.x software, `httpx` is considered API-stable and production-ready, i.e. current API or options may be subject to deprecation and emit log warnings, but can only effectively be removed in a major version change.
|
146
|
+
|
143
147
|
## Contributing
|
144
148
|
|
145
149
|
* Discuss your contribution in an issue
|
146
150
|
* Fork it
|
147
151
|
* Make your changes, add some tests
|
148
|
-
* Ensure all tests pass (`bundle exec rake test`)
|
152
|
+
* Ensure all tests pass (`docker-compose -f docker-compose.yml -f docker-compose-ruby-{RUBY_VERSION}.yml run httpx bundle exec rake test`)
|
149
153
|
* Open a Merge Request (that's Pull Request in Github-ish)
|
150
154
|
* Wait for feedback
|
data/doc/release_notes/0_18_5.md
CHANGED
@@ -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
|
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,39 @@
|
|
1
|
+
# 0.19.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### Happy Eyeballs v2
|
6
|
+
|
7
|
+
When the system supports dual-stack networking, `httpx` implements the Happy Eyeballs v2 algorithm (RFC 8305) to resolve hostnames to both IPv6 and IPv4 addresses while privileging IPv6 connectivity. This is implemented by `httpx` both for the `:native` as well as the `:https` (DoH) resolver (which do not perform address sorting, thereby being "DNS-based load-balancing" friendly), and "outsourced" to `getaddrinfo` when using the `:system` resolver.
|
8
|
+
|
9
|
+
IPv6 connectivity will also be privileged for `/etc/hosts` local DNS (i.e. `localhost` connections will connec to `::1`).
|
10
|
+
|
11
|
+
A new option, `:ip_families`, will also be available (`[Socket::AF_INET6, Socket::AF_INET]` in dual-stack systems). If you'd like to i.e. force IPv4 connectivity, you can do use it (`client = HTTPX.with(ip_families: [Socket::AF_INET])`).
|
12
|
+
|
13
|
+
## Improvements
|
14
|
+
|
15
|
+
### DNS: :system resolver uses getaddrinfo (instead of the resolver lib)
|
16
|
+
|
17
|
+
The `:system` resolver switched to using the `getaddinfo` system function to perform DNS requests. Not only is this call **not** blocking the session event loop anymore (unlike pre-0.19.0 `:system` resolver), it adds a lot of functionality that the stdlib `resolv` library just doesn't support at the moment (such as SRV records).
|
18
|
+
|
19
|
+
### HTTP/2 proxy support
|
20
|
+
|
21
|
+
The `:proxy` plugin handles "prior-knowledge" HTTP/2 proxies.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
HTTPX.plugin(:proxy, fallback_protocol: "h2").with_proxy(uri: "http://http2-proxy:3128").get(...
|
25
|
+
```
|
26
|
+
|
27
|
+
Connection coalescing has also been enabled for proxied connections (also `CONNECT`-tunneled connections).
|
28
|
+
|
29
|
+
### curl-to-httpx
|
30
|
+
|
31
|
+
widget in [project website](https://honeyryderchuck.gitlab.io/httpx/) to turn curl commands into the equivalent `httpx` code.
|
32
|
+
|
33
|
+
## Bugfixes
|
34
|
+
|
35
|
+
* faraday adapter now supports passing session options.
|
36
|
+
* proxy: several fixes which enabled env-var (`HTTP(S)_PROXY`) defined proxy support.
|
37
|
+
* proxy: fixed graceful recovery from proxy tcp connect errors.
|
38
|
+
* several fixes around CNAMEs timeouts with the native resolver.
|
39
|
+
* https resolver is now closed when wrapping session closes (it was left open).
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# 0.19.2
|
2
|
+
|
3
|
+
## Bugfixes
|
4
|
+
|
5
|
+
* skip resolution delay path for early resolve cases
|
6
|
+
|
7
|
+
when the early resolve path (using IP, /etc/hosts IP, IP from cache) is followed, emit_addresses is called, and in a particular case (dual-stack network but using an IPv4 address), the happy eyeballs resolution delay path was activated when it shouldn't (it's meant to be used only for DNS network requests), and resulted in @pool being called before it was ever set. This simple check ensures that it doesn't happen before it must.
|
@@ -81,6 +81,9 @@ module Faraday
|
|
81
81
|
|
82
82
|
def response=(response)
|
83
83
|
super
|
84
|
+
|
85
|
+
return if response.is_a?(::HTTPX::ErrorResponse)
|
86
|
+
|
84
87
|
response.body.on_data = @response_on_data
|
85
88
|
end
|
86
89
|
end
|
@@ -136,7 +139,7 @@ module Faraday
|
|
136
139
|
|
137
140
|
def on_response(&blk)
|
138
141
|
if blk
|
139
|
-
@on_response =
|
142
|
+
@on_response = ->(response) do
|
140
143
|
blk.call(response)
|
141
144
|
end
|
142
145
|
self
|
@@ -200,9 +203,9 @@ module Faraday
|
|
200
203
|
end
|
201
204
|
end
|
202
205
|
|
203
|
-
def initialize(app)
|
206
|
+
def initialize(app, options = {})
|
204
207
|
super(app)
|
205
|
-
@session = Session.new
|
208
|
+
@session = Session.new(options)
|
206
209
|
end
|
207
210
|
|
208
211
|
def call(env)
|
@@ -210,6 +213,7 @@ module Faraday
|
|
210
213
|
if parallel?(env)
|
211
214
|
handler = env[:parallel_manager].enqueue(env)
|
212
215
|
handler.on_response do |response|
|
216
|
+
response.raise_for_status
|
213
217
|
save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
|
214
218
|
response_headers.merge!(response.headers)
|
215
219
|
end
|
@@ -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 =
|
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" =>
|
212
|
+
":path" => request.path,
|
217
213
|
":authority" => request.authority,
|
218
214
|
}
|
219
215
|
end
|
data/lib/httpx/connection.rb
CHANGED
@@ -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 :io, :origin, :origins, :state, :pending, :options
|
48
48
|
|
49
49
|
attr_writer :timers
|
50
50
|
|
@@ -78,7 +78,11 @@ module HTTPX
|
|
78
78
|
# this is a semi-private method, to be used by the resolver
|
79
79
|
# to initiate the io object.
|
80
80
|
def addresses=(addrs)
|
81
|
-
@io
|
81
|
+
if @io
|
82
|
+
@io.add_addresses(addrs)
|
83
|
+
else
|
84
|
+
@io = IO.registry(@type).new(@origin, addrs, @options)
|
85
|
+
end
|
82
86
|
end
|
83
87
|
|
84
88
|
def addresses
|
@@ -489,6 +493,18 @@ module HTTPX
|
|
489
493
|
end
|
490
494
|
|
491
495
|
def transition(nextstate)
|
496
|
+
handle_transition(nextstate)
|
497
|
+
rescue Errno::ECONNREFUSED,
|
498
|
+
Errno::EADDRNOTAVAIL,
|
499
|
+
Errno::EHOSTUNREACH,
|
500
|
+
TLSError => e
|
501
|
+
# connect errors, exit gracefully
|
502
|
+
handle_error(e)
|
503
|
+
@state = :closed
|
504
|
+
emit(:close)
|
505
|
+
end
|
506
|
+
|
507
|
+
def handle_transition(nextstate)
|
492
508
|
case nextstate
|
493
509
|
when :idle
|
494
510
|
@timeout = @current_timeout = @options.timeout[:connect_timeout]
|
@@ -525,14 +541,6 @@ module HTTPX
|
|
525
541
|
emit(:activate)
|
526
542
|
end
|
527
543
|
@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
544
|
end
|
537
545
|
|
538
546
|
def purge_after_closed
|
@@ -550,6 +558,10 @@ module HTTPX
|
|
550
558
|
ex.set_backtrace(error.backtrace)
|
551
559
|
error = ex
|
552
560
|
else
|
561
|
+
# inactive connections do not contribute to the select loop, therefore
|
562
|
+
# they should fail due to such errors.
|
563
|
+
return if @state == :inactive
|
564
|
+
|
553
565
|
if @timeout
|
554
566
|
@timeout -= error.timeout
|
555
567
|
return unless @timeout <= 0
|
data/lib/httpx/extensions.rb
CHANGED
@@ -54,6 +54,22 @@ module HTTPX
|
|
54
54
|
Numeric.__send__(:include, NegMethods)
|
55
55
|
end
|
56
56
|
|
57
|
+
module StringExtensions
|
58
|
+
refine String do
|
59
|
+
def delete_suffix!(suffix)
|
60
|
+
suffix = Backports.coerce_to_str(suffix)
|
61
|
+
chomp! if frozen?
|
62
|
+
len = suffix.length
|
63
|
+
if len > 0 && index(suffix, -len)
|
64
|
+
self[-len..-1] = ''
|
65
|
+
self
|
66
|
+
else
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
end unless String.method_defined?(:delete_suffix!)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
57
73
|
module HashExtensions
|
58
74
|
refine Hash do
|
59
75
|
def compact
|
data/lib/httpx/headers.rb
CHANGED
data/lib/httpx/io/tcp.rb
CHANGED
@@ -15,6 +15,7 @@ module HTTPX
|
|
15
15
|
|
16
16
|
def initialize(origin, addresses, options)
|
17
17
|
@state = :idle
|
18
|
+
@addresses = []
|
18
19
|
@hostname = origin.host
|
19
20
|
@options = Options.new(options)
|
20
21
|
@fallback_protocol = @options.fallback_protocol
|
@@ -30,15 +31,29 @@ module HTTPX
|
|
30
31
|
raise Error, "Given IO objects do not match the request authority" unless @io
|
31
32
|
|
32
33
|
_, _, _, @ip = @io.addr
|
33
|
-
@addresses
|
34
|
-
@ip_index = @addresses.size - 1
|
34
|
+
@addresses << @ip
|
35
35
|
@keep_open = true
|
36
36
|
@state = :connected
|
37
37
|
else
|
38
|
-
|
38
|
+
add_addresses(addresses)
|
39
39
|
end
|
40
40
|
@ip_index = @addresses.size - 1
|
41
|
-
@io ||= build_socket
|
41
|
+
# @io ||= build_socket
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_addresses(addrs)
|
45
|
+
return if addrs.empty?
|
46
|
+
|
47
|
+
addrs = addrs.map { |addr| addr.is_a?(IPAddr) ? addr : IPAddr.new(addr) }
|
48
|
+
|
49
|
+
ip_index = @ip_index || (@addresses.size - 1)
|
50
|
+
if addrs.first.ipv6?
|
51
|
+
# should be the next in line
|
52
|
+
@addresses = [*@addresses[0, ip_index], *addrs, *@addresses[ip_index..-1]]
|
53
|
+
else
|
54
|
+
@addresses.unshift(*addrs)
|
55
|
+
@ip_index += addrs.size if @ip_index
|
56
|
+
end
|
42
57
|
end
|
43
58
|
|
44
59
|
def to_io
|
@@ -52,20 +67,26 @@ module HTTPX
|
|
52
67
|
def connect
|
53
68
|
return unless closed?
|
54
69
|
|
55
|
-
if @io.closed?
|
70
|
+
if !@io || @io.closed?
|
56
71
|
transition(:idle)
|
57
72
|
@io = build_socket
|
58
73
|
end
|
59
74
|
try_connect
|
60
|
-
rescue Errno::
|
75
|
+
rescue Errno::ECONNREFUSED,
|
76
|
+
Errno::EADDRNOTAVAIL,
|
77
|
+
Errno::EHOSTUNREACH => e
|
61
78
|
raise e if @ip_index <= 0
|
62
79
|
|
80
|
+
log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
|
63
81
|
@ip_index -= 1
|
82
|
+
@io = build_socket
|
64
83
|
retry
|
65
84
|
rescue Errno::ETIMEDOUT => e
|
66
85
|
raise ConnectTimeoutError.new(@options.timeout[:connect_timeout], e.message) if @ip_index <= 0
|
67
86
|
|
87
|
+
log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
|
68
88
|
@ip_index -= 1
|
89
|
+
@io = build_socket
|
69
90
|
retry
|
70
91
|
end
|
71
92
|
|
data/lib/httpx/options.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "socket"
|
4
|
+
|
3
5
|
module HTTPX
|
4
6
|
class Options
|
5
7
|
WINDOW_SIZE = 1 << 14 # 16K
|
@@ -9,6 +11,18 @@ module HTTPX
|
|
9
11
|
KEEP_ALIVE_TIMEOUT = 20
|
10
12
|
SETTINGS_TIMEOUT = 10
|
11
13
|
|
14
|
+
# https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
|
15
|
+
ip_address_families = begin
|
16
|
+
list = Socket.ip_address_list
|
17
|
+
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
|
18
|
+
[Socket::AF_INET6, Socket::AF_INET]
|
19
|
+
else
|
20
|
+
[Socket::AF_INET]
|
21
|
+
end
|
22
|
+
rescue NotImplementedError
|
23
|
+
[Socket::AF_INET]
|
24
|
+
end
|
25
|
+
|
12
26
|
DEFAULT_OPTIONS = {
|
13
27
|
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
14
28
|
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
@@ -37,6 +51,7 @@ module HTTPX
|
|
37
51
|
:persistent => false,
|
38
52
|
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
39
53
|
:resolver_options => { cache: true },
|
54
|
+
:ip_families => ip_address_families,
|
40
55
|
}.freeze
|
41
56
|
|
42
57
|
begin
|
@@ -110,20 +125,18 @@ module HTTPX
|
|
110
125
|
end
|
111
126
|
|
112
127
|
def initialize(options = {})
|
113
|
-
|
114
|
-
defaults.each do |k, v|
|
115
|
-
next if v.nil?
|
116
|
-
|
117
|
-
begin
|
118
|
-
value = __send__(:"option_#{k}", v)
|
119
|
-
instance_variable_set(:"@#{k}", value)
|
120
|
-
rescue NoMethodError
|
121
|
-
raise Error, "unknown option: #{k}"
|
122
|
-
end
|
123
|
-
end
|
128
|
+
__initialize__(options)
|
124
129
|
freeze
|
125
130
|
end
|
126
131
|
|
132
|
+
def freeze
|
133
|
+
super
|
134
|
+
@origin.freeze
|
135
|
+
@timeout.freeze
|
136
|
+
@headers.freeze
|
137
|
+
@addresses.freeze
|
138
|
+
end
|
139
|
+
|
127
140
|
def option_origin(value)
|
128
141
|
URI(value)
|
129
142
|
end
|
@@ -174,6 +187,10 @@ module HTTPX
|
|
174
187
|
Array(value)
|
175
188
|
end
|
176
189
|
|
190
|
+
def option_ip_families(value)
|
191
|
+
Array(value)
|
192
|
+
end
|
193
|
+
|
177
194
|
%i[
|
178
195
|
params form json body ssl http2_settings
|
179
196
|
request_class response_class headers_class request_body_class
|
@@ -249,5 +266,21 @@ module HTTPX
|
|
249
266
|
end
|
250
267
|
end
|
251
268
|
end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
def __initialize__(options = {})
|
273
|
+
defaults = DEFAULT_OPTIONS.merge(options)
|
274
|
+
defaults.each do |k, v|
|
275
|
+
next if v.nil?
|
276
|
+
|
277
|
+
begin
|
278
|
+
value = __send__(:"option_#{k}", v)
|
279
|
+
instance_variable_set(:"@#{k}", value)
|
280
|
+
rescue NoMethodError
|
281
|
+
raise Error, "unknown option: #{k}"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
252
285
|
end
|
253
286
|
end
|
@@ -18,12 +18,6 @@ module HTTPX
|
|
18
18
|
require "httpx/plugins/cookies/set_cookie_parser"
|
19
19
|
end
|
20
20
|
|
21
|
-
module OptionsMethods
|
22
|
-
def option_cookies(value)
|
23
|
-
value.is_a?(Jar) ? value : Jar.new(value)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
21
|
module InstanceMethods
|
28
22
|
extend Forwardable
|
29
23
|
|
@@ -77,7 +71,7 @@ module HTTPX
|
|
77
71
|
end
|
78
72
|
|
79
73
|
module OptionsMethods
|
80
|
-
def
|
74
|
+
def __initialize__(*)
|
81
75
|
super
|
82
76
|
|
83
77
|
return unless @headers.key?("cookie")
|
@@ -89,6 +83,10 @@ module HTTPX
|
|
89
83
|
end
|
90
84
|
end
|
91
85
|
end
|
86
|
+
|
87
|
+
def option_cookies(value)
|
88
|
+
value.is_a?(Jar) ? value : Jar.new(value)
|
89
|
+
end
|
92
90
|
end
|
93
91
|
end
|
94
92
|
register_plugin :cookies, Cookies
|
@@ -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
|
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 =
|
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
|
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
|
-
|
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
|
-
|
80
|
-
def
|
81
|
-
request.
|
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, {})
|