httpx 0.13.2 → 0.14.0

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/0_10_1.md +1 -1
  3. data/doc/release_notes/0_13_0.md +2 -2
  4. data/doc/release_notes/0_13_1.md +1 -1
  5. data/doc/release_notes/0_14_0.md +79 -0
  6. data/lib/httpx.rb +1 -2
  7. data/lib/httpx/callbacks.rb +12 -3
  8. data/lib/httpx/connection.rb +12 -9
  9. data/lib/httpx/connection/http1.rb +26 -11
  10. data/lib/httpx/connection/http2.rb +52 -8
  11. data/lib/httpx/headers.rb +1 -1
  12. data/lib/httpx/io/tcp.rb +1 -1
  13. data/lib/httpx/options.rb +91 -56
  14. data/lib/httpx/plugins/aws_sdk_authentication.rb +5 -2
  15. data/lib/httpx/plugins/aws_sigv4.rb +4 -4
  16. data/lib/httpx/plugins/basic_authentication.rb +8 -3
  17. data/lib/httpx/plugins/compression.rb +8 -8
  18. data/lib/httpx/plugins/compression/brotli.rb +4 -3
  19. data/lib/httpx/plugins/compression/deflate.rb +4 -3
  20. data/lib/httpx/plugins/compression/gzip.rb +2 -1
  21. data/lib/httpx/plugins/cookies.rb +3 -7
  22. data/lib/httpx/plugins/digest_authentication.rb +4 -4
  23. data/lib/httpx/plugins/expect.rb +6 -6
  24. data/lib/httpx/plugins/follow_redirects.rb +3 -3
  25. data/lib/httpx/plugins/grpc.rb +247 -0
  26. data/lib/httpx/plugins/grpc/call.rb +62 -0
  27. data/lib/httpx/plugins/grpc/message.rb +85 -0
  28. data/lib/httpx/plugins/multipart/part.rb +1 -1
  29. data/lib/httpx/plugins/proxy.rb +3 -7
  30. data/lib/httpx/plugins/proxy/ssh.rb +3 -3
  31. data/lib/httpx/plugins/rate_limiter.rb +1 -1
  32. data/lib/httpx/plugins/retries.rb +13 -14
  33. data/lib/httpx/plugins/stream.rb +96 -74
  34. data/lib/httpx/plugins/upgrade.rb +4 -4
  35. data/lib/httpx/request.rb +25 -2
  36. data/lib/httpx/response.rb +4 -0
  37. data/lib/httpx/session.rb +17 -7
  38. data/lib/httpx/transcoder/chunker.rb +1 -1
  39. data/lib/httpx/version.rb +1 -1
  40. data/sig/callbacks.rbs +2 -0
  41. data/sig/connection/http1.rbs +4 -0
  42. data/sig/connection/http2.rbs +5 -1
  43. data/sig/options.rbs +9 -2
  44. data/sig/plugins/aws_sdk_authentication.rbs +2 -0
  45. data/sig/plugins/basic_authentication.rbs +2 -0
  46. data/sig/plugins/compression.rbs +2 -2
  47. data/sig/plugins/stream.rbs +17 -16
  48. data/sig/request.rbs +7 -2
  49. data/sig/response.rbs +1 -0
  50. data/sig/session.rbs +4 -0
  51. metadata +38 -35
  52. data/lib/httpx/timeout.rb +0 -67
  53. data/sig/timeout.rbs +0 -29
data/lib/httpx/headers.rb CHANGED
@@ -112,7 +112,7 @@ module HTTPX
112
112
  end
113
113
 
114
114
  def ==(other)
115
- to_hash == Headers.new(other).to_hash
115
+ other == to_hash
116
116
  end
117
117
 
118
118
  # the headers store in Hash format
data/lib/httpx/io/tcp.rb CHANGED
@@ -63,7 +63,7 @@ module HTTPX
63
63
  @ip_index -= 1
64
64
  retry
65
65
  rescue Errno::ETIMEDOUT => e
66
- raise ConnectTimeoutError.new(@options.timeout.connect_timeout, e.message) if @ip_index <= 0
66
+ raise ConnectTimeoutError.new(@options.timeout[:connect_timeout], e.message) if @ip_index <= 0
67
67
 
68
68
  @ip_index -= 1
69
69
  retry
data/lib/httpx/options.rb CHANGED
@@ -4,6 +4,37 @@ module HTTPX
4
4
  class Options
5
5
  WINDOW_SIZE = 1 << 14 # 16K
6
6
  MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112 # 112K
7
+ CONNECT_TIMEOUT = 60
8
+ OPERATION_TIMEOUT = 60
9
+ KEEP_ALIVE_TIMEOUT = 20
10
+
11
+ DEFAULT_OPTIONS = {
12
+ :debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
13
+ :debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
14
+ :ssl => {},
15
+ :http2_settings => { settings_enable_push: 0 },
16
+ :fallback_protocol => "http/1.1",
17
+ :timeout => {
18
+ connect_timeout: CONNECT_TIMEOUT,
19
+ operation_timeout: OPERATION_TIMEOUT,
20
+ keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
21
+ },
22
+ :headers => {},
23
+ :window_size => WINDOW_SIZE,
24
+ :body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
25
+ :request_class => Class.new(Request),
26
+ :response_class => Class.new(Response),
27
+ :headers_class => Class.new(Headers),
28
+ :request_body_class => Class.new(Request::Body),
29
+ :response_body_class => Class.new(Response::Body),
30
+ :connection_class => Class.new(Connection),
31
+ :transport => nil,
32
+ :transport_options => nil,
33
+ :addresses => nil,
34
+ :persistent => false,
35
+ :resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
36
+ :resolver_options => { cache: true },
37
+ }.freeze
7
38
 
8
39
  class << self
9
40
  def new(options = {})
@@ -14,10 +45,23 @@ module HTTPX
14
45
  super
15
46
  end
16
47
 
17
- def def_option(name, &interpreter)
48
+ def def_option(name, layout = nil, &interpreter)
18
49
  attr_reader name
19
50
 
20
- if interpreter
51
+ if layout
52
+ class_eval(<<-OUT, __FILE__, __LINE__ + 1)
53
+ def #{name}=(value)
54
+ return if value.nil?
55
+
56
+ value = begin
57
+ #{layout}
58
+ end
59
+
60
+ @#{name} = value
61
+ end
62
+ OUT
63
+
64
+ elsif interpreter
21
65
  define_method(:"#{name}=") do |value|
22
66
  return if value.nil?
23
67
 
@@ -32,80 +76,71 @@ module HTTPX
32
76
  end
33
77
 
34
78
  def initialize(options = {})
35
- defaults = {
36
- :debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
37
- :debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
38
- :ssl => {},
39
- :http2_settings => { settings_enable_push: 0 },
40
- :fallback_protocol => "http/1.1",
41
- :timeout => Timeout.new,
42
- :headers => {},
43
- :window_size => WINDOW_SIZE,
44
- :body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
45
- :request_class => Class.new(Request),
46
- :response_class => Class.new(Response),
47
- :headers_class => Class.new(Headers),
48
- :request_body_class => Class.new(Request::Body),
49
- :response_body_class => Class.new(Response::Body),
50
- :connection_class => Class.new(Connection),
51
- :transport => nil,
52
- :transport_options => nil,
53
- :addresses => nil,
54
- :persistent => false,
55
- :resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
56
- :resolver_options => { cache: true },
57
- }
58
-
59
- defaults.merge!(options)
79
+ defaults = DEFAULT_OPTIONS.merge(options)
60
80
  defaults.each do |(k, v)|
61
81
  next if v.nil?
62
82
 
63
- __send__(:"#{k}=", v)
83
+ begin
84
+ __send__(:"#{k}=", v)
85
+ rescue NoMethodError
86
+ raise Error, "unknown option: #{k}"
87
+ end
64
88
  end
65
89
  end
66
90
 
67
- def_option(:headers) do |headers|
91
+ def_option(:origin, <<-OUT)
92
+ URI(value)
93
+ OUT
94
+
95
+ def_option(:headers, <<-OUT)
68
96
  if self.headers
69
- self.headers.merge(headers)
97
+ self.headers.merge(value)
70
98
  else
71
- Headers.new(headers)
99
+ Headers.new(value)
72
100
  end
73
- end
101
+ OUT
74
102
 
75
- def_option(:timeout) do |opts|
76
- Timeout.new(opts)
77
- end
103
+ def_option(:timeout, <<-OUT)
104
+ timeouts = Hash[value]
105
+
106
+ if timeouts.key?(:loop_timeout)
107
+ warn ":loop_timeout is deprecated, use :operation_timeout instead"
108
+ timeouts[:operation_timeout] = timeouts.delete(:loop_timeout)
109
+ end
78
110
 
79
- def_option(:max_concurrent_requests) do |num|
80
- raise Error, ":max_concurrent_requests must be positive" unless num.positive?
111
+ timeouts
112
+ OUT
81
113
 
82
- num
83
- end
114
+ def_option(:max_concurrent_requests, <<-OUT)
115
+ raise Error, ":max_concurrent_requests must be positive" unless value.positive?
84
116
 
85
- def_option(:max_requests) do |num|
86
- raise Error, ":max_requests must be positive" unless num.positive?
117
+ value
118
+ OUT
87
119
 
88
- num
89
- end
120
+ def_option(:max_requests, <<-OUT)
121
+ raise Error, ":max_requests must be positive" unless value.positive?
90
122
 
91
- def_option(:window_size) do |num|
92
- Integer(num)
93
- end
123
+ value
124
+ OUT
94
125
 
95
- def_option(:body_threshold_size) do |num|
96
- Integer(num)
97
- end
126
+ def_option(:window_size, <<-OUT)
127
+ Integer(value)
128
+ OUT
129
+
130
+ def_option(:body_threshold_size, <<-OUT)
131
+ Integer(value)
132
+ OUT
98
133
 
99
- def_option(:transport) do |tr|
100
- transport = tr.to_s
101
- raise Error, "#{transport} is an unsupported transport type" unless IO.registry.key?(transport)
134
+ def_option(:transport, <<-OUT)
135
+ transport = value.to_s
136
+ raise Error, "\#{transport} is an unsupported transport type" unless IO.registry.key?(transport)
102
137
 
103
138
  transport
104
- end
139
+ OUT
105
140
 
106
- def_option(:addresses) do |addrs|
107
- Array(addrs)
108
- end
141
+ def_option(:addresses, <<-OUT)
142
+ Array(value)
143
+ OUT
109
144
 
110
145
  %w[
111
146
  params form json body ssl http2_settings
@@ -32,9 +32,8 @@ module HTTPX
32
32
  class << self
33
33
  attr_reader :credentials, :region
34
34
 
35
- def load_dependencies(klass)
35
+ def load_dependencies(_klass)
36
36
  require "aws-sdk-core"
37
- klass.plugin(:aws_sigv4)
38
37
 
39
38
  client = Class.new(Seahorse::Client::Base) do
40
39
  @identifier = :httpx
@@ -50,6 +49,10 @@ module HTTPX
50
49
  @region = client.config[:region]
51
50
  end
52
51
 
52
+ def configure(klass)
53
+ klass.plugin(:aws_sigv4)
54
+ end
55
+
53
56
  def extra_options(options)
54
57
  options.merge(max_concurrent_requests: 1)
55
58
  end
@@ -143,10 +143,10 @@ module HTTPX
143
143
  class << self
144
144
  def extra_options(options)
145
145
  Class.new(options.class) do
146
- def_option(:sigv4_signer) do |signer|
147
- signer.is_a?(Signer) ? signer : Signer.new(signer)
148
- end
149
- end.new.merge(options)
146
+ def_option(:sigv4_signer, <<-OUT)
147
+ value.is_a?(#{Signer}) ? value : #{Signer}.new(value)
148
+ OUT
149
+ end.new(options)
150
150
  end
151
151
 
152
152
  def load_dependencies(klass)
@@ -8,9 +8,14 @@ module HTTPX
8
8
  # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#basic-authentication
9
9
  #
10
10
  module BasicAuthentication
11
- def self.load_dependencies(klass)
12
- require "base64"
13
- klass.plugin(:authentication)
11
+ class << self
12
+ def load_dependencies(_klass)
13
+ require "base64"
14
+ end
15
+
16
+ def configure(klass)
17
+ klass.plugin(:authentication)
18
+ end
14
19
  end
15
20
 
16
21
  module InstanceMethods
@@ -25,18 +25,18 @@ module HTTPX
25
25
  end
26
26
 
27
27
  Class.new(options.class) do
28
- def_option(:compression_threshold_size) do |bytes|
29
- bytes = Integer(bytes)
28
+ def_option(:compression_threshold_size, <<-OUT)
29
+ bytes = Integer(value)
30
30
  raise Error, ":expect_threshold_size must be positive" unless bytes.positive?
31
31
 
32
32
  bytes
33
- end
33
+ OUT
34
34
 
35
- def_option(:encodings) do |encs|
36
- raise Error, ":encodings must be a registry" unless encs.respond_to?(:registry)
35
+ def_option(:encodings, <<-OUT)
36
+ raise Error, ":encodings must be a registry" unless value.respond_to?(:registry)
37
37
 
38
- encs
39
- end
38
+ value
39
+ OUT
40
40
  end.new(options).merge(encodings: encodings)
41
41
  end
42
42
  end
@@ -66,7 +66,7 @@ module HTTPX
66
66
 
67
67
  @body = Encoder.new(@body, options.encodings.registry(encoding).deflater)
68
68
  end
69
- @headers["content-length"] = @body.bytesize unless chunked?
69
+ @headers["content-length"] = @body.bytesize unless unbounded_body?
70
70
  end
71
71
  end
72
72
 
@@ -5,12 +5,12 @@ module HTTPX
5
5
  module Compression
6
6
  module Brotli
7
7
  class << self
8
- def load_dependencies(klass)
9
- klass.plugin(:compression)
8
+ def load_dependencies(_klass)
10
9
  require "brotli"
11
10
  end
12
11
 
13
12
  def configure(klass)
13
+ klass.plugin(:compression)
14
14
  klass.default_options.encodings.register "br", self
15
15
  end
16
16
  end
@@ -18,12 +18,13 @@ module HTTPX
18
18
  module Deflater
19
19
  module_function
20
20
 
21
- def deflate(raw, buffer, chunk_size:)
21
+ def deflate(raw, buffer = "".b, chunk_size: 16_384)
22
22
  while (chunk = raw.read(chunk_size))
23
23
  compressed = ::Brotli.deflate(chunk)
24
24
  buffer << compressed
25
25
  yield compressed if block_given?
26
26
  end
27
+ buffer
27
28
  end
28
29
  end
29
30
 
@@ -4,20 +4,20 @@ module HTTPX
4
4
  module Plugins
5
5
  module Compression
6
6
  module Deflate
7
- def self.load_dependencies(klass)
7
+ def self.load_dependencies(_klass)
8
8
  require "stringio"
9
9
  require "zlib"
10
- klass.plugin(:"compression/gzip")
11
10
  end
12
11
 
13
12
  def self.configure(klass)
13
+ klass.plugin(:"compression/gzip")
14
14
  klass.default_options.encodings.register "deflate", self
15
15
  end
16
16
 
17
17
  module Deflater
18
18
  module_function
19
19
 
20
- def deflate(raw, buffer, chunk_size:)
20
+ def deflate(raw, buffer = "".b, chunk_size: 16_384)
21
21
  deflater = Zlib::Deflate.new
22
22
  while (chunk = raw.read(chunk_size))
23
23
  compressed = deflater.deflate(chunk)
@@ -27,6 +27,7 @@ module HTTPX
27
27
  last = deflater.finish
28
28
  buffer << last
29
29
  yield last if block_given?
30
+ buffer
30
31
  ensure
31
32
  deflater.close if deflater
32
33
  end
@@ -19,7 +19,7 @@ module HTTPX
19
19
  @compressed_chunk = "".b
20
20
  end
21
21
 
22
- def deflate(raw, buffer, chunk_size:)
22
+ def deflate(raw, buffer = "".b, chunk_size: 16_384)
23
23
  gzip = Zlib::GzipWriter.new(self)
24
24
 
25
25
  begin
@@ -38,6 +38,7 @@ module HTTPX
38
38
 
39
39
  buffer << compressed
40
40
  yield compressed if block_given?
41
+ buffer
41
42
  end
42
43
 
43
44
  private
@@ -20,13 +20,9 @@ module HTTPX
20
20
 
21
21
  def self.extra_options(options)
22
22
  Class.new(options.class) do
23
- def_option(:cookies) do |cookies|
24
- if cookies.is_a?(Jar)
25
- cookies
26
- else
27
- Jar.new(cookies)
28
- end
29
- end
23
+ def_option(:cookies, <<-OUT)
24
+ value.is_a?(#{Jar}) ? value : #{Jar}.new(value)
25
+ OUT
30
26
  end.new(options)
31
27
  end
32
28
 
@@ -14,11 +14,11 @@ module HTTPX
14
14
 
15
15
  def self.extra_options(options)
16
16
  Class.new(options.class) do
17
- def_option(:digest) do |digest|
18
- raise Error, ":digest must be a Digest" unless digest.is_a?(Digest)
17
+ def_option(:digest, <<-OUT)
18
+ raise Error, ":digest must be a Digest" unless value.is_a?(#{Digest})
19
19
 
20
- digest
21
- end
20
+ value
21
+ OUT
22
22
  end.new(options)
23
23
  end
24
24
 
@@ -16,19 +16,19 @@ module HTTPX
16
16
 
17
17
  def self.extra_options(options)
18
18
  Class.new(options.class) do
19
- def_option(:expect_timeout) do |seconds|
20
- seconds = Integer(seconds)
19
+ def_option(:expect_timeout, <<-OUT)
20
+ seconds = Integer(value)
21
21
  raise Error, ":expect_timeout must be positive" unless seconds.positive?
22
22
 
23
23
  seconds
24
- end
24
+ OUT
25
25
 
26
- def_option(:expect_threshold_size) do |bytes|
27
- bytes = Integer(bytes)
26
+ def_option(:expect_threshold_size, <<-OUT)
27
+ bytes = Integer(value)
28
28
  raise Error, ":expect_threshold_size must be positive" unless bytes.positive?
29
29
 
30
30
  bytes
31
- end
31
+ OUT
32
32
  end.new(options).merge(expect_timeout: EXPECT_TIMEOUT)
33
33
  end
34
34
 
@@ -19,12 +19,12 @@ module HTTPX
19
19
 
20
20
  def self.extra_options(options)
21
21
  Class.new(options.class) do
22
- def_option(:max_redirects) do |num|
23
- num = Integer(num)
22
+ def_option(:max_redirects, <<-OUT)
23
+ num = Integer(value)
24
24
  raise Error, ":max_redirects must be positive" if num.negative?
25
25
 
26
26
  num
27
- end
27
+ OUT
28
28
 
29
29
  def_option(:follow_insecure_redirects)
30
30
  end.new(options)