faraday 0.9.2 → 1.0.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 (103) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +276 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +27 -217
  5. data/Rakefile +7 -0
  6. data/UPGRADING.md +55 -0
  7. data/examples/client_spec.rb +65 -0
  8. data/examples/client_test.rb +79 -0
  9. data/lib/faraday/adapter/em_http.rb +149 -101
  10. data/lib/faraday/adapter/em_http_ssl_patch.rb +25 -19
  11. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  12. data/lib/faraday/adapter/em_synchrony.rb +106 -56
  13. data/lib/faraday/adapter/excon.rb +98 -55
  14. data/lib/faraday/adapter/httpclient.rb +89 -55
  15. data/lib/faraday/adapter/net_http.rb +132 -53
  16. data/lib/faraday/adapter/net_http_persistent.rb +70 -28
  17. data/lib/faraday/adapter/patron.rb +92 -38
  18. data/lib/faraday/adapter/rack.rb +30 -13
  19. data/lib/faraday/adapter/test.rb +136 -52
  20. data/lib/faraday/adapter/typhoeus.rb +7 -115
  21. data/lib/faraday/adapter.rb +89 -20
  22. data/lib/faraday/adapter_registry.rb +28 -0
  23. data/lib/faraday/autoload.rb +47 -36
  24. data/lib/faraday/connection.rb +345 -168
  25. data/lib/faraday/dependency_loader.rb +37 -0
  26. data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
  27. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  28. data/lib/faraday/error.rb +108 -29
  29. data/lib/faraday/file_part.rb +128 -0
  30. data/lib/faraday/logging/formatter.rb +105 -0
  31. data/lib/faraday/middleware.rb +12 -28
  32. data/lib/faraday/middleware_registry.rb +129 -0
  33. data/lib/faraday/options/connection_options.rb +22 -0
  34. data/lib/faraday/options/env.rb +181 -0
  35. data/lib/faraday/options/proxy_options.rb +28 -0
  36. data/lib/faraday/options/request_options.rb +22 -0
  37. data/lib/faraday/options/ssl_options.rb +59 -0
  38. data/lib/faraday/options.rb +57 -194
  39. data/lib/faraday/param_part.rb +53 -0
  40. data/lib/faraday/parameters.rb +4 -196
  41. data/lib/faraday/rack_builder.rb +74 -39
  42. data/lib/faraday/request/authorization.rb +42 -31
  43. data/lib/faraday/request/basic_authentication.rb +14 -7
  44. data/lib/faraday/request/instrumentation.rb +45 -27
  45. data/lib/faraday/request/multipart.rb +81 -45
  46. data/lib/faraday/request/retry.rb +211 -126
  47. data/lib/faraday/request/token_authentication.rb +15 -10
  48. data/lib/faraday/request/url_encoded.rb +41 -23
  49. data/lib/faraday/request.rb +84 -30
  50. data/lib/faraday/response/logger.rb +22 -48
  51. data/lib/faraday/response/raise_error.rb +38 -14
  52. data/lib/faraday/response.rb +27 -16
  53. data/lib/faraday/utils/headers.rb +139 -0
  54. data/lib/faraday/utils/params_hash.rb +61 -0
  55. data/lib/faraday/utils.rb +28 -228
  56. data/lib/faraday.rb +102 -204
  57. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  58. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  59. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  60. data/spec/faraday/adapter/excon_spec.rb +49 -0
  61. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  62. data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
  63. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  64. data/spec/faraday/adapter/patron_spec.rb +18 -0
  65. data/spec/faraday/adapter/rack_spec.rb +8 -0
  66. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  67. data/spec/faraday/adapter_registry_spec.rb +28 -0
  68. data/spec/faraday/adapter_spec.rb +55 -0
  69. data/spec/faraday/composite_read_io_spec.rb +80 -0
  70. data/spec/faraday/connection_spec.rb +691 -0
  71. data/spec/faraday/error_spec.rb +45 -0
  72. data/spec/faraday/middleware_spec.rb +26 -0
  73. data/spec/faraday/options/env_spec.rb +70 -0
  74. data/spec/faraday/options/options_spec.rb +297 -0
  75. data/spec/faraday/options/proxy_options_spec.rb +37 -0
  76. data/spec/faraday/options/request_options_spec.rb +19 -0
  77. data/spec/faraday/params_encoders/flat_spec.rb +34 -0
  78. data/spec/faraday/params_encoders/nested_spec.rb +134 -0
  79. data/spec/faraday/rack_builder_spec.rb +196 -0
  80. data/spec/faraday/request/authorization_spec.rb +88 -0
  81. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  82. data/spec/faraday/request/multipart_spec.rb +274 -0
  83. data/spec/faraday/request/retry_spec.rb +242 -0
  84. data/spec/faraday/request/url_encoded_spec.rb +70 -0
  85. data/spec/faraday/request_spec.rb +109 -0
  86. data/spec/faraday/response/logger_spec.rb +220 -0
  87. data/spec/faraday/response/middleware_spec.rb +52 -0
  88. data/spec/faraday/response/raise_error_spec.rb +106 -0
  89. data/spec/faraday/response_spec.rb +75 -0
  90. data/spec/faraday/utils/headers_spec.rb +82 -0
  91. data/spec/faraday/utils_spec.rb +56 -0
  92. data/spec/faraday_spec.rb +37 -0
  93. data/spec/spec_helper.rb +132 -0
  94. data/spec/support/disabling_stub.rb +14 -0
  95. data/spec/support/fake_safe_buffer.rb +15 -0
  96. data/spec/support/helper_methods.rb +133 -0
  97. data/spec/support/shared_examples/adapter.rb +104 -0
  98. data/spec/support/shared_examples/params_encoder.rb +18 -0
  99. data/spec/support/shared_examples/request_method.rb +234 -0
  100. data/spec/support/streaming_response_checker.rb +35 -0
  101. data/spec/support/webmock_rack_app.rb +68 -0
  102. metadata +110 -64
  103. data/lib/faraday/upload_io.rb +0 -67
@@ -1,70 +1,102 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'net/https'
3
5
  rescue LoadError
4
- warn "Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support"
6
+ warn 'Warning: no such file to load -- net/https. ' \
7
+ 'Make sure openssl is installed if you want ssl support'
5
8
  require 'net/http'
6
9
  end
7
10
  require 'zlib'
8
11
 
9
12
  module Faraday
10
13
  class Adapter
14
+ # Net::HTTP adapter.
11
15
  class NetHttp < Faraday::Adapter
12
- NET_HTTP_EXCEPTIONS = [
13
- EOFError,
16
+ exceptions = [
17
+ IOError,
18
+ Errno::EADDRNOTAVAIL,
14
19
  Errno::ECONNABORTED,
15
20
  Errno::ECONNREFUSED,
16
21
  Errno::ECONNRESET,
17
22
  Errno::EHOSTUNREACH,
18
23
  Errno::EINVAL,
19
24
  Errno::ENETUNREACH,
25
+ Errno::EPIPE,
20
26
  Net::HTTPBadResponse,
21
27
  Net::HTTPHeaderSyntaxError,
22
28
  Net::ProtocolError,
23
29
  SocketError,
24
- Zlib::GzipFile::Error,
30
+ Zlib::GzipFile::Error
25
31
  ]
26
32
 
27
- NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
28
- NET_HTTP_EXCEPTIONS << Net::OpenTimeout if defined?(Net::OpenTimeout)
33
+ exceptions << OpenSSL::SSL::SSLError if defined?(OpenSSL)
34
+ exceptions << Net::OpenTimeout if defined?(Net::OpenTimeout)
29
35
 
30
- def call(env)
31
- super
32
- with_net_http_connection(env) do |http|
33
- configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
36
+ NET_HTTP_EXCEPTIONS = exceptions.freeze
34
37
 
35
- req = env[:request]
36
- http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
37
- http.open_timeout = req[:open_timeout] if req[:open_timeout]
38
+ def initialize(app = nil, opts = {}, &block)
39
+ @ssl_cert_store = nil
40
+ super(app, opts, &block)
41
+ end
42
+
43
+ def build_connection(env)
44
+ net_http_connection(env).tap do |http|
45
+ if http.respond_to?(:use_ssl=)
46
+ http.use_ssl = env[:url].scheme == 'https'
47
+ end
48
+ configure_ssl(http, env[:ssl])
49
+ configure_request(http, env[:request])
50
+ end
51
+ end
52
+
53
+ def net_http_connection(env)
54
+ klass = if (proxy = env[:request][:proxy])
55
+ Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port,
56
+ proxy[:user], proxy[:password])
57
+ else
58
+ Net::HTTP
59
+ end
60
+ port = env[:url].port || (env[:url].scheme == 'https' ? 443 : 80)
61
+ klass.new(env[:url].hostname, port)
62
+ end
38
63
 
64
+ def call(env)
65
+ super
66
+ http_response = connection(env) do |http|
39
67
  begin
40
- http_response = perform_request(http, env)
41
- rescue *NET_HTTP_EXCEPTIONS => err
42
- if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
43
- raise Faraday::SSLError, err
44
- else
45
- raise Error::ConnectionFailed, err
68
+ perform_request(http, env)
69
+ rescue *NET_HTTP_EXCEPTIONS => e
70
+ if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
71
+ raise Faraday::SSLError, e
46
72
  end
73
+
74
+ raise Faraday::ConnectionFailed, e
47
75
  end
76
+ end
48
77
 
49
- save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers|
50
- http_response.each_header do |key, value|
51
- response_headers[key] = value
52
- end
78
+ save_response(env, http_response.code.to_i,
79
+ http_response.body || +'', nil,
80
+ http_response.message) do |response_headers|
81
+ http_response.each_header do |key, value|
82
+ response_headers[key] = value
53
83
  end
54
84
  end
55
85
 
56
86
  @app.call env
57
- rescue Timeout::Error, Errno::ETIMEDOUT => err
58
- raise Faraday::Error::TimeoutError, err
87
+ rescue Timeout::Error, Errno::ETIMEDOUT => e
88
+ raise Faraday::TimeoutError, e
59
89
  end
60
90
 
91
+ private
92
+
61
93
  def create_request(env)
62
94
  request = Net::HTTPGenericRequest.new \
63
- env[:method].to_s.upcase, # request method
64
- !!env[:body], # is there request body
65
- :head != env[:method], # is there response body
66
- env[:url].request_uri, # request uri path
67
- env[:request_headers] # request headers
95
+ env[:method].to_s.upcase, # request method
96
+ !!env[:body], # is there request body
97
+ env[:method] != :head, # is there response body
98
+ env[:url].request_uri, # request uri path
99
+ env[:request_headers] # request headers
68
100
 
69
101
  if env[:body].respond_to?(:read)
70
102
  request.body_stream = env[:body]
@@ -75,45 +107,92 @@ module Faraday
75
107
  end
76
108
 
77
109
  def perform_request(http, env)
78
- if :get == env[:method] and !env[:body]
110
+ if env[:request].stream_response?
111
+ size = 0
112
+ yielded = false
113
+ http_response = request_with_wrapped_block(http, env) do |chunk|
114
+ if chunk.bytesize.positive? || size.positive?
115
+ yielded = true
116
+ size += chunk.bytesize
117
+ env[:request].on_data.call(chunk, size)
118
+ end
119
+ end
120
+ env[:request].on_data.call(+'', 0) unless yielded
121
+ # Net::HTTP returns something,
122
+ # but it's not meaningful according to the docs.
123
+ http_response.body = nil
124
+ http_response
125
+ else
126
+ request_with_wrapped_block(http, env)
127
+ end
128
+ end
129
+
130
+ def request_with_wrapped_block(http, env, &block)
131
+ if (env[:method] == :get) && !env[:body]
79
132
  # prefer `get` to `request` because the former handles gzip (ruby 1.9)
80
- http.get env[:url].request_uri, env[:request_headers]
133
+ request_via_get_method(http, env, &block)
81
134
  else
82
- http.request create_request(env)
135
+ request_via_request_method(http, env, &block)
83
136
  end
84
137
  end
85
138
 
86
- def with_net_http_connection(env)
87
- yield net_http_connection(env)
139
+ def request_via_get_method(http, env, &block)
140
+ http.get env[:url].request_uri, env[:request_headers], &block
88
141
  end
89
142
 
90
- def net_http_connection(env)
91
- if proxy = env[:request][:proxy]
92
- Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
143
+ def request_via_request_method(http, env, &block)
144
+ if block_given?
145
+ http.request create_request(env) do |response|
146
+ response.read_body(&block)
147
+ end
93
148
  else
94
- Net::HTTP
95
- end.new(env[:url].host, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
149
+ http.request create_request(env)
150
+ end
96
151
  end
97
152
 
98
153
  def configure_ssl(http, ssl)
99
- http.use_ssl = true
100
- http.verify_mode = ssl_verify_mode(ssl)
101
- http.cert_store = ssl_cert_store(ssl)
102
-
103
- http.cert = ssl[:client_cert] if ssl[:client_cert]
104
- http.key = ssl[:client_key] if ssl[:client_key]
105
- http.ca_file = ssl[:ca_file] if ssl[:ca_file]
106
- http.ca_path = ssl[:ca_path] if ssl[:ca_path]
154
+ return unless ssl
155
+
156
+ http.verify_mode = ssl_verify_mode(ssl)
157
+ http.cert_store = ssl_cert_store(ssl)
158
+
159
+ http.cert = ssl[:client_cert] if ssl[:client_cert]
160
+ http.key = ssl[:client_key] if ssl[:client_key]
161
+ http.ca_file = ssl[:ca_file] if ssl[:ca_file]
162
+ http.ca_path = ssl[:ca_path] if ssl[:ca_path]
107
163
  http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
108
- http.ssl_version = ssl[:version] if ssl[:version]
164
+ http.ssl_version = ssl[:version] if ssl[:version]
165
+ http.min_version = ssl[:min_version] if ssl[:min_version]
166
+ http.max_version = ssl[:max_version] if ssl[:max_version]
167
+ end
168
+
169
+ def configure_request(http, req)
170
+ if (sec = request_timeout(:read, req))
171
+ http.read_timeout = sec
172
+ end
173
+
174
+ if (sec = http.respond_to?(:write_timeout=) &&
175
+ request_timeout(:write, req))
176
+ http.write_timeout = sec
177
+ end
178
+
179
+ if (sec = request_timeout(:open, req))
180
+ http.open_timeout = sec
181
+ end
182
+
183
+ # Only set if Net::Http supports it, since Ruby 2.5.
184
+ http.max_retries = 0 if http.respond_to?(:max_retries=)
185
+
186
+ @config_block&.call(http)
109
187
  end
110
188
 
111
189
  def ssl_cert_store(ssl)
112
190
  return ssl[:cert_store] if ssl[:cert_store]
113
- # Use the default cert store by default, i.e. system ca certs
114
- cert_store = OpenSSL::X509::Store.new
115
- cert_store.set_default_paths
116
- cert_store
191
+
192
+ @ssl_cert_store ||= begin
193
+ # Use the default cert store by default, i.e. system ca certs
194
+ OpenSSL::X509::Store.new.tap(&:set_default_paths)
195
+ end
117
196
  end
118
197
 
119
198
  def ssl_verify_mode(ssl)
@@ -1,48 +1,90 @@
1
- # Rely on autoloading instead of explicit require; helps avoid the "already
2
- # initialized constant" warning on Ruby 1.8.7 when NetHttp is refereced below.
3
- # require 'faraday/adapter/net_http'
1
+ # frozen_string_literal: true
4
2
 
5
3
  module Faraday
6
4
  class Adapter
5
+ # Net::HTTP::Persistent adapter.
7
6
  class NetHttpPersistent < NetHttp
8
7
  dependency 'net/http/persistent'
9
8
 
10
- def with_net_http_connection(env)
11
- if proxy = env[:request][:proxy]
12
- proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
13
- proxy_uri.user = proxy_uri.password = nil
14
- # awful patch for net-http-persistent 2.8 not unescaping user/password
15
- (class << proxy_uri; self; end).class_eval do
16
- define_method(:user) { proxy[:user] }
17
- define_method(:password) { proxy[:password] }
18
- end if proxy[:user]
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
19
27
  end
28
+ @cached_connection
29
+ end
20
30
 
21
- yield Net::HTTP::Persistent.new 'Faraday', proxy_uri
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
22
50
  end
23
51
 
24
52
  def perform_request(http, env)
25
53
  http.request env[:url], create_request(env)
26
- rescue Errno::ETIMEDOUT => error
27
- raise Faraday::Error::TimeoutError, error
28
- rescue Net::HTTP::Persistent::Error => error
29
- if error.message.include? 'Timeout'
30
- raise Faraday::Error::TimeoutError, error
31
- elsif error.message.include? 'connection refused'
32
- raise Faraday::Error::ConnectionFailed, error
33
- else
34
- raise
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
35
61
  end
62
+
63
+ raise
36
64
  end
37
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
+
38
75
  def configure_ssl(http, ssl)
39
- http.verify_mode = ssl_verify_mode(ssl)
40
- http.cert_store = ssl_cert_store(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
41
85
 
42
- http.certificate = ssl[:client_cert] if ssl[:client_cert]
43
- http.private_key = ssl[:client_key] if ssl[:client_key]
44
- http.ca_file = ssl[:ca_file] if ssl[:ca_file]
45
- http.ssl_version = ssl[:version] if ssl[:version]
86
+ def http_set(http, attr, value)
87
+ http.send("#{attr}=", value) if http.send(attr) != value
46
88
  end
47
89
  end
48
90
  end
@@ -1,55 +1,66 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
5
+ # Patron adapter.
3
6
  class Patron < Faraday::Adapter
4
7
  dependency 'patron'
5
8
 
6
- def initialize(app, &block)
7
- super(app)
8
- @block = block
9
+ def build_connection(env)
10
+ session = ::Patron::Session.new
11
+ @config_block&.call(session)
12
+ if (env[:url].scheme == 'https') && env[:ssl]
13
+ configure_ssl(session, env[:ssl])
14
+ end
15
+
16
+ if (req = env[:request])
17
+ configure_timeouts(session, req)
18
+ configure_proxy(session, req[:proxy])
19
+ end
20
+
21
+ session
9
22
  end
10
23
 
11
24
  def call(env)
12
25
  super
13
-
14
26
  # TODO: support streaming requests
15
27
  env[:body] = env[:body].read if env[:body].respond_to? :read
16
28
 
17
- session = @session ||= create_session
18
-
19
- if req = env[:request]
20
- session.timeout = session.connect_timeout = req[:timeout] if req[:timeout]
21
- session.connect_timeout = req[:open_timeout] if req[:open_timeout]
22
-
23
- if proxy = req[:proxy]
24
- proxy_uri = proxy[:uri].dup
25
- proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20')
26
- proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20')
27
- session.proxy = proxy_uri.to_s
29
+ response = connection(env) do |session|
30
+ begin
31
+ data = env[:body] ? env[:body].to_s : nil
32
+ session.request(env[:method], env[:url].to_s,
33
+ env[:request_headers], data: data)
34
+ rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
35
+ raise Faraday::ConnectionFailed, $ERROR_INFO
28
36
  end
29
37
  end
30
38
 
31
- response = begin
32
- data = env[:body] ? env[:body].to_s : nil
33
- session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data)
34
- rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
35
- raise Error::ConnectionFailed, $!
39
+ if (req = env[:request]).stream_response?
40
+ warn "Streaming downloads for #{self.class.name} " \
41
+ 'are not yet implemented.'
42
+ req.on_data.call(response.body, response.body.bytesize)
36
43
  end
44
+ # Remove the "HTTP/1.1 200", leaving just the reason phrase
45
+ reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
37
46
 
38
- save_response(env, response.status, response.body, response.headers)
47
+ save_response(env, response.status, response.body,
48
+ response.headers, reason_phrase)
39
49
 
40
50
  @app.call env
41
- rescue ::Patron::TimeoutError => err
42
- if err.message == "Connection time-out"
43
- raise Faraday::Error::ConnectionFailed, err
44
- else
45
- raise Faraday::Error::TimeoutError, err
51
+ rescue ::Patron::TimeoutError => e
52
+ if connection_timed_out_message?(e.message)
53
+ raise Faraday::ConnectionFailed, e
46
54
  end
47
- rescue ::Patron::Error => err
48
- if err.message.include?("code 407")
49
- raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
50
- else
51
- raise Error::ConnectionFailed, err
55
+
56
+ raise Faraday::TimeoutError, e
57
+ rescue ::Patron::Error => e
58
+ if e.message.include?('code 407')
59
+ raise Faraday::ConnectionFailed,
60
+ %(407 "Proxy Authentication Required ")
52
61
  end
62
+
63
+ raise Faraday::ConnectionFailed, e
53
64
  end
54
65
 
55
66
  if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
@@ -61,17 +72,60 @@ module Faraday
61
72
  actions << :options unless actions.include? :options
62
73
  else
63
74
  # Patron 0.4.20 and up
64
- actions << "PATCH" unless actions.include? "PATCH"
65
- actions << "OPTIONS" unless actions.include? "OPTIONS"
75
+ actions << 'PATCH' unless actions.include? 'PATCH'
76
+ actions << 'OPTIONS' unless actions.include? 'OPTIONS'
66
77
  end
67
78
  end
68
79
  end
69
80
 
70
- def create_session
71
- session = ::Patron::Session.new
72
- session.insecure = true
73
- @block.call(session) if @block
74
- session
81
+ def configure_ssl(session, ssl)
82
+ if ssl.fetch(:verify, true)
83
+ session.cacert = ssl[:ca_file]
84
+ else
85
+ session.insecure = true
86
+ end
87
+ end
88
+
89
+ def configure_timeouts(session, req)
90
+ return unless req
91
+
92
+ if (sec = request_timeout(:read, req))
93
+ session.timeout = sec
94
+ end
95
+
96
+ return unless (sec = request_timeout(:open, req))
97
+
98
+ session.connect_timeout = sec
99
+ end
100
+
101
+ def configure_proxy(session, proxy)
102
+ return unless proxy
103
+
104
+ proxy_uri = proxy[:uri].dup
105
+ proxy_uri.user = proxy[:user] &&
106
+ Utils.escape(proxy[:user]).gsub('+', '%20')
107
+ proxy_uri.password = proxy[:password] &&
108
+ Utils.escape(proxy[:password]).gsub('+', '%20')
109
+ session.proxy = proxy_uri.to_s
110
+ end
111
+
112
+ private
113
+
114
+ CURL_TIMEOUT_MESSAGES = [
115
+ 'Connection time-out',
116
+ 'Connection timed out',
117
+ 'Timed out before name resolve',
118
+ 'server connect has timed out',
119
+ 'Resolving timed out',
120
+ 'name lookup timed out',
121
+ 'timed out before SSL',
122
+ 'connect() timed out'
123
+ ].freeze
124
+
125
+ def connection_timed_out_message?(message)
126
+ CURL_TIMEOUT_MESSAGES.any? do |curl_message|
127
+ message.include?(curl_message)
128
+ end
75
129
  end
76
130
  end
77
131
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
3
5
  # Sends requests to a Rack app.
4
6
  #
5
- # Examples
7
+ # @example
6
8
  #
7
9
  # class MyRackApp
8
10
  # def call(env)
@@ -17,7 +19,7 @@ module Faraday
17
19
  dependency 'rack/test'
18
20
 
19
21
  # not prefixed with "HTTP_"
20
- SPECIAL_HEADERS = %w[ CONTENT_LENGTH CONTENT_TYPE ]
22
+ SPECIAL_HEADERS = %w[CONTENT_LENGTH CONTENT_TYPE].freeze
21
23
 
22
24
  def initialize(faraday_app, rack_app)
23
25
  super(faraday_app)
@@ -27,32 +29,47 @@ module Faraday
27
29
 
28
30
  def call(env)
29
31
  super
30
- rack_env = {
31
- :method => env[:method],
32
- :input => env[:body].respond_to?(:read) ? env[:body].read : env[:body],
33
- 'rack.url_scheme' => env[:url].scheme
34
- }
32
+ rack_env = build_rack_env(env)
35
33
 
36
- env[:request_headers].each do |name, value|
34
+ env[:request_headers]&.each do |name, value|
37
35
  name = name.upcase.tr('-', '_')
38
36
  name = "HTTP_#{name}" unless SPECIAL_HEADERS.include? name
39
37
  rack_env[name] = value
40
- end if env[:request_headers]
38
+ end
41
39
 
42
- timeout = env[:request][:timeout] || env[:request][:open_timeout]
40
+ timeout = request_timeout(:open, env[:request])
41
+ timeout ||= request_timeout(:read, env[:request])
43
42
  response = if timeout
44
- Timer.timeout(timeout, Faraday::Error::TimeoutError) { execute_request(env, rack_env) }
45
- else
46
- execute_request(env, rack_env)
43
+ Timer.timeout(timeout, Faraday::TimeoutError) do
44
+ execute_request(env, rack_env)
45
+ end
46
+ else
47
+ execute_request(env, rack_env)
48
+ end
49
+
50
+ if (req = env[:request]).stream_response?
51
+ warn "Streaming downloads for #{self.class.name} " \
52
+ 'are not yet implemented.'
53
+ req.on_data.call(response.body, response.body.bytesize)
47
54
  end
48
55
 
49
56
  save_response(env, response.status, response.body, response.headers)
50
57
  @app.call env
51
58
  end
52
59
 
60
+ private
61
+
53
62
  def execute_request(env, rack_env)
54
63
  @session.request(env[:url].to_s, rack_env)
55
64
  end
65
+
66
+ def build_rack_env(env)
67
+ {
68
+ method: env[:method],
69
+ input: env[:body].respond_to?(:read) ? env[:body].read : env[:body],
70
+ 'rack.url_scheme' => env[:url].scheme
71
+ }
72
+ end
56
73
  end
57
74
  end
58
75
  end