faraday 1.0.1 → 1.4.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +3 -5
  5. data/examples/client_spec.rb +1 -1
  6. data/lib/faraday.rb +53 -41
  7. data/lib/faraday/adapter.rb +1 -6
  8. data/lib/faraday/adapter/em_http.rb +16 -13
  9. data/lib/faraday/adapter/em_synchrony.rb +16 -13
  10. data/lib/faraday/autoload.rb +1 -4
  11. data/lib/faraday/connection.rb +5 -4
  12. data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
  13. data/lib/faraday/encoders/nested_params_encoder.rb +7 -2
  14. data/lib/faraday/error.rb +20 -0
  15. data/lib/faraday/methods.rb +6 -0
  16. data/lib/faraday/middleware.rb +14 -4
  17. data/lib/faraday/options.rb +4 -8
  18. data/lib/faraday/rack_builder.rb +13 -12
  19. data/lib/faraday/request.rb +20 -10
  20. data/lib/faraday/request/multipart.rb +9 -2
  21. data/lib/faraday/request/retry.rb +2 -2
  22. data/lib/faraday/response.rb +0 -6
  23. data/lib/faraday/response/raise_error.rb +12 -1
  24. data/lib/faraday/utils.rb +2 -2
  25. data/lib/faraday/utils/headers.rb +2 -2
  26. data/lib/faraday/version.rb +5 -0
  27. data/spec/faraday/adapter/test_spec.rb +260 -0
  28. data/spec/faraday/connection_spec.rb +30 -0
  29. data/spec/faraday/error_spec.rb +15 -0
  30. data/spec/faraday/middleware_spec.rb +32 -6
  31. data/spec/faraday/params_encoders/flat_spec.rb +8 -0
  32. data/spec/faraday/params_encoders/nested_spec.rb +8 -0
  33. data/spec/faraday/rack_builder_spec.rb +149 -0
  34. data/spec/faraday/request/authorization_spec.rb +2 -2
  35. data/spec/faraday/request/multipart_spec.rb +41 -13
  36. data/spec/faraday/request/retry_spec.rb +1 -1
  37. data/spec/faraday/request_spec.rb +16 -5
  38. data/spec/faraday/response/raise_error_spec.rb +63 -0
  39. data/spec/support/shared_examples/adapter.rb +2 -1
  40. data/spec/support/shared_examples/request_method.rb +39 -11
  41. metadata +64 -9
  42. data/lib/faraday/adapter/excon.rb +0 -124
  43. data/lib/faraday/adapter/net_http.rb +0 -219
  44. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  45. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # Excon adapter.
6
- class Excon < Faraday::Adapter
7
- dependency 'excon'
8
-
9
- def build_connection(env)
10
- opts = opts_from_env(env)
11
- ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
12
- end
13
-
14
- def call(env)
15
- super
16
-
17
- req_opts = {
18
- method: env[:method].to_s.upcase,
19
- headers: env[:request_headers],
20
- body: read_body(env)
21
- }
22
-
23
- req = env[:request]
24
- if req&.stream_response?
25
- total = 0
26
- req_opts[:response_block] = lambda do |chunk, _remain, _total|
27
- req.on_data.call(chunk, total += chunk.size)
28
- end
29
- end
30
-
31
- resp = connection(env) { |http| http.request(req_opts) }
32
- save_response(env, resp.status.to_i, resp.body, resp.headers,
33
- resp.reason_phrase)
34
-
35
- @app.call(env)
36
- rescue ::Excon::Errors::SocketError => e
37
- raise Faraday::TimeoutError, e if e.message =~ /\btimeout\b/
38
-
39
- raise Faraday::SSLError, e if e.message =~ /\bcertificate\b/
40
-
41
- raise Faraday::ConnectionFailed, e
42
- rescue ::Excon::Errors::Timeout => e
43
- raise Faraday::TimeoutError, e
44
- end
45
-
46
- # TODO: support streaming requests
47
- def read_body(env)
48
- env[:body].respond_to?(:read) ? env[:body].read : env[:body]
49
- end
50
-
51
- private
52
-
53
- def opts_from_env(env)
54
- opts = {}
55
- amend_opts_with_ssl!(opts, env[:ssl]) if needs_ssl_settings?(env)
56
-
57
- if (req = env[:request])
58
- amend_opts_with_timeouts!(opts, req)
59
- amend_opts_with_proxy_settings!(opts, req)
60
- end
61
-
62
- opts
63
- end
64
-
65
- def needs_ssl_settings?(env)
66
- env[:url].scheme == 'https' && env[:ssl]
67
- end
68
-
69
- OPTS_KEYS = [
70
- %i[client_cert client_cert],
71
- %i[client_key client_key],
72
- %i[certificate certificate],
73
- %i[private_key private_key],
74
- %i[ssl_ca_path ca_path],
75
- %i[ssl_ca_file ca_file],
76
- %i[ssl_version version],
77
- %i[ssl_min_version min_version],
78
- %i[ssl_max_version max_version]
79
- ].freeze
80
-
81
- def amend_opts_with_ssl!(opts, ssl)
82
- opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true)
83
- # https://github.com/geemus/excon/issues/106
84
- # https://github.com/jruby/jruby-ossl/issues/19
85
- opts[:nonblock] = false
86
-
87
- OPTS_KEYS.each do |(key_in_opts, key_in_ssl)|
88
- next unless ssl[key_in_ssl]
89
-
90
- opts[key_in_opts] = ssl[key_in_ssl]
91
- end
92
- end
93
-
94
- def amend_opts_with_timeouts!(opts, req)
95
- if (sec = request_timeout(:read, req))
96
- opts[:read_timeout] = sec
97
- end
98
-
99
- if (sec = request_timeout(:write, req))
100
- opts[:write_timeout] = sec
101
- end
102
-
103
- return unless (sec = request_timeout(:open, req))
104
-
105
- opts[:connect_timeout] = sec
106
- end
107
-
108
- def amend_opts_with_proxy_settings!(opts, req)
109
- opts[:proxy] = proxy_settings_for_opts(req[:proxy]) if req[:proxy]
110
- end
111
-
112
- def proxy_settings_for_opts(proxy)
113
- {
114
- host: proxy[:uri].host,
115
- hostname: proxy[:uri].hostname,
116
- port: proxy[:uri].port,
117
- scheme: proxy[:uri].scheme,
118
- user: proxy[:user],
119
- password: proxy[:password]
120
- }
121
- end
122
- end
123
- end
124
- end
@@ -1,219 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- begin
4
- require 'net/https'
5
- rescue LoadError
6
- warn 'Warning: no such file to load -- net/https. ' \
7
- 'Make sure openssl is installed if you want ssl support'
8
- require 'net/http'
9
- end
10
- require 'zlib'
11
-
12
- module Faraday
13
- class Adapter
14
- # Net::HTTP adapter.
15
- class NetHttp < Faraday::Adapter
16
- exceptions = [
17
- IOError,
18
- Errno::EADDRNOTAVAIL,
19
- Errno::ECONNABORTED,
20
- Errno::ECONNREFUSED,
21
- Errno::ECONNRESET,
22
- Errno::EHOSTUNREACH,
23
- Errno::EINVAL,
24
- Errno::ENETUNREACH,
25
- Errno::EPIPE,
26
- Net::HTTPBadResponse,
27
- Net::HTTPHeaderSyntaxError,
28
- Net::ProtocolError,
29
- SocketError,
30
- Zlib::GzipFile::Error
31
- ]
32
-
33
- if defined?(::OpenSSL::SSL::SSLError)
34
- exceptions << ::OpenSSL::SSL::SSLError
35
- end
36
- exceptions << ::Net::OpenTimeout if defined?(::Net::OpenTimeout)
37
-
38
- NET_HTTP_EXCEPTIONS = exceptions.freeze
39
-
40
- def initialize(app = nil, opts = {}, &block)
41
- @ssl_cert_store = nil
42
- super(app, opts, &block)
43
- end
44
-
45
- def build_connection(env)
46
- net_http_connection(env).tap do |http|
47
- if http.respond_to?(:use_ssl=)
48
- http.use_ssl = env[:url].scheme == 'https'
49
- end
50
- configure_ssl(http, env[:ssl])
51
- configure_request(http, env[:request])
52
- end
53
- end
54
-
55
- def net_http_connection(env)
56
- klass = if (proxy = env[:request][:proxy])
57
- Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port,
58
- proxy[:user], proxy[:password])
59
- else
60
- Net::HTTP
61
- end
62
- port = env[:url].port || (env[:url].scheme == 'https' ? 443 : 80)
63
- klass.new(env[:url].hostname, port)
64
- end
65
-
66
- def call(env)
67
- super
68
- http_response = connection(env) do |http|
69
- begin
70
- perform_request(http, env)
71
- rescue *NET_HTTP_EXCEPTIONS => e
72
- if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
73
- raise Faraday::SSLError, e
74
- end
75
-
76
- raise Faraday::ConnectionFailed, e
77
- end
78
- end
79
-
80
- save_response(env, http_response.code.to_i,
81
- http_response.body || +'', nil,
82
- http_response.message) do |response_headers|
83
- http_response.each_header do |key, value|
84
- response_headers[key] = value
85
- end
86
- end
87
-
88
- @app.call env
89
- rescue Timeout::Error, Errno::ETIMEDOUT => e
90
- raise Faraday::TimeoutError, e
91
- end
92
-
93
- private
94
-
95
- def create_request(env)
96
- request = Net::HTTPGenericRequest.new \
97
- env[:method].to_s.upcase, # request method
98
- !!env[:body], # is there request body
99
- env[:method] != :head, # is there response body
100
- env[:url].request_uri, # request uri path
101
- env[:request_headers] # request headers
102
-
103
- if env[:body].respond_to?(:read)
104
- request.body_stream = env[:body]
105
- else
106
- request.body = env[:body]
107
- end
108
- request
109
- end
110
-
111
- def perform_request(http, env)
112
- if env[:request].stream_response?
113
- size = 0
114
- yielded = false
115
- http_response = request_with_wrapped_block(http, env) do |chunk|
116
- if chunk.bytesize.positive? || size.positive?
117
- yielded = true
118
- size += chunk.bytesize
119
- env[:request].on_data.call(chunk, size)
120
- end
121
- end
122
- env[:request].on_data.call(+'', 0) unless yielded
123
- # Net::HTTP returns something,
124
- # but it's not meaningful according to the docs.
125
- http_response.body = nil
126
- http_response
127
- else
128
- request_with_wrapped_block(http, env)
129
- end
130
- end
131
-
132
- def request_with_wrapped_block(http, env, &block)
133
- if (env[:method] == :get) && !env[:body]
134
- # prefer `get` to `request` because the former handles gzip (ruby 1.9)
135
- request_via_get_method(http, env, &block)
136
- else
137
- request_via_request_method(http, env, &block)
138
- end
139
- end
140
-
141
- def request_via_get_method(http, env, &block)
142
- # Must use Net::HTTP#start and pass it a block otherwise the server's
143
- # TCP socket does not close correctly.
144
- http.start do |opened_http|
145
- opened_http.get env[:url].request_uri, env[:request_headers], &block
146
- end
147
- end
148
-
149
- def request_via_request_method(http, env, &block)
150
- # Must use Net::HTTP#start and pass it a block otherwise the server's
151
- # TCP socket does not close correctly.
152
- http.start do |opened_http|
153
- if block_given?
154
- opened_http.request create_request(env) do |response|
155
- response.read_body(&block)
156
- end
157
- else
158
- opened_http.request create_request(env)
159
- end
160
- end
161
- end
162
-
163
- def configure_ssl(http, ssl)
164
- return unless ssl
165
-
166
- http.verify_mode = ssl_verify_mode(ssl)
167
- http.cert_store = ssl_cert_store(ssl)
168
-
169
- http.cert = ssl[:client_cert] if ssl[:client_cert]
170
- http.key = ssl[:client_key] if ssl[:client_key]
171
- http.ca_file = ssl[:ca_file] if ssl[:ca_file]
172
- http.ca_path = ssl[:ca_path] if ssl[:ca_path]
173
- http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
174
- http.ssl_version = ssl[:version] if ssl[:version]
175
- http.min_version = ssl[:min_version] if ssl[:min_version]
176
- http.max_version = ssl[:max_version] if ssl[:max_version]
177
- end
178
-
179
- def configure_request(http, req)
180
- if (sec = request_timeout(:read, req))
181
- http.read_timeout = sec
182
- end
183
-
184
- if (sec = http.respond_to?(:write_timeout=) &&
185
- request_timeout(:write, req))
186
- http.write_timeout = sec
187
- end
188
-
189
- if (sec = request_timeout(:open, req))
190
- http.open_timeout = sec
191
- end
192
-
193
- # Only set if Net::Http supports it, since Ruby 2.5.
194
- http.max_retries = 0 if http.respond_to?(:max_retries=)
195
-
196
- @config_block&.call(http)
197
- end
198
-
199
- def ssl_cert_store(ssl)
200
- return ssl[:cert_store] if ssl[:cert_store]
201
-
202
- @ssl_cert_store ||= begin
203
- # Use the default cert store by default, i.e. system ca certs
204
- OpenSSL::X509::Store.new.tap(&:set_default_paths)
205
- end
206
- end
207
-
208
- def ssl_verify_mode(ssl)
209
- ssl[:verify_mode] || begin
210
- if ssl.fetch(:verify, true)
211
- OpenSSL::SSL::VERIFY_PEER
212
- else
213
- OpenSSL::SSL::VERIFY_NONE
214
- end
215
- end
216
- end
217
- end
218
- end
219
- end
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # Net::HTTP::Persistent adapter.
6
- class NetHttpPersistent < NetHttp
7
- dependency 'net/http/persistent'
8
-
9
- private
10
-
11
- def net_http_connection(env)
12
- @cached_connection ||=
13
- if Net::HTTP::Persistent.instance_method(:initialize)
14
- .parameters.first == %i[key name]
15
- options = { name: 'Faraday' }
16
- if @connection_options.key?(:pool_size)
17
- options[:pool_size] = @connection_options[:pool_size]
18
- end
19
- Net::HTTP::Persistent.new(**options)
20
- else
21
- Net::HTTP::Persistent.new('Faraday')
22
- end
23
-
24
- proxy_uri = proxy_uri(env)
25
- if @cached_connection.proxy_uri != proxy_uri
26
- @cached_connection.proxy = proxy_uri
27
- end
28
- @cached_connection
29
- end
30
-
31
- def proxy_uri(env)
32
- proxy_uri = nil
33
- if (proxy = env[:request][:proxy])
34
- proxy_uri = if proxy[:uri].is_a?(::URI::HTTP)
35
- proxy[:uri].dup
36
- else
37
- ::URI.parse(proxy[:uri].to_s)
38
- end
39
- proxy_uri.user = proxy_uri.password = nil
40
- # awful patch for net-http-persistent 2.8
41
- # not unescaping user/password
42
- if proxy[:user]
43
- (class << proxy_uri; self; end).class_eval do
44
- define_method(:user) { proxy[:user] }
45
- define_method(:password) { proxy[:password] }
46
- end
47
- end
48
- end
49
- proxy_uri
50
- end
51
-
52
- def perform_request(http, env)
53
- http.request env[:url], create_request(env)
54
- rescue Errno::ETIMEDOUT => e
55
- raise Faraday::TimeoutError, e
56
- rescue Net::HTTP::Persistent::Error => e
57
- raise Faraday::TimeoutError, e if e.message.include? 'Timeout'
58
-
59
- if e.message.include? 'connection refused'
60
- raise Faraday::ConnectionFailed, e
61
- end
62
-
63
- raise
64
- end
65
-
66
- SSL_CONFIGURATIONS = {
67
- certificate: :client_cert,
68
- private_key: :client_key,
69
- ca_file: :ca_file,
70
- ssl_version: :version,
71
- min_version: :min_version,
72
- max_version: :max_version
73
- }.freeze
74
-
75
- def configure_ssl(http, ssl)
76
- return unless ssl
77
-
78
- http_set(http, :verify_mode, ssl_verify_mode(ssl))
79
- http_set(http, :cert_store, ssl_cert_store(ssl))
80
-
81
- SSL_CONFIGURATIONS
82
- .select { |_, key| ssl[key] }
83
- .each { |target, key| http_set(http, target, ssl[key]) }
84
- end
85
-
86
- def http_set(http, attr, value)
87
- http.send("#{attr}=", value) if http.send(attr) != value
88
- end
89
- end
90
- end
91
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Faraday::Adapter::NetHttpPersistent do
4
- features :request_body_on_query_methods, :reason_phrase_parse, :compression, :trace_method
5
-
6
- it_behaves_like 'an adapter'
7
-
8
- it 'allows to provide adapter specific configs' do
9
- url = URI('https://example.com')
10
-
11
- adapter = described_class.new do |http|
12
- http.idle_timeout = 123
13
- end
14
-
15
- http = adapter.send(:connection, url: url, request: {})
16
- adapter.send(:configure_request, http, {})
17
-
18
- expect(http.idle_timeout).to eq(123)
19
- end
20
-
21
- it 'sets max_retries to 0' do
22
- url = URI('http://example.com')
23
-
24
- adapter = described_class.new
25
-
26
- http = adapter.send(:connection, url: url, request: {})
27
- adapter.send(:configure_request, http, {})
28
-
29
- # `max_retries=` is only present in Ruby 2.5
30
- expect(http.max_retries).to eq(0) if http.respond_to?(:max_retries=)
31
- end
32
-
33
- it 'allows to set pool_size on initialize' do
34
- url = URI('https://example.com')
35
-
36
- adapter = described_class.new(nil, pool_size: 5)
37
-
38
- http = adapter.send(:connection, url: url, request: {})
39
-
40
- # `pool` is only present in net_http_persistent >= 3.0
41
- expect(http.pool.size).to eq(5) if http.respond_to?(:pool)
42
- end
43
-
44
- context 'min_version' do
45
- it 'allows to set min_version in SSL settings' do
46
- url = URI('https://example.com')
47
-
48
- adapter = described_class.new(nil)
49
-
50
- http = adapter.send(:connection, url: url, request: {})
51
- adapter.send(:configure_ssl, http, min_version: :TLS1_2)
52
-
53
- # `min_version` is only present in net_http_persistent >= 3.1 (UNRELEASED)
54
- expect(http.min_version).to eq(:TLS1_2) if http.respond_to?(:min_version)
55
- end
56
- end
57
- end