httpx 0.24.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +0 -48
  3. data/README.md +4 -13
  4. data/doc/release_notes/0_24_4.md +3 -3
  5. data/doc/release_notes/1_0_0.md +60 -0
  6. data/lib/httpx/adapters/datadog.rb +28 -97
  7. data/lib/httpx/adapters/faraday.rb +9 -52
  8. data/lib/httpx/adapters/webmock.rb +2 -7
  9. data/lib/httpx/altsvc.rb +4 -22
  10. data/lib/httpx/base64.rb +27 -0
  11. data/lib/httpx/chainable.rb +0 -23
  12. data/lib/httpx/connection.rb +11 -32
  13. data/lib/httpx/domain_name.rb +5 -12
  14. data/lib/httpx/errors.rb +0 -2
  15. data/lib/httpx/extensions.rb +0 -124
  16. data/lib/httpx/io/ssl.rb +26 -59
  17. data/lib/httpx/io/tcp.rb +27 -68
  18. data/lib/httpx/io/udp.rb +13 -48
  19. data/lib/httpx/io/unix.rb +1 -8
  20. data/lib/httpx/loggable.rb +4 -19
  21. data/lib/httpx/options.rb +24 -84
  22. data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
  23. data/lib/httpx/plugins/{authentication → auth}/digest.rb +2 -5
  24. data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
  25. data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
  26. data/lib/httpx/plugins/auth.rb +25 -0
  27. data/lib/httpx/plugins/aws_sigv4.rb +0 -1
  28. data/lib/httpx/plugins/{basic_authentication.rb → basic_auth.rb} +5 -6
  29. data/lib/httpx/plugins/brotli.rb +50 -0
  30. data/lib/httpx/plugins/circuit_breaker/circuit.rb +40 -16
  31. data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +16 -5
  32. data/lib/httpx/plugins/circuit_breaker.rb +11 -4
  33. data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
  34. data/lib/httpx/plugins/cookies.rb +1 -1
  35. data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +5 -5
  36. data/lib/httpx/plugins/follow_redirects.rb +21 -24
  37. data/lib/httpx/plugins/grpc/grpc_encoding.rb +82 -0
  38. data/lib/httpx/plugins/grpc/message.rb +7 -39
  39. data/lib/httpx/plugins/grpc.rb +15 -21
  40. data/lib/httpx/plugins/h2c.rb +0 -1
  41. data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +5 -5
  42. data/lib/httpx/plugins/oauth.rb +2 -2
  43. data/lib/httpx/plugins/proxy/http.rb +0 -2
  44. data/lib/httpx/plugins/proxy/socks4.rb +0 -4
  45. data/lib/httpx/plugins/proxy/socks5.rb +1 -5
  46. data/lib/httpx/plugins/proxy.rb +3 -32
  47. data/lib/httpx/plugins/retries.rb +3 -4
  48. data/lib/httpx/plugins/stream.rb +4 -6
  49. data/lib/httpx/punycode.rb +9 -291
  50. data/lib/httpx/request/body.rb +145 -0
  51. data/lib/httpx/request.rb +2 -119
  52. data/lib/httpx/resolver/https.rb +1 -1
  53. data/lib/httpx/resolver/native.rb +6 -14
  54. data/lib/httpx/resolver/resolver.rb +1 -1
  55. data/lib/httpx/resolver/system.rb +11 -9
  56. data/lib/httpx/response/body.rb +206 -0
  57. data/lib/httpx/response/buffer.rb +90 -0
  58. data/lib/httpx/response.rb +5 -208
  59. data/lib/httpx/selector.rb +0 -2
  60. data/lib/httpx/session.rb +0 -10
  61. data/lib/httpx/transcoder/body.rb +0 -1
  62. data/lib/httpx/transcoder/deflate.rb +37 -0
  63. data/lib/httpx/transcoder/form.rb +52 -32
  64. data/lib/httpx/transcoder/gzip.rb +74 -0
  65. data/lib/httpx/transcoder/json.rb +2 -4
  66. data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
  67. data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +3 -3
  68. data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
  69. data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
  70. data/lib/httpx/transcoder/multipart.rb +17 -0
  71. data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
  72. data/lib/httpx/transcoder/utils/deflater.rb +72 -0
  73. data/lib/httpx/transcoder/xml.rb +0 -2
  74. data/lib/httpx/transcoder.rb +2 -2
  75. data/lib/httpx/utils.rb +10 -20
  76. data/lib/httpx/version.rb +1 -1
  77. data/lib/httpx.rb +0 -8
  78. data/sig/chainable.rbs +5 -6
  79. data/sig/connection.rbs +0 -1
  80. data/sig/errors.rbs +0 -3
  81. data/sig/httpx.rbs +2 -1
  82. data/sig/io/unix.rbs +1 -1
  83. data/sig/options.rbs +12 -8
  84. data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
  85. data/sig/plugins/auth.rbs +13 -0
  86. data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
  87. data/sig/plugins/brotli.rbs +22 -0
  88. data/sig/plugins/circuit_breaker.rbs +7 -3
  89. data/sig/plugins/compression.rbs +0 -2
  90. data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
  91. data/sig/plugins/follow_redirects.rbs +0 -1
  92. data/sig/plugins/grpc/call.rbs +19 -0
  93. data/sig/plugins/grpc/grpc_encoding.rbs +33 -0
  94. data/sig/plugins/grpc/message.rbs +17 -0
  95. data/sig/plugins/grpc.rbs +2 -32
  96. data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
  97. data/sig/plugins/oauth.rbs +1 -1
  98. data/sig/plugins/proxy/socks4.rbs +2 -3
  99. data/sig/plugins/proxy/socks5.rbs +0 -1
  100. data/sig/plugins/proxy/ssh.rbs +1 -1
  101. data/sig/plugins/response_cache.rbs +5 -2
  102. data/sig/request/body.rbs +42 -0
  103. data/sig/request.rbs +1 -27
  104. data/sig/resolver/resolver.rbs +1 -1
  105. data/sig/response/body.rbs +52 -0
  106. data/sig/response/buffer.rbs +24 -0
  107. data/sig/response.rbs +0 -39
  108. data/sig/transcoder/body.rbs +4 -3
  109. data/sig/transcoder/deflate.rbs +11 -0
  110. data/sig/transcoder/form.rbs +5 -3
  111. data/sig/transcoder/gzip.rbs +24 -0
  112. data/sig/transcoder/json.rbs +4 -2
  113. data/sig/{plugins → transcoder}/multipart.rbs +3 -10
  114. data/sig/transcoder/utils/body_reader.rbs +15 -0
  115. data/sig/transcoder/utils/deflater.rbs +29 -0
  116. data/sig/transcoder.rbs +18 -2
  117. metadata +50 -34
  118. data/lib/httpx/plugins/authentication.rb +0 -24
  119. data/lib/httpx/plugins/compression/brotli.rb +0 -54
  120. data/lib/httpx/plugins/compression/deflate.rb +0 -54
  121. data/lib/httpx/plugins/compression/gzip.rb +0 -90
  122. data/lib/httpx/plugins/compression.rb +0 -165
  123. data/lib/httpx/plugins/multipart/decoder.rb +0 -137
  124. data/lib/httpx/plugins/multipart.rb +0 -96
  125. data/sig/plugins/authentication.rbs +0 -13
  126. data/sig/plugins/compression/brotli.rbs +0 -21
  127. data/sig/plugins/compression/deflate.rbs +0 -17
  128. data/sig/plugins/compression/gzip.rbs +0 -29
  129. /data/sig/plugins/{authentication → auth}/digest.rbs +0 -0
  130. /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
  131. /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ module Transcoder
5
+ module GRPCEncoding
6
+ class Deflater
7
+ extend Forwardable
8
+
9
+ attr_reader :content_type
10
+
11
+ def initialize(body, compressed:)
12
+ @content_type = body.content_type
13
+ @body = BodyReader.new(body)
14
+ @compressed = compressed
15
+ end
16
+
17
+ def bytesize
18
+ return @body.bytesize if @body.respond_to?(:bytesize)
19
+
20
+ Float::INFINITY
21
+ end
22
+
23
+ def read(length = nil, outbuf = nil)
24
+ buf = @body.read(length, outbuf)
25
+
26
+ return unless buf
27
+
28
+ compressed_flag = @compressed ? 1 : 0
29
+
30
+ buf = outbuf if outbuf
31
+
32
+ buf.prepend([compressed_flag, buf.bytesize].pack("CL>"))
33
+ buf
34
+ end
35
+ end
36
+
37
+ class Inflater
38
+ def initialize(response)
39
+ @encodings = response.headers.get("grpc-encoding")
40
+ @response = response
41
+ end
42
+
43
+ def call(message, &blk)
44
+ data = "".b
45
+
46
+ until message.empty?
47
+ compressed, size = message.unpack("CL>")
48
+
49
+ encoded_data = message.byteslice(5..size + 5 - 1)
50
+
51
+ if compressed == 1
52
+ @encodings.reverse_each do |encoding|
53
+ decoder = @response.body.class.initialize_inflater_by_encoding(encoding, @response, bytesize: encoded_data.bytesize)
54
+ encoded_data = decoder.call(encoded_data)
55
+
56
+ blk.call(encoded_data) if blk
57
+
58
+ data << encoded_data
59
+ end
60
+ else
61
+ blk.call(encoded_data) if blk
62
+
63
+ data << encoded_data
64
+ end
65
+
66
+ message = message.byteslice((size + 5)..-1)
67
+ end
68
+
69
+ data
70
+ end
71
+ end
72
+
73
+ def self.encode(*args, **kwargs)
74
+ Deflater.new(*args, **kwargs)
75
+ end
76
+
77
+ def self.decode(response)
78
+ Inflater.new(response)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -12,57 +12,25 @@ module HTTPX
12
12
  # decodes a unary grpc response
13
13
  def unary(response)
14
14
  verify_status(response)
15
- decode(response.to_s, encodings: response.headers.get("grpc-encoding"), encoders: response.encoders)
15
+
16
+ decoder = Transcoder::GRPCEncoding.decode(response)
17
+
18
+ decoder.call(response.to_s)
16
19
  end
17
20
 
18
21
  # lazy decodes a grpc stream response
19
22
  def stream(response, &block)
20
23
  return enum_for(__method__, response) unless block
21
24
 
25
+ decoder = Transcoder::GRPCEncoding.decode(response)
26
+
22
27
  response.each do |frame|
23
- decode(frame, encodings: response.headers.get("grpc-encoding"), encoders: response.encoders, &block)
28
+ decoder.call(frame, &block)
24
29
  end
25
30
 
26
31
  verify_status(response)
27
32
  end
28
33
 
29
- # encodes a single grpc message
30
- def encode(bytes, deflater:)
31
- if deflater
32
- compressed_flag = 1
33
- bytes = deflater.deflate(StringIO.new(bytes))
34
- else
35
- compressed_flag = 0
36
- end
37
-
38
- "".b << [compressed_flag, bytes.bytesize].pack("CL>") << bytes.to_s
39
- end
40
-
41
- # decodes a single grpc message
42
- def decode(message, encodings:, encoders:)
43
- until message.empty?
44
-
45
- compressed, size = message.unpack("CL>")
46
-
47
- data = message.byteslice(5..size + 5 - 1)
48
- if compressed == 1
49
- encodings.reverse_each do |algo|
50
- next unless encoders.key?(algo)
51
-
52
- inflater = encoders[algo].inflater(size)
53
- data = inflater.inflate(data)
54
- size = data.bytesize
55
- end
56
- end
57
-
58
- return data unless block_given?
59
-
60
- yield data
61
-
62
- message = message.byteslice((size + 5)..-1)
63
- end
64
- end
65
-
66
34
  def cancel(request)
67
35
  request.emit(:refuse, :client_cancellation)
68
36
  end
@@ -49,20 +49,19 @@ module HTTPX
49
49
  class << self
50
50
  def load_dependencies(*)
51
51
  require "stringio"
52
+ require "httpx/plugins/grpc/grpc_encoding"
52
53
  require "httpx/plugins/grpc/message"
53
54
  require "httpx/plugins/grpc/call"
54
55
  end
55
56
 
56
57
  def configure(klass)
57
58
  klass.plugin(:persistent)
58
- klass.plugin(:compression)
59
59
  klass.plugin(:stream)
60
60
  end
61
61
 
62
62
  def extra_options(options)
63
63
  options.merge(
64
64
  fallback_protocol: "h2",
65
- http2_settings: { wait_for_handshake: false },
66
65
  grpc_rpcs: {}.freeze,
67
66
  grpc_compression: false,
68
67
  grpc_deadline: DEADLINE
@@ -108,9 +107,18 @@ module HTTPX
108
107
  @trailing_metadata = Hash[trailers]
109
108
  super
110
109
  end
110
+ end
111
+
112
+ module RequestBodyMethods
113
+ def initialize(headers, _)
114
+ super
111
115
 
112
- def encoders
113
- @options.encodings
116
+ if (compression = headers["grpc-encoding"])
117
+ deflater_body = self.class.initialize_deflater_body(@body, compression)
118
+ @body = Transcoder::GRPCEncoding.encode(deflater_body || @body, compressed: !deflater_body.nil?)
119
+ else
120
+ @body = Transcoder::GRPCEncoding.encode(@body, compressed: false)
121
+ end
114
122
  end
115
123
  end
116
124
 
@@ -233,7 +241,7 @@ module HTTPX
233
241
  uri.path = rpc_method
234
242
 
235
243
  headers = HEADERS.merge(
236
- "grpc-accept-encoding" => ["identity", *@options.encodings.keys]
244
+ "grpc-accept-encoding" => ["identity", *@options.supported_compression_formats]
237
245
  )
238
246
  unless deadline == Float::INFINITY
239
247
  # convert to milliseconds
@@ -244,27 +252,13 @@ module HTTPX
244
252
  headers = headers.merge(metadata) if metadata
245
253
 
246
254
  # prepare compressor
247
- deflater = nil
248
255
  compression = @options.grpc_compression == true ? "gzip" : @options.grpc_compression
249
256
 
250
- if compression
251
- headers["grpc-encoding"] = compression
252
- deflater = @options.encodings[compression].deflater if @options.encodings.key?(compression)
253
- end
257
+ headers["grpc-encoding"] = compression if compression
254
258
 
255
259
  headers.merge!(@options.call_credentials.call) if @options.call_credentials
256
260
 
257
- body = if input.respond_to?(:each)
258
- Enumerator.new do |y|
259
- input.each do |message|
260
- y << Message.encode(message, deflater: deflater)
261
- end
262
- end
263
- else
264
- Message.encode(input, deflater: deflater)
265
- end
266
-
267
- build_request("POST", uri, headers: headers, body: body)
261
+ build_request("POST", uri, headers: headers, body: input)
268
262
  end
269
263
  end
270
264
  end
@@ -13,7 +13,6 @@ module HTTPX
13
13
 
14
14
  class << self
15
15
  def load_dependencies(klass)
16
- require "base64"
17
16
  klass.plugin(:upgrade)
18
17
  end
19
18
 
@@ -3,12 +3,12 @@
3
3
  module HTTPX
4
4
  module Plugins
5
5
  #
6
- # https://gitlab.com/os85/httpx/wikis/Authentication#ntlm-authentication
6
+ # https://gitlab.com/os85/httpx/wikis/Authorization#ntlm-auth
7
7
  #
8
8
  module NTLMAuth
9
9
  class << self
10
10
  def load_dependencies(_klass)
11
- require_relative "authentication/ntlm"
11
+ require_relative "auth/ntlm"
12
12
  end
13
13
 
14
14
  def extra_options(options)
@@ -25,11 +25,11 @@ module HTTPX
25
25
  end
26
26
 
27
27
  module InstanceMethods
28
- def ntlm_authentication(user, password, domain = nil)
28
+ def ntlm_auth(user, password, domain = nil)
29
29
  with(ntlm: Authentication::Ntlm.new(user, password, domain: domain))
30
30
  end
31
31
 
32
- alias_method :ntlm_auth, :ntlm_authentication
32
+ private
33
33
 
34
34
  def send_requests(*requests)
35
35
  requests.flat_map do |request|
@@ -55,6 +55,6 @@ module HTTPX
55
55
  end
56
56
  end
57
57
  end
58
- register_plugin :ntlm_authentication, NTLMAuth
58
+ register_plugin :ntlm_auth, NTLMAuth
59
59
  end
60
60
  end
@@ -8,7 +8,7 @@ module HTTPX
8
8
  module OAuth
9
9
  class << self
10
10
  def load_dependencies(_klass)
11
- require_relative "authentication/basic"
11
+ require_relative "auth/basic"
12
12
  end
13
13
  end
14
14
 
@@ -106,7 +106,7 @@ module HTTPX
106
106
  end
107
107
 
108
108
  module InstanceMethods
109
- def oauth_authentication(**args)
109
+ def oauth_auth(**args)
110
110
  with(oauth_session: OAuthSession.new(**args))
111
111
  end
112
112
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "base64"
4
-
5
3
  module HTTPX
6
4
  module Plugins
7
5
  module Proxy
@@ -92,10 +92,6 @@ module HTTPX
92
92
  @options = Options.new(options)
93
93
  end
94
94
 
95
- def timeout
96
- @options.timeout[:operation_timeout]
97
- end
98
-
99
95
  def close; end
100
96
 
101
97
  def consume(*); end
@@ -20,7 +20,7 @@ module HTTPX
20
20
 
21
21
  class << self
22
22
  def load_dependencies(*)
23
- require_relative "../authentication/socks5"
23
+ require_relative "../auth/socks5"
24
24
  end
25
25
 
26
26
  def extra_options(options)
@@ -144,10 +144,6 @@ module HTTPX
144
144
  @options = Options.new(options)
145
145
  end
146
146
 
147
- def timeout
148
- @options.timeout[:operation_timeout]
149
- end
150
-
151
147
  def close; end
152
148
 
153
149
  def consume(*); end
@@ -28,35 +28,6 @@ module HTTPX
28
28
  def extra_options(options)
29
29
  options.merge(supported_proxy_protocols: [])
30
30
  end
31
-
32
- if URI::Generic.methods.include?(:use_proxy?)
33
- def use_proxy?(*args)
34
- URI::Generic.use_proxy?(*args)
35
- end
36
- else
37
- # https://github.com/ruby/uri/blob/ae07f956a4bea00b4f54a75bd40b8fa918103eed/lib/uri/generic.rb
38
- def use_proxy?(hostname, addr, port, no_proxy)
39
- hostname = hostname.downcase
40
- dothostname = ".#{hostname}"
41
- no_proxy.scan(/([^:,\s]+)(?::(\d+))?/) do |p_host, p_port|
42
- if !p_port || port == p_port.to_i
43
- if p_host.start_with?(".")
44
- return false if hostname.end_with?(p_host.downcase)
45
- else
46
- return false if dothostname.end_with?(".#{p_host.downcase}")
47
- end
48
- if addr
49
- begin
50
- return false if IPAddr.new(p_host).include?(addr)
51
- rescue IPAddr::InvalidAddressError
52
- next
53
- end
54
- end
55
- end
56
- end
57
- true
58
- end
59
- end
60
31
  end
61
32
 
62
33
  class Parameters
@@ -82,7 +53,7 @@ module HTTPX
82
53
 
83
54
  auth_scheme = scheme.to_s.capitalize
84
55
 
85
- require_relative "authentication/#{scheme}" unless defined?(Authentication) && Authentication.const_defined?(auth_scheme, false)
56
+ require_relative "auth/#{scheme}" unless defined?(Authentication) && Authentication.const_defined?(auth_scheme, false)
86
57
 
87
58
  @authenticator = Authentication.const_get(auth_scheme).new(@username, @password, **extra)
88
59
  end
@@ -162,8 +133,8 @@ module HTTPX
162
133
  no_proxy = proxy[:no_proxy]
163
134
  no_proxy = no_proxy.join(",") if no_proxy.is_a?(Array)
164
135
 
165
- return super(request, connections, options.merge(proxy: nil)) unless Proxy.use_proxy?(uri.host, next_proxy.host,
166
- next_proxy.port, no_proxy)
136
+ return super(request, connections, options.merge(proxy: nil)) unless URI::Generic.use_proxy?(uri.host, next_proxy.host,
137
+ next_proxy.port, no_proxy)
167
138
  end
168
139
 
169
140
  proxy.merge(uri: next_proxy)
@@ -88,13 +88,12 @@ module HTTPX
88
88
  request.retries.positive? &&
89
89
  __repeatable_request?(request, options) &&
90
90
  (
91
- # rubocop:disable Style/MultilineTernaryOperator
92
- options.retry_on ?
93
- options.retry_on.call(response) :
94
91
  (
95
92
  response.is_a?(ErrorResponse) && __retryable_error?(response.error)
93
+ ) ||
94
+ (
95
+ options.retry_on && options.retry_on.call(response)
96
96
  )
97
- # rubocop:enable Style/MultilineTernaryOperator
98
97
  )
99
98
  __try_partial_retry(request, response)
100
99
  log { "failed to get response, #{request.retries} tries to go..." }
@@ -94,6 +94,10 @@ module HTTPX
94
94
  # https://gitlab.com/honeyryderchuck/httpx/wikis/Stream
95
95
  #
96
96
  module Stream
97
+ def self.extra_options(options)
98
+ options.merge(timeout: { read_timeout: Float::INFINITY, operation_timeout: 60 })
99
+ end
100
+
97
101
  module InstanceMethods
98
102
  def request(*args, stream: false, **options)
99
103
  return super(*args, **options) unless stream
@@ -139,12 +143,6 @@ module HTTPX
139
143
  super
140
144
  end
141
145
  end
142
-
143
- def self.const_missing(const_name)
144
- super unless const_name == :StreamResponse
145
- warn "DEPRECATION WARNING: the class #{self}::StreamResponse is deprecated. Use HTTPX::StreamResponse instead."
146
- HTTPX::StreamResponse
147
- end
148
146
  end
149
147
  register_plugin :stream, Stream
150
148
  end