httpx 0.21.0 → 1.2.1
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 +4 -4
- data/LICENSE.txt +0 -48
- data/README.md +54 -45
- data/doc/release_notes/0_10_0.md +2 -2
- data/doc/release_notes/0_11_0.md +3 -5
- data/doc/release_notes/0_12_0.md +5 -5
- data/doc/release_notes/0_13_0.md +4 -4
- data/doc/release_notes/0_14_0.md +2 -2
- data/doc/release_notes/0_16_0.md +3 -3
- data/doc/release_notes/0_17_0.md +1 -1
- data/doc/release_notes/0_18_0.md +4 -4
- data/doc/release_notes/0_18_2.md +1 -1
- data/doc/release_notes/0_19_0.md +1 -1
- data/doc/release_notes/0_20_0.md +1 -1
- data/doc/release_notes/0_21_0.md +7 -5
- data/doc/release_notes/0_21_1.md +12 -0
- data/doc/release_notes/0_22_0.md +13 -0
- data/doc/release_notes/0_22_1.md +11 -0
- data/doc/release_notes/0_22_2.md +5 -0
- data/doc/release_notes/0_22_3.md +55 -0
- data/doc/release_notes/0_22_4.md +6 -0
- data/doc/release_notes/0_22_5.md +6 -0
- data/doc/release_notes/0_23_0.md +42 -0
- data/doc/release_notes/0_23_1.md +5 -0
- data/doc/release_notes/0_23_2.md +5 -0
- data/doc/release_notes/0_23_3.md +6 -0
- data/doc/release_notes/0_23_4.md +5 -0
- data/doc/release_notes/0_24_0.md +48 -0
- data/doc/release_notes/0_24_1.md +12 -0
- data/doc/release_notes/0_24_2.md +12 -0
- data/doc/release_notes/0_24_3.md +12 -0
- data/doc/release_notes/0_24_4.md +18 -0
- data/doc/release_notes/0_24_5.md +6 -0
- data/doc/release_notes/0_24_6.md +5 -0
- data/doc/release_notes/0_24_7.md +10 -0
- data/doc/release_notes/1_0_0.md +60 -0
- data/doc/release_notes/1_0_1.md +5 -0
- data/doc/release_notes/1_0_2.md +7 -0
- data/doc/release_notes/1_1_0.md +32 -0
- data/doc/release_notes/1_1_1.md +17 -0
- data/doc/release_notes/1_1_2.md +12 -0
- data/doc/release_notes/1_1_3.md +18 -0
- data/doc/release_notes/1_1_4.md +6 -0
- data/doc/release_notes/1_1_5.md +12 -0
- data/doc/release_notes/1_2_0.md +49 -0
- data/doc/release_notes/1_2_1.md +6 -0
- data/lib/httpx/adapters/datadog.rb +100 -106
- data/lib/httpx/adapters/faraday.rb +143 -107
- data/lib/httpx/adapters/sentry.rb +26 -7
- data/lib/httpx/adapters/webmock.rb +33 -17
- data/lib/httpx/altsvc.rb +61 -24
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/buffer.rb +12 -0
- data/lib/httpx/callbacks.rb +5 -3
- data/lib/httpx/chainable.rb +54 -39
- data/lib/httpx/connection/http1.rb +62 -37
- data/lib/httpx/connection/http2.rb +16 -27
- data/lib/httpx/connection.rb +213 -120
- data/lib/httpx/domain_name.rb +10 -13
- data/lib/httpx/errors.rb +34 -2
- data/lib/httpx/extensions.rb +4 -134
- data/lib/httpx/io/ssl.rb +77 -71
- data/lib/httpx/io/tcp.rb +46 -70
- data/lib/httpx/io/udp.rb +18 -52
- data/lib/httpx/io/unix.rb +6 -13
- data/lib/httpx/io.rb +3 -9
- data/lib/httpx/loggable.rb +4 -19
- data/lib/httpx/options.rb +168 -110
- data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
- data/lib/httpx/plugins/{authentication → auth}/digest.rb +13 -14
- data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
- data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sdk_authentication.rb +1 -3
- data/lib/httpx/plugins/aws_sigv4.rb +5 -6
- data/lib/httpx/plugins/basic_auth.rb +29 -0
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/callbacks.rb +91 -0
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +40 -16
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +14 -5
- data/lib/httpx/plugins/circuit_breaker.rb +30 -7
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
- data/lib/httpx/plugins/cookies.rb +20 -10
- data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +11 -12
- data/lib/httpx/plugins/expect.rb +15 -13
- data/lib/httpx/plugins/follow_redirects.rb +71 -29
- data/lib/httpx/plugins/grpc/call.rb +2 -3
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +88 -0
- data/lib/httpx/plugins/grpc/message.rb +7 -37
- data/lib/httpx/plugins/grpc.rb +35 -29
- data/lib/httpx/plugins/h2c.rb +25 -18
- data/lib/httpx/plugins/internal_telemetry.rb +16 -0
- data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +7 -5
- data/lib/httpx/plugins/oauth.rb +170 -0
- data/lib/httpx/plugins/persistent.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +15 -10
- data/lib/httpx/plugins/proxy/socks4.rb +8 -6
- data/lib/httpx/plugins/proxy/socks5.rb +10 -8
- data/lib/httpx/plugins/proxy.rb +69 -67
- data/lib/httpx/plugins/push_promise.rb +1 -1
- data/lib/httpx/plugins/rate_limiter.rb +3 -1
- data/lib/httpx/plugins/response_cache/file_store.rb +40 -0
- data/lib/httpx/plugins/response_cache/store.rb +34 -17
- data/lib/httpx/plugins/response_cache.rb +6 -6
- data/lib/httpx/plugins/retries.rb +61 -12
- data/lib/httpx/plugins/ssrf_filter.rb +142 -0
- data/lib/httpx/plugins/stream.rb +27 -32
- data/lib/httpx/plugins/upgrade/h2.rb +4 -4
- data/lib/httpx/plugins/upgrade.rb +8 -10
- data/lib/httpx/plugins/webdav.rb +10 -8
- data/lib/httpx/pool.rb +85 -23
- data/lib/httpx/punycode.rb +9 -291
- data/lib/httpx/request/body.rb +158 -0
- data/lib/httpx/request.rb +86 -121
- data/lib/httpx/resolver/https.rb +54 -17
- data/lib/httpx/resolver/multi.rb +8 -12
- data/lib/httpx/resolver/native.rb +163 -70
- data/lib/httpx/resolver/resolver.rb +28 -13
- data/lib/httpx/resolver/system.rb +15 -10
- data/lib/httpx/resolver.rb +38 -16
- data/lib/httpx/response/body.rb +242 -0
- data/lib/httpx/response/buffer.rb +96 -0
- data/lib/httpx/response.rb +113 -211
- data/lib/httpx/selector.rb +2 -4
- data/lib/httpx/session.rb +91 -64
- data/lib/httpx/session_extensions.rb +4 -1
- data/lib/httpx/timers.rb +28 -8
- data/lib/httpx/transcoder/body.rb +0 -2
- data/lib/httpx/transcoder/chunker.rb +0 -1
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +52 -33
- data/lib/httpx/transcoder/gzip.rb +74 -0
- data/lib/httpx/transcoder/json.rb +2 -5
- data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
- data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +3 -3
- data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
- data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
- data/lib/httpx/transcoder/multipart.rb +17 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +72 -0
- data/lib/httpx/transcoder/utils/inflater.rb +19 -0
- data/lib/httpx/transcoder/xml.rb +0 -5
- data/lib/httpx/transcoder.rb +4 -6
- data/lib/httpx/utils.rb +36 -16
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +12 -14
- data/sig/altsvc.rbs +33 -0
- data/sig/buffer.rbs +1 -0
- data/sig/callbacks.rbs +3 -3
- data/sig/chainable.rbs +10 -9
- data/sig/connection/http1.rbs +5 -4
- data/sig/connection/http2.rbs +1 -1
- data/sig/connection.rbs +46 -24
- data/sig/errors.rbs +9 -3
- data/sig/httpx.rbs +5 -4
- data/sig/io/ssl.rbs +26 -0
- data/sig/io/tcp.rbs +60 -0
- data/sig/io/udp.rbs +20 -0
- data/sig/io/unix.rbs +10 -0
- data/sig/options.rbs +28 -12
- data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
- data/sig/plugins/{authentication → auth}/digest.rbs +2 -1
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
- data/sig/plugins/brotli.rbs +22 -0
- data/sig/plugins/callbacks.rbs +38 -0
- data/sig/plugins/circuit_breaker.rbs +13 -3
- data/sig/plugins/compression.rbs +6 -4
- data/sig/plugins/cookies/jar.rbs +2 -2
- data/sig/plugins/cookies.rbs +2 -0
- data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
- data/sig/plugins/follow_redirects.rbs +11 -2
- data/sig/plugins/grpc/call.rbs +19 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +2 -32
- data/sig/plugins/h2c.rbs +1 -1
- data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
- data/sig/plugins/oauth.rbs +54 -0
- data/sig/plugins/proxy/socks4.rbs +4 -4
- data/sig/plugins/proxy/socks5.rbs +2 -2
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/proxy.rbs +10 -4
- data/sig/plugins/response_cache.rbs +12 -3
- data/sig/plugins/retries.rbs +28 -8
- data/sig/plugins/stream.rbs +24 -17
- data/sig/plugins/upgrade.rbs +5 -3
- data/sig/pool.rbs +5 -4
- data/sig/request/body.rbs +40 -0
- data/sig/request.rbs +12 -28
- data/sig/resolver/https.rbs +7 -2
- data/sig/resolver/native.rbs +10 -4
- data/sig/resolver/resolver.rbs +6 -4
- data/sig/resolver/system.rbs +2 -0
- data/sig/resolver.rbs +9 -5
- data/sig/response/body.rbs +53 -0
- data/sig/response/buffer.rbs +24 -0
- data/sig/response.rbs +17 -38
- data/sig/session.rbs +24 -18
- data/sig/timers.rbs +17 -7
- data/sig/transcoder/body.rbs +4 -3
- data/sig/transcoder/deflate.rbs +11 -0
- data/sig/transcoder/form.rbs +5 -3
- data/sig/transcoder/gzip.rbs +24 -0
- data/sig/transcoder/json.rbs +4 -2
- data/sig/{plugins → transcoder}/multipart.rbs +3 -12
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +29 -0
- data/sig/transcoder/utils/inflater.rbs +12 -0
- data/sig/transcoder/xml.rbs +1 -1
- data/sig/transcoder.rbs +22 -7
- data/sig/utils.rbs +2 -0
- metadata +127 -40
- data/lib/httpx/plugins/authentication.rb +0 -20
- data/lib/httpx/plugins/basic_authentication.rb +0 -30
- data/lib/httpx/plugins/compression/brotli.rb +0 -54
- data/lib/httpx/plugins/compression/deflate.rb +0 -49
- data/lib/httpx/plugins/compression/gzip.rb +0 -88
- data/lib/httpx/plugins/compression.rb +0 -164
- data/lib/httpx/plugins/multipart/decoder.rb +0 -187
- data/lib/httpx/plugins/multipart.rb +0 -84
- data/lib/httpx/registry.rb +0 -85
- data/sig/plugins/authentication.rbs +0 -11
- data/sig/plugins/compression/brotli.rbs +0 -21
- data/sig/plugins/compression/deflate.rbs +0 -17
- data/sig/plugins/compression/gzip.rbs +0 -29
- data/sig/registry.rbs +0 -13
- /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
data/lib/httpx/io/udp.rb
CHANGED
|
@@ -6,11 +6,10 @@ module HTTPX
|
|
|
6
6
|
class UDP
|
|
7
7
|
include Loggable
|
|
8
8
|
|
|
9
|
-
def initialize(
|
|
10
|
-
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
@io = UDPSocket.new(ip.family)
|
|
9
|
+
def initialize(ip, port, options)
|
|
10
|
+
@host = ip
|
|
11
|
+
@port = port
|
|
12
|
+
@io = UDPSocket.new(IPAddr.new(ip).family)
|
|
14
13
|
@options = options
|
|
15
14
|
end
|
|
16
15
|
|
|
@@ -24,45 +23,19 @@ module HTTPX
|
|
|
24
23
|
true
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def close
|
|
30
|
-
@io.close
|
|
31
|
-
rescue StandardError
|
|
32
|
-
nil
|
|
33
|
-
end
|
|
34
|
-
# :nocov:
|
|
35
|
-
else
|
|
36
|
-
def close
|
|
37
|
-
@io.close
|
|
38
|
-
end
|
|
26
|
+
def close
|
|
27
|
+
@io.close
|
|
39
28
|
end
|
|
40
29
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
RUBY_VERSION < "2.3"
|
|
30
|
+
if RUBY_ENGINE == "jruby"
|
|
31
|
+
# In JRuby, sendmsg_nonblock is not implemented
|
|
44
32
|
def write(buffer)
|
|
45
|
-
siz = @io.
|
|
33
|
+
siz = @io.send(buffer.to_s, 0, @host, @port)
|
|
46
34
|
log { "WRITE: #{siz} bytes..." }
|
|
47
35
|
buffer.shift!(siz)
|
|
48
36
|
siz
|
|
49
|
-
rescue ::IO::WaitWritable
|
|
50
|
-
0
|
|
51
|
-
rescue EOFError
|
|
52
|
-
nil
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def read(size, buffer)
|
|
56
|
-
data, _ = @io.recvfrom_nonblock(size)
|
|
57
|
-
buffer.replace(data)
|
|
58
|
-
log { "READ: #{buffer.bytesize} bytes..." }
|
|
59
|
-
buffer.bytesize
|
|
60
|
-
rescue ::IO::WaitReadable
|
|
61
|
-
0
|
|
62
|
-
rescue IOError
|
|
63
37
|
end
|
|
64
38
|
else
|
|
65
|
-
|
|
66
39
|
def write(buffer)
|
|
67
40
|
siz = @io.sendmsg_nonblock(buffer.to_s, 0, Socket.sockaddr_in(@port, @host.to_s), exception: false)
|
|
68
41
|
return 0 if siz == :wait_writable
|
|
@@ -73,24 +46,17 @@ module HTTPX
|
|
|
73
46
|
buffer.shift!(siz)
|
|
74
47
|
siz
|
|
75
48
|
end
|
|
49
|
+
end
|
|
76
50
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
51
|
+
def read(size, buffer)
|
|
52
|
+
ret = @io.recvfrom_nonblock(size, 0, buffer, exception: false)
|
|
53
|
+
return 0 if ret == :wait_readable
|
|
54
|
+
return if ret.nil?
|
|
81
55
|
|
|
82
|
-
|
|
83
|
-
rescue IOError
|
|
84
|
-
end
|
|
85
|
-
end
|
|
56
|
+
log { "READ: #{buffer.bytesize} bytes..." }
|
|
86
57
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
log { "WRITE: #{siz} bytes..." }
|
|
91
|
-
buffer.shift!(siz)
|
|
92
|
-
siz
|
|
93
|
-
end if RUBY_ENGINE == "jruby"
|
|
94
|
-
# :nocov:
|
|
58
|
+
buffer.bytesize
|
|
59
|
+
rescue IOError
|
|
60
|
+
end
|
|
95
61
|
end
|
|
96
62
|
end
|
data/lib/httpx/io/unix.rb
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "forwardable"
|
|
4
|
-
|
|
5
3
|
module HTTPX
|
|
6
4
|
class UNIX < TCP
|
|
7
|
-
extend Forwardable
|
|
8
|
-
|
|
9
5
|
using URIExtensions
|
|
10
6
|
|
|
11
7
|
attr_reader :path
|
|
@@ -13,7 +9,7 @@ module HTTPX
|
|
|
13
9
|
alias_method :host, :path
|
|
14
10
|
|
|
15
11
|
def initialize(origin, addresses, options)
|
|
16
|
-
@addresses =
|
|
12
|
+
@addresses = []
|
|
17
13
|
@hostname = origin.host
|
|
18
14
|
@state = :idle
|
|
19
15
|
@options = Options.new(options)
|
|
@@ -31,14 +27,7 @@ module HTTPX
|
|
|
31
27
|
@keep_open = true
|
|
32
28
|
@state = :connected
|
|
33
29
|
else
|
|
34
|
-
|
|
35
|
-
# :nocov:
|
|
36
|
-
warn ":transport_options is deprecated, use :addresses instead"
|
|
37
|
-
@path = @options.transport_options[:path]
|
|
38
|
-
# :nocov:
|
|
39
|
-
else
|
|
40
|
-
@path = addresses.first
|
|
41
|
-
end
|
|
30
|
+
@path = addresses.first
|
|
42
31
|
end
|
|
43
32
|
@io ||= build_socket
|
|
44
33
|
end
|
|
@@ -60,6 +49,10 @@ module HTTPX
|
|
|
60
49
|
::IO::WaitReadable
|
|
61
50
|
end
|
|
62
51
|
|
|
52
|
+
def expired?
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
|
|
63
56
|
# :nocov:
|
|
64
57
|
def inspect
|
|
65
58
|
"#<#{self.class}(path: #{@path}): (state: #{@state})>"
|
data/lib/httpx/io.rb
CHANGED
|
@@ -4,14 +4,8 @@ require "socket"
|
|
|
4
4
|
require "httpx/io/udp"
|
|
5
5
|
require "httpx/io/tcp"
|
|
6
6
|
require "httpx/io/unix"
|
|
7
|
-
require "httpx/io/ssl"
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
register "udp", UDP
|
|
13
|
-
register "unix", HTTPX::UNIX
|
|
14
|
-
register "tcp", TCP
|
|
15
|
-
register "ssl", SSL
|
|
16
|
-
end
|
|
8
|
+
begin
|
|
9
|
+
require "httpx/io/ssl"
|
|
10
|
+
rescue LoadError
|
|
17
11
|
end
|
data/lib/httpx/loggable.rb
CHANGED
|
@@ -24,26 +24,11 @@ module HTTPX
|
|
|
24
24
|
debug_stream << message
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return unless @options.debug
|
|
31
|
-
return unless @options.debug_level >= level
|
|
32
|
-
|
|
33
|
-
log(level: level, color: color) { ex.full_message }
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
else
|
|
37
|
-
|
|
38
|
-
def log_exception(ex, level: @options.debug_level, color: nil)
|
|
39
|
-
return unless @options.debug
|
|
40
|
-
return unless @options.debug_level >= level
|
|
41
|
-
|
|
42
|
-
message = +"#{ex.message} (#{ex.class})"
|
|
43
|
-
message << "\n" << ex.backtrace.join("\n") unless ex.backtrace.nil?
|
|
44
|
-
log(level: level, color: color) { message }
|
|
45
|
-
end
|
|
27
|
+
def log_exception(ex, level: @options.debug_level, color: nil)
|
|
28
|
+
return unless @options.debug
|
|
29
|
+
return unless @options.debug_level >= level
|
|
46
30
|
|
|
31
|
+
log(level: level, color: color) { ex.full_message }
|
|
47
32
|
end
|
|
48
33
|
end
|
|
49
34
|
end
|
data/lib/httpx/options.rb
CHANGED
|
@@ -3,19 +3,22 @@
|
|
|
3
3
|
require "socket"
|
|
4
4
|
|
|
5
5
|
module HTTPX
|
|
6
|
+
# Contains a set of options which are passed and shared across from session to its requests or
|
|
7
|
+
# responses.
|
|
6
8
|
class Options
|
|
9
|
+
BUFFER_SIZE = 1 << 14
|
|
7
10
|
WINDOW_SIZE = 1 << 14 # 16K
|
|
8
11
|
MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112 # 112K
|
|
9
|
-
CONNECT_TIMEOUT = 60
|
|
10
|
-
OPERATION_TIMEOUT = 60
|
|
11
12
|
KEEP_ALIVE_TIMEOUT = 20
|
|
12
13
|
SETTINGS_TIMEOUT = 10
|
|
13
|
-
|
|
14
|
+
CLOSE_HANDSHAKE_TIMEOUT = 10
|
|
15
|
+
CONNECT_TIMEOUT = READ_TIMEOUT = WRITE_TIMEOUT = 60
|
|
16
|
+
REQUEST_TIMEOUT = OPERATION_TIMEOUT = nil
|
|
14
17
|
|
|
15
18
|
# https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
|
|
16
19
|
ip_address_families = begin
|
|
17
20
|
list = Socket.ip_address_list
|
|
18
|
-
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
|
|
21
|
+
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? && !a.ipv6_unique_local? }
|
|
19
22
|
[Socket::AF_INET6, Socket::AF_INET]
|
|
20
23
|
else
|
|
21
24
|
[Socket::AF_INET]
|
|
@@ -25,14 +28,19 @@ module HTTPX
|
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
DEFAULT_OPTIONS = {
|
|
31
|
+
:max_requests => Float::INFINITY,
|
|
28
32
|
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
|
29
33
|
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
|
30
34
|
:ssl => {},
|
|
31
35
|
:http2_settings => { settings_enable_push: 0 },
|
|
32
36
|
:fallback_protocol => "http/1.1",
|
|
37
|
+
:supported_compression_formats => %w[gzip deflate],
|
|
38
|
+
:decompress_response_body => true,
|
|
39
|
+
:compress_request_body => true,
|
|
33
40
|
:timeout => {
|
|
34
41
|
connect_timeout: CONNECT_TIMEOUT,
|
|
35
42
|
settings_timeout: SETTINGS_TIMEOUT,
|
|
43
|
+
close_handshake_timeout: CLOSE_HANDSHAKE_TIMEOUT,
|
|
36
44
|
operation_timeout: OPERATION_TIMEOUT,
|
|
37
45
|
keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
|
|
38
46
|
read_timeout: READ_TIMEOUT,
|
|
@@ -41,6 +49,7 @@ module HTTPX
|
|
|
41
49
|
},
|
|
42
50
|
:headers => {},
|
|
43
51
|
:window_size => WINDOW_SIZE,
|
|
52
|
+
:buffer_size => BUFFER_SIZE,
|
|
44
53
|
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
|
|
45
54
|
:request_class => Class.new(Request),
|
|
46
55
|
:response_class => Class.new(Response),
|
|
@@ -50,7 +59,6 @@ module HTTPX
|
|
|
50
59
|
:connection_class => Class.new(Connection),
|
|
51
60
|
:options_class => Class.new(self),
|
|
52
61
|
:transport => nil,
|
|
53
|
-
:transport_options => nil,
|
|
54
62
|
:addresses => nil,
|
|
55
63
|
:persistent => false,
|
|
56
64
|
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
|
@@ -58,28 +66,6 @@ module HTTPX
|
|
|
58
66
|
:ip_families => ip_address_families,
|
|
59
67
|
}.freeze
|
|
60
68
|
|
|
61
|
-
begin
|
|
62
|
-
module HashExtensions
|
|
63
|
-
refine Hash do
|
|
64
|
-
def >=(other)
|
|
65
|
-
Hash[other] <= self
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def <=(other)
|
|
69
|
-
other = Hash[other]
|
|
70
|
-
return false unless size <= other.size
|
|
71
|
-
|
|
72
|
-
each do |k, v|
|
|
73
|
-
v2 = other.fetch(k) { return false }
|
|
74
|
-
return false unless v2 == v
|
|
75
|
-
end
|
|
76
|
-
true
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
using HashExtensions
|
|
81
|
-
end unless Hash.method_defined?(:>=)
|
|
82
|
-
|
|
83
69
|
class << self
|
|
84
70
|
def new(options = {})
|
|
85
71
|
# let enhanced options go through
|
|
@@ -98,38 +84,54 @@ module HTTPX
|
|
|
98
84
|
|
|
99
85
|
attr_reader(optname)
|
|
100
86
|
end
|
|
101
|
-
|
|
102
|
-
def def_option(optname, *args, &block)
|
|
103
|
-
if args.size.zero? && !block
|
|
104
|
-
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
|
105
|
-
def option_#{optname}(v); v; end # def option_smth(v); v; end
|
|
106
|
-
OUT
|
|
107
|
-
return
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
deprecated_def_option(optname, *args, &block)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def deprecated_def_option(optname, layout = nil, &interpreter)
|
|
114
|
-
warn "DEPRECATION WARNING: using `def_option(#{optname})` for setting options is deprecated. " \
|
|
115
|
-
"Define module OptionsMethods and `def option_#{optname}(val)` instead."
|
|
116
|
-
|
|
117
|
-
if layout
|
|
118
|
-
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
|
119
|
-
def option_#{optname}(value) # def option_origin(v)
|
|
120
|
-
#{layout} # URI(v)
|
|
121
|
-
end # end
|
|
122
|
-
OUT
|
|
123
|
-
elsif interpreter
|
|
124
|
-
define_method(:"option_#{optname}") do |value|
|
|
125
|
-
instance_exec(value, &interpreter)
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
87
|
end
|
|
130
88
|
|
|
89
|
+
# creates a new options instance from a given hash, which optionally define the following:
|
|
90
|
+
#
|
|
91
|
+
# :debug :: an object which log messages are written to (must respond to <tt><<</tt>)
|
|
92
|
+
# :debug_level :: the log level of messages (can be 1, 2, or 3).
|
|
93
|
+
# :ssl :: a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::IO::SSL)
|
|
94
|
+
# :http2_settings :: a hash of options to be passed to a HTTP2Next::Connection (ex: <tt>{ max_concurrent_streams: 2 }</tt>)
|
|
95
|
+
# :fallback_protocol :: version of HTTP protocol to use by default in the absence of protocol negotiation
|
|
96
|
+
# like ALPN (defaults to <tt>"http/1.1"</tt>)
|
|
97
|
+
# :supported_compression_formats :: list of compressions supported by the transcoder layer (defaults to <tt>%w[gzip deflate]</tt>).
|
|
98
|
+
# :decompress_response_body :: whether to auto-decompress response body (defaults to <tt>true</tt>).
|
|
99
|
+
# :compress_request_body :: whether to auto-decompress response body (defaults to <tt>true</tt>)
|
|
100
|
+
# :timeout :: hash of timeout configurations (supports <tt>:connect_timeout</tt>, <tt>:settings_timeout</tt>,
|
|
101
|
+
# <tt>:operation_timeout</tt>, <tt>:keep_alive_timeout</tt>, <tt>:read_timeout</tt>, <tt>:write_timeout</tt>
|
|
102
|
+
# and <tt>:request_timeout</tt>
|
|
103
|
+
# :headers :: hash of HTTP headers (ex: <tt>{ "x-custom-foo" => "bar" }</tt>)
|
|
104
|
+
# :window_size :: number of bytes to read from a socket
|
|
105
|
+
# :buffer_size :: internal read and write buffer size in bytes
|
|
106
|
+
# :body_threshold_size :: maximum size in bytes of response payload that is buffered in memory.
|
|
107
|
+
# :request_class :: class used to instantiate a request
|
|
108
|
+
# :response_class :: class used to instantiate a response
|
|
109
|
+
# :headers_class :: class used to instantiate headers
|
|
110
|
+
# :request_body_class :: class used to instantiate a request body
|
|
111
|
+
# :response_body_class :: class used to instantiate a response body
|
|
112
|
+
# :connection_class :: class used to instantiate connections
|
|
113
|
+
# :options_class :: class used to instantiate options
|
|
114
|
+
# :transport :: type of transport to use (set to "unix" for UNIX sockets)
|
|
115
|
+
# :addresses :: bucket of peer addresses (can be a list of IP addresses, a hash of domain to list of adddresses;
|
|
116
|
+
# paths should be used for UNIX sockets instead)
|
|
117
|
+
# :io :: open socket, or domain/ip-to-socket hash, which requests should be sent to
|
|
118
|
+
# :persistent :: whether to persist connections in between requests (defaults to <tt>true</tt>)
|
|
119
|
+
# :resolver_class :: which resolver to use (defaults to <tt>:native</tt>, can also be <tt>:system<tt> for
|
|
120
|
+
# using getaddrinfo or <tt>:https</tt> for DoH resolver, or a custom class)
|
|
121
|
+
# :resolver_options :: hash of options passed to the resolver
|
|
122
|
+
# :ip_families :: which socket families are supported (system-dependent)
|
|
123
|
+
# :origin :: HTTP origin to set on requests with relative path (ex: "https://api.serv.com")
|
|
124
|
+
# :base_path :: path to prefix given relative paths with (ex: "/v2")
|
|
125
|
+
# :max_concurrent_requests :: max number of requests which can be set concurrently
|
|
126
|
+
# :max_requests :: max number of requests which can be made on socket before it reconnects.
|
|
127
|
+
# :params :: hash or array of key-values which will be encoded and set in the query string of request uris.
|
|
128
|
+
# :form :: hash of array of key-values which will be form-or-multipart-encoded in requests body payload.
|
|
129
|
+
# :json :: hash of array of key-values which will be JSON-encoded in requests body payload.
|
|
130
|
+
# :xml :: Nokogiri XML nodes which will be encoded in requests body payload.
|
|
131
|
+
#
|
|
132
|
+
# This list of options are enhanced with each loaded plugin, see the plugin docs for details.
|
|
131
133
|
def initialize(options = {})
|
|
132
|
-
|
|
134
|
+
do_initialize(options)
|
|
133
135
|
freeze
|
|
134
136
|
end
|
|
135
137
|
|
|
@@ -140,6 +142,7 @@ module HTTPX
|
|
|
140
142
|
@timeout.freeze
|
|
141
143
|
@headers.freeze
|
|
142
144
|
@addresses.freeze
|
|
145
|
+
@supported_compression_formats.freeze
|
|
143
146
|
end
|
|
144
147
|
|
|
145
148
|
def option_origin(value)
|
|
@@ -155,14 +158,11 @@ module HTTPX
|
|
|
155
158
|
end
|
|
156
159
|
|
|
157
160
|
def option_timeout(value)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if timeouts.key?(:loop_timeout)
|
|
161
|
-
warn ":loop_timeout is deprecated, use :operation_timeout instead"
|
|
162
|
-
timeouts[:operation_timeout] = timeouts.delete(:loop_timeout)
|
|
163
|
-
end
|
|
161
|
+
Hash[value]
|
|
162
|
+
end
|
|
164
163
|
|
|
165
|
-
|
|
164
|
+
def option_supported_compression_formats(value)
|
|
165
|
+
Array(value).map(&:to_s)
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
def option_max_concurrent_requests(value)
|
|
@@ -178,16 +178,31 @@ module HTTPX
|
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
def option_window_size(value)
|
|
181
|
-
Integer(value)
|
|
181
|
+
value = Integer(value)
|
|
182
|
+
|
|
183
|
+
raise TypeError, ":window_size must be positive" unless value.positive?
|
|
184
|
+
|
|
185
|
+
value
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def option_buffer_size(value)
|
|
189
|
+
value = Integer(value)
|
|
190
|
+
|
|
191
|
+
raise TypeError, ":buffer_size must be positive" unless value.positive?
|
|
192
|
+
|
|
193
|
+
value
|
|
182
194
|
end
|
|
183
195
|
|
|
184
196
|
def option_body_threshold_size(value)
|
|
185
|
-
Integer(value)
|
|
197
|
+
bytes = Integer(value)
|
|
198
|
+
raise TypeError, ":body_threshold_size must be positive" unless bytes.positive?
|
|
199
|
+
|
|
200
|
+
bytes
|
|
186
201
|
end
|
|
187
202
|
|
|
188
203
|
def option_transport(value)
|
|
189
204
|
transport = value.to_s
|
|
190
|
-
raise TypeError, "
|
|
205
|
+
raise TypeError, "#{transport} is an unsupported transport type" unless %w[unix].include?(transport)
|
|
191
206
|
|
|
192
207
|
transport
|
|
193
208
|
end
|
|
@@ -204,50 +219,78 @@ module HTTPX
|
|
|
204
219
|
params form json xml body ssl http2_settings
|
|
205
220
|
request_class response_class headers_class request_body_class
|
|
206
221
|
response_body_class connection_class options_class
|
|
207
|
-
io fallback_protocol debug debug_level
|
|
222
|
+
io fallback_protocol debug debug_level resolver_class resolver_options
|
|
223
|
+
compress_request_body decompress_response_body
|
|
208
224
|
persistent
|
|
209
225
|
].each do |method_name|
|
|
210
|
-
|
|
226
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
|
227
|
+
def option_#{method_name}(v); v; end # def option_smth(v); v; end
|
|
228
|
+
OUT
|
|
211
229
|
end
|
|
212
230
|
|
|
213
|
-
|
|
214
|
-
private_constant :REQUEST_IVARS
|
|
231
|
+
REQUEST_BODY_IVARS = %i[@headers @params @form @xml @json @body].freeze
|
|
215
232
|
|
|
216
233
|
def ==(other)
|
|
217
|
-
|
|
234
|
+
super || options_equals?(other)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
|
|
238
|
+
# headers and other request options do not play a role, as they are
|
|
239
|
+
# relevant only for the request.
|
|
240
|
+
ivars = instance_variables - ignore_ivars
|
|
241
|
+
other_ivars = other.instance_variables - ignore_ivars
|
|
242
|
+
|
|
243
|
+
return false if ivars.size != other_ivars.size
|
|
244
|
+
|
|
245
|
+
return false if ivars.sort != other_ivars.sort
|
|
246
|
+
|
|
218
247
|
ivars.all? do |ivar|
|
|
219
|
-
|
|
220
|
-
when :@headers
|
|
221
|
-
# currently, this is used to pick up an available matching connection.
|
|
222
|
-
# the headers do not play a role, as they are relevant only for the request.
|
|
223
|
-
true
|
|
224
|
-
when *REQUEST_IVARS
|
|
225
|
-
true
|
|
226
|
-
else
|
|
227
|
-
instance_variable_get(ivar) == other.instance_variable_get(ivar)
|
|
228
|
-
end
|
|
248
|
+
instance_variable_get(ivar) == other.instance_variable_get(ivar)
|
|
229
249
|
end
|
|
230
250
|
end
|
|
231
251
|
|
|
252
|
+
OTHER_LOOKUP = ->(obj, k, ivar_map) {
|
|
253
|
+
case obj
|
|
254
|
+
when Hash
|
|
255
|
+
obj[ivar_map[k]]
|
|
256
|
+
else
|
|
257
|
+
obj.instance_variable_get(k)
|
|
258
|
+
end
|
|
259
|
+
}
|
|
232
260
|
def merge(other)
|
|
233
|
-
|
|
261
|
+
ivar_map = nil
|
|
262
|
+
other_ivars = case other
|
|
263
|
+
when Hash
|
|
264
|
+
ivar_map = other.keys.to_h { |k| [:"@#{k}", k] }
|
|
265
|
+
ivar_map.keys
|
|
266
|
+
else
|
|
267
|
+
other.instance_variables
|
|
268
|
+
end
|
|
234
269
|
|
|
235
|
-
|
|
236
|
-
return self if h2.empty?
|
|
270
|
+
return self if other_ivars.empty?
|
|
237
271
|
|
|
238
|
-
|
|
272
|
+
return self if other_ivars.all? { |ivar| instance_variable_get(ivar) == OTHER_LOOKUP[other, ivar, ivar_map] }
|
|
239
273
|
|
|
240
|
-
|
|
274
|
+
opts = dup
|
|
241
275
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
276
|
+
other_ivars.each do |ivar|
|
|
277
|
+
v = OTHER_LOOKUP[other, ivar, ivar_map]
|
|
278
|
+
|
|
279
|
+
unless v
|
|
280
|
+
opts.instance_variable_set(ivar, v)
|
|
281
|
+
next
|
|
247
282
|
end
|
|
283
|
+
|
|
284
|
+
v = opts.__send__(:"option_#{ivar[1..-1]}", v)
|
|
285
|
+
|
|
286
|
+
orig_v = instance_variable_get(ivar)
|
|
287
|
+
|
|
288
|
+
v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
|
|
289
|
+
|
|
290
|
+
opts.instance_variable_set(ivar, v)
|
|
248
291
|
end
|
|
249
292
|
|
|
250
|
-
|
|
293
|
+
opts
|
|
251
294
|
end
|
|
252
295
|
|
|
253
296
|
def to_hash
|
|
@@ -256,30 +299,45 @@ module HTTPX
|
|
|
256
299
|
end
|
|
257
300
|
end
|
|
258
301
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
302
|
+
def extend_with_plugin_classes(pl)
|
|
303
|
+
if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
|
|
304
|
+
@request_class = @request_class.dup
|
|
305
|
+
@request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
|
|
306
|
+
@request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
|
|
264
307
|
end
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
value = case value
|
|
270
|
-
when Symbol, Numeric, TrueClass, FalseClass
|
|
271
|
-
value
|
|
272
|
-
else
|
|
273
|
-
value.dup
|
|
274
|
-
end
|
|
275
|
-
instance_variable_set(ivar, value)
|
|
276
|
-
end
|
|
308
|
+
if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
|
|
309
|
+
@response_class = @response_class.dup
|
|
310
|
+
@response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
|
|
311
|
+
@response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
|
|
277
312
|
end
|
|
313
|
+
if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
|
|
314
|
+
@headers_class = @headers_class.dup
|
|
315
|
+
@headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
|
|
316
|
+
@headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
|
|
317
|
+
end
|
|
318
|
+
if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
|
|
319
|
+
@request_body_class = @request_body_class.dup
|
|
320
|
+
@request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
|
|
321
|
+
@request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
|
|
322
|
+
end
|
|
323
|
+
if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
|
|
324
|
+
@response_body_class = @response_body_class.dup
|
|
325
|
+
@response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
|
|
326
|
+
@response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
|
|
327
|
+
end
|
|
328
|
+
if defined?(pl::ConnectionMethods)
|
|
329
|
+
@connection_class = @connection_class.dup
|
|
330
|
+
@connection_class.__send__(:include, pl::ConnectionMethods)
|
|
331
|
+
end
|
|
332
|
+
return unless defined?(pl::OptionsMethods)
|
|
333
|
+
|
|
334
|
+
@options_class = @options_class.dup
|
|
335
|
+
@options_class.__send__(:include, pl::OptionsMethods)
|
|
278
336
|
end
|
|
279
337
|
|
|
280
338
|
private
|
|
281
339
|
|
|
282
|
-
def
|
|
340
|
+
def do_initialize(options = {})
|
|
283
341
|
defaults = DEFAULT_OPTIONS.merge(options)
|
|
284
342
|
defaults.each do |k, v|
|
|
285
343
|
next if v.nil?
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "base64"
|
|
3
|
+
require "httpx/base64"
|
|
4
4
|
|
|
5
5
|
module HTTPX
|
|
6
6
|
module Plugins
|
|
@@ -11,10 +11,6 @@ module HTTPX
|
|
|
11
11
|
@password = password
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def can_authenticate?(authenticate)
|
|
15
|
-
authenticate && /Basic .*/.match?(authenticate)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
14
|
def authenticate(*)
|
|
19
15
|
"Basic #{Base64.strict_encode64("#{@user}:#{@password}")}"
|
|
20
16
|
end
|