faraday 0.15.2 → 0.16.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/README.md +19 -345
  4. data/lib/faraday/adapter/em_http.rb +142 -99
  5. data/lib/faraday/adapter/em_http_ssl_patch.rb +23 -17
  6. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  7. data/lib/faraday/adapter/em_synchrony.rb +104 -60
  8. data/lib/faraday/adapter/excon.rb +100 -55
  9. data/lib/faraday/adapter/httpclient.rb +61 -39
  10. data/lib/faraday/adapter/net_http.rb +105 -47
  11. data/lib/faraday/adapter/net_http_persistent.rb +49 -26
  12. data/lib/faraday/adapter/patron.rb +54 -35
  13. data/lib/faraday/adapter/rack.rb +28 -12
  14. data/lib/faraday/adapter/test.rb +86 -53
  15. data/lib/faraday/adapter/typhoeus.rb +4 -1
  16. data/lib/faraday/adapter.rb +36 -22
  17. data/lib/faraday/adapter_registry.rb +28 -0
  18. data/lib/faraday/autoload.rb +47 -36
  19. data/lib/faraday/connection.rb +321 -179
  20. data/lib/faraday/dependency_loader.rb +37 -0
  21. data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
  22. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  23. data/lib/faraday/error.rb +67 -33
  24. data/lib/faraday/file_part.rb +128 -0
  25. data/lib/faraday/logging/formatter.rb +92 -0
  26. data/lib/faraday/middleware.rb +4 -28
  27. data/lib/faraday/middleware_registry.rb +129 -0
  28. data/lib/faraday/options/connection_options.rb +22 -0
  29. data/lib/faraday/options/env.rb +181 -0
  30. data/lib/faraday/options/proxy_options.rb +28 -0
  31. data/lib/faraday/options/request_options.rb +21 -0
  32. data/lib/faraday/options/ssl_options.rb +59 -0
  33. data/lib/faraday/options.rb +35 -186
  34. data/lib/faraday/param_part.rb +53 -0
  35. data/lib/faraday/parameters.rb +4 -197
  36. data/lib/faraday/rack_builder.rb +67 -56
  37. data/lib/faraday/request/authorization.rb +42 -30
  38. data/lib/faraday/request/basic_authentication.rb +14 -7
  39. data/lib/faraday/request/instrumentation.rb +45 -27
  40. data/lib/faraday/request/multipart.rb +79 -48
  41. data/lib/faraday/request/retry.rb +198 -170
  42. data/lib/faraday/request/token_authentication.rb +15 -10
  43. data/lib/faraday/request/url_encoded.rb +41 -23
  44. data/lib/faraday/request.rb +82 -30
  45. data/lib/faraday/response/logger.rb +22 -69
  46. data/lib/faraday/response/raise_error.rb +36 -14
  47. data/lib/faraday/response.rb +23 -16
  48. data/lib/faraday/utils/headers.rb +139 -0
  49. data/lib/faraday/utils/params_hash.rb +61 -0
  50. data/lib/faraday/utils.rb +28 -245
  51. data/lib/faraday.rb +93 -175
  52. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  53. metadata +21 -5
  54. data/lib/faraday/upload_io.rb +0 -67
@@ -1,16 +1,21 @@
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 = [
16
+ exceptions = [
13
17
  IOError,
18
+ Errno::EADDRNOTAVAIL,
14
19
  Errno::ECONNABORTED,
15
20
  Errno::ECONNREFUSED,
16
21
  Errno::ECONNRESET,
@@ -22,34 +27,40 @@ module Faraday
22
27
  Net::HTTPHeaderSyntaxError,
23
28
  Net::ProtocolError,
24
29
  SocketError,
25
- Zlib::GzipFile::Error,
30
+ Zlib::GzipFile::Error
26
31
  ]
27
32
 
28
- NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
29
- 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)
35
+
36
+ NET_HTTP_EXCEPTIONS = exceptions.freeze
30
37
 
31
38
  def initialize(app = nil, opts = {}, &block)
32
- @cert_store = nil
39
+ @ssl_cert_store = nil
33
40
  super(app, opts, &block)
34
41
  end
35
42
 
36
43
  def call(env)
37
44
  super
38
45
  with_net_http_connection(env) do |http|
39
- configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
46
+ if (env[:url].scheme == 'https') && env[:ssl]
47
+ configure_ssl(http, env[:ssl])
48
+ end
40
49
  configure_request(http, env[:request])
41
50
 
42
51
  begin
43
52
  http_response = perform_request(http, env)
44
- rescue *NET_HTTP_EXCEPTIONS => err
45
- if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
46
- raise Faraday::SSLError, err
47
- else
48
- raise Error::ConnectionFailed, err
53
+ rescue *NET_HTTP_EXCEPTIONS => e
54
+ if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
55
+ raise Faraday::SSLError, e
49
56
  end
57
+
58
+ raise Faraday::ConnectionFailed, e
50
59
  end
51
60
 
52
- save_response(env, http_response.code.to_i, http_response.body || '', nil, http_response.message) do |response_headers|
61
+ save_response(env, http_response.code.to_i,
62
+ http_response.body || '', nil,
63
+ http_response.message) do |response_headers|
53
64
  http_response.each_header do |key, value|
54
65
  response_headers[key] = value
55
66
  end
@@ -57,19 +68,19 @@ module Faraday
57
68
  end
58
69
 
59
70
  @app.call env
60
- rescue Timeout::Error, Errno::ETIMEDOUT => err
61
- raise Faraday::Error::TimeoutError, err
71
+ rescue Timeout::Error, Errno::ETIMEDOUT => e
72
+ raise Faraday::TimeoutError, e
62
73
  end
63
74
 
64
75
  private
65
76
 
66
77
  def create_request(env)
67
78
  request = Net::HTTPGenericRequest.new \
68
- env[:method].to_s.upcase, # request method
69
- !!env[:body], # is there request body
70
- :head != env[:method], # is there response body
71
- env[:url].request_uri, # request uri path
72
- env[:request_headers] # request headers
79
+ env[:method].to_s.upcase, # request method
80
+ !!env[:body], # is there request body
81
+ env[:method] != :head, # is there response body
82
+ env[:url].request_uri, # request uri path
83
+ env[:request_headers] # request headers
73
84
 
74
85
  if env[:body].respond_to?(:read)
75
86
  request.body_stream = env[:body]
@@ -80,9 +91,44 @@ module Faraday
80
91
  end
81
92
 
82
93
  def perform_request(http, env)
83
- if :get == env[:method] and !env[:body]
94
+ if env[:request].stream_response?
95
+ size = 0
96
+ yielded = false
97
+ http_response = request_with_wrapped_block(http, env) do |chunk|
98
+ if chunk.bytesize.positive? || size.positive?
99
+ yielded = true
100
+ size += chunk.bytesize
101
+ env[:request].on_data.call(chunk, size)
102
+ end
103
+ end
104
+ env[:request].on_data.call('', 0) unless yielded
105
+ # Net::HTTP returns something,
106
+ # but it's not meaningful according to the docs.
107
+ http_response.body = nil
108
+ http_response
109
+ else
110
+ request_with_wrapped_block(http, env)
111
+ end
112
+ end
113
+
114
+ def request_with_wrapped_block(http, env, &block)
115
+ if (env[:method] == :get) && !env[:body]
84
116
  # prefer `get` to `request` because the former handles gzip (ruby 1.9)
85
- http.get env[:url].request_uri, env[:request_headers]
117
+ request_via_get_method(http, env, &block)
118
+ else
119
+ request_via_request_method(http, env, &block)
120
+ end
121
+ end
122
+
123
+ def request_via_get_method(http, env, &block)
124
+ http.get env[:url].request_uri, env[:request_headers], &block
125
+ end
126
+
127
+ def request_via_request_method(http, env, &block)
128
+ if block_given?
129
+ http.request create_request(env) do |response|
130
+ response.read_body(&block)
131
+ end
86
132
  else
87
133
  http.request create_request(env)
88
134
  end
@@ -93,44 +139,56 @@ module Faraday
93
139
  end
94
140
 
95
141
  def net_http_connection(env)
96
- if proxy = env[:request][:proxy]
97
- Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
98
- else
99
- Net::HTTP
100
- end.new(env[:url].hostname, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
142
+ klass = if (proxy = env[:request][:proxy])
143
+ Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port,
144
+ proxy[:user], proxy[:password])
145
+ else
146
+ Net::HTTP
147
+ end
148
+ port = env[:url].port || (env[:url].scheme == 'https' ? 443 : 80)
149
+ klass.new(env[:url].hostname, port)
101
150
  end
102
151
 
103
152
  def configure_ssl(http, ssl)
104
- http.use_ssl = true
105
- http.verify_mode = ssl_verify_mode(ssl)
106
- http.cert_store = ssl_cert_store(ssl)
107
-
108
- http.cert = ssl[:client_cert] if ssl[:client_cert]
109
- http.key = ssl[:client_key] if ssl[:client_key]
110
- http.ca_file = ssl[:ca_file] if ssl[:ca_file]
111
- http.ca_path = ssl[:ca_path] if ssl[:ca_path]
153
+ http.use_ssl = true
154
+ http.verify_mode = ssl_verify_mode(ssl)
155
+ http.cert_store = ssl_cert_store(ssl)
156
+
157
+ http.cert = ssl[:client_cert] if ssl[:client_cert]
158
+ http.key = ssl[:client_key] if ssl[:client_key]
159
+ http.ca_file = ssl[:ca_file] if ssl[:ca_file]
160
+ http.ca_path = ssl[:ca_path] if ssl[:ca_path]
112
161
  http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
113
- http.ssl_version = ssl[:version] if ssl[:version]
114
- http.min_version = ssl[:min_version] if ssl[:min_version]
115
- http.max_version = ssl[:max_version] if ssl[:max_version]
162
+ http.ssl_version = ssl[:version] if ssl[:version]
163
+ http.min_version = ssl[:min_version] if ssl[:min_version]
164
+ http.max_version = ssl[:max_version] if ssl[:max_version]
116
165
  end
117
166
 
118
167
  def configure_request(http, req)
119
- http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
120
- http.open_timeout = req[:open_timeout] if req[:open_timeout]
168
+ if req[:timeout]
169
+ http.read_timeout = req[:timeout]
170
+ http.open_timeout = req[:timeout]
171
+ if http.respond_to?(:write_timeout=)
172
+ http.write_timeout = req[:timeout]
173
+ end
174
+ end
175
+ http.open_timeout = req[:open_timeout] if req[:open_timeout]
176
+ if req[:write_timeout] && http.respond_to?(:write_timeout=)
177
+ http.write_timeout = req[:write_timeout]
178
+ end
121
179
  # Only set if Net::Http supports it, since Ruby 2.5.
122
- http.max_retries = 0 if http.respond_to?(:max_retries=)
180
+ http.max_retries = 0 if http.respond_to?(:max_retries=)
123
181
 
124
- @config_block.call(http) if @config_block
182
+ @config_block&.call(http)
125
183
  end
126
184
 
127
185
  def ssl_cert_store(ssl)
128
186
  return ssl[:cert_store] if ssl[:cert_store]
129
- return @cert_store if @cert_store
130
- # Use the default cert store by default, i.e. system ca certs
131
- @cert_store = OpenSSL::X509::Store.new
132
- @cert_store.set_default_paths
133
- @cert_store
187
+
188
+ @ssl_cert_store ||= begin
189
+ # Use the default cert store by default, i.e. system ca certs
190
+ OpenSSL::X509::Store.new.tap(&:set_default_paths)
191
+ end
134
192
  end
135
193
 
136
194
  def ssl_verify_mode(ssl)
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
5
+ # Net::HTTP::Persistent adapter.
3
6
  class NetHttpPersistent < NetHttp
4
7
  dependency 'net/http/persistent'
5
8
 
@@ -7,59 +10,79 @@ module Faraday
7
10
 
8
11
  def net_http_connection(env)
9
12
  @cached_connection ||=
10
- if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == [:key, :name]
11
- Net::HTTP::Persistent.new(name: 'Faraday')
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)
12
20
  else
13
21
  Net::HTTP::Persistent.new('Faraday')
14
22
  end
15
23
 
16
24
  proxy_uri = proxy_uri(env)
17
- @cached_connection.proxy = proxy_uri if @cached_connection.proxy_uri != proxy_uri
25
+ if @cached_connection.proxy_uri != proxy_uri
26
+ @cached_connection.proxy = proxy_uri
27
+ end
18
28
  @cached_connection
19
29
  end
20
30
 
21
31
  def proxy_uri(env)
22
32
  proxy_uri = nil
23
33
  if (proxy = env[:request][:proxy])
24
- proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
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
25
39
  proxy_uri.user = proxy_uri.password = nil
26
- # awful patch for net-http-persistent 2.8 not unescaping user/password
27
- (class << proxy_uri; self; end).class_eval do
28
- define_method(:user) { proxy[:user] }
29
- define_method(:password) { proxy[:password] }
30
- end if proxy[:user]
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
31
48
  end
32
49
  proxy_uri
33
50
  end
34
51
 
35
52
  def perform_request(http, env)
36
53
  http.request env[:url], create_request(env)
37
- rescue Errno::ETIMEDOUT => error
38
- raise Faraday::Error::TimeoutError, error
39
- rescue Net::HTTP::Persistent::Error => error
40
- if error.message.include? 'Timeout'
41
- raise Faraday::Error::TimeoutError, error
42
- elsif error.message.include? 'connection refused'
43
- raise Faraday::Error::ConnectionFailed, error
44
- else
45
- 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
46
61
  end
62
+
63
+ raise
47
64
  end
48
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
+
49
75
  def configure_ssl(http, ssl)
50
76
  http_set(http, :verify_mode, ssl_verify_mode(ssl))
51
- http_set(http, :cert_store, ssl_cert_store(ssl))
77
+ http_set(http, :cert_store, ssl_cert_store(ssl))
52
78
 
53
- http_set(http, :certificate, ssl[:client_cert]) if ssl[:client_cert]
54
- http_set(http, :private_key, ssl[:client_key]) if ssl[:client_key]
55
- http_set(http, :ca_file, ssl[:ca_file]) if ssl[:ca_file]
56
- http_set(http, :ssl_version, ssl[:version]) if ssl[:version]
79
+ SSL_CONFIGURATIONS
80
+ .select { |_, key| ssl[key] }
81
+ .each { |target, key| http_set(http, target, ssl[key]) }
57
82
  end
58
83
 
59
84
  def http_set(http, attr, value)
60
- if http.send(attr) != value
61
- http.send("#{attr}=", value)
62
- end
85
+ http.send("#{attr}=", value) if http.send(attr) != value
63
86
  end
64
87
  end
65
88
  end
@@ -1,5 +1,8 @@
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
 
@@ -9,46 +12,60 @@ module Faraday
9
12
  env[:body] = env[:body].read if env[:body].respond_to? :read
10
13
 
11
14
  session = ::Patron::Session.new
12
- @config_block.call(session) if @config_block
13
- configure_ssl(session, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
15
+ @config_block&.call(session)
16
+ if (env[:url].scheme == 'https') && env[:ssl]
17
+ configure_ssl(session, env[:ssl])
18
+ end
14
19
 
15
- if req = env[:request]
16
- session.timeout = session.connect_timeout = req[:timeout] if req[:timeout]
17
- session.connect_timeout = req[:open_timeout] if req[:open_timeout]
20
+ if (req = env[:request])
21
+ if req[:timeout]
22
+ session.timeout = session.connect_timeout = req[:timeout]
23
+ end
24
+ session.connect_timeout = req[:open_timeout] if req[:open_timeout]
18
25
 
19
- if proxy = req[:proxy]
26
+ if (proxy = req[:proxy])
20
27
  proxy_uri = proxy[:uri].dup
21
- proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20')
22
- proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20')
28
+ proxy_uri.user = proxy[:user] &&
29
+ Utils.escape(proxy[:user]).gsub('+', '%20')
30
+ proxy_uri.password = proxy[:password] &&
31
+ Utils.escape(proxy[:password]).gsub('+', '%20')
23
32
  session.proxy = proxy_uri.to_s
24
33
  end
25
34
  end
26
35
 
27
36
  response = begin
28
37
  data = env[:body] ? env[:body].to_s : nil
29
- session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data)
30
- rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
31
- raise Error::ConnectionFailed, $!
38
+ session.request(env[:method], env[:url].to_s,
39
+ env[:request_headers], data: data)
40
+ rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
41
+ raise Faraday::ConnectionFailed, $ERROR_INFO
32
42
  end
33
43
 
44
+ if (req = env[:request]).stream_response?
45
+ warn "Streaming downloads for #{self.class.name} " \
46
+ 'are not yet implemented.'
47
+ req.on_data.call(response.body, response.body.bytesize)
48
+ end
34
49
  # Remove the "HTTP/1.1 200", leaving just the reason phrase
35
50
  reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
36
51
 
37
- save_response(env, response.status, response.body, response.headers, reason_phrase)
52
+ save_response(env, response.status, response.body,
53
+ response.headers, reason_phrase)
38
54
 
39
55
  @app.call env
40
- rescue ::Patron::TimeoutError => err
41
- if connection_timed_out_message?(err.message)
42
- raise Faraday::Error::ConnectionFailed, err
43
- else
44
- raise Faraday::Error::TimeoutError, err
56
+ rescue ::Patron::TimeoutError => e
57
+ if connection_timed_out_message?(e.message)
58
+ raise Faraday::ConnectionFailed, e
45
59
  end
46
- rescue ::Patron::Error => err
47
- if err.message.include?("code 407")
48
- raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
49
- else
50
- raise Error::ConnectionFailed, err
60
+
61
+ raise Faraday::TimeoutError, e
62
+ rescue ::Patron::Error => e
63
+ if e.message.include?('code 407')
64
+ raise Faraday::ConnectionFailed,
65
+ %(407 "Proxy Authentication Required ")
51
66
  end
67
+
68
+ raise Faraday::ConnectionFailed, e
52
69
  end
53
70
 
54
71
  if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
@@ -60,8 +77,8 @@ module Faraday
60
77
  actions << :options unless actions.include? :options
61
78
  else
62
79
  # Patron 0.4.20 and up
63
- actions << "PATCH" unless actions.include? "PATCH"
64
- actions << "OPTIONS" unless actions.include? "OPTIONS"
80
+ actions << 'PATCH' unless actions.include? 'PATCH'
81
+ actions << 'OPTIONS' unless actions.include? 'OPTIONS'
65
82
  end
66
83
  end
67
84
  end
@@ -76,20 +93,22 @@ module Faraday
76
93
 
77
94
  private
78
95
 
79
- CURL_TIMEOUT_MESSAGES = [ "Connection time-out",
80
- "Connection timed out",
81
- "Timed out before name resolve",
82
- "server connect has timed out",
83
- "Resolving timed out",
84
- "name lookup timed out",
85
- "timed out before SSL",
86
- "connect() timed out"
87
- ].freeze
96
+ CURL_TIMEOUT_MESSAGES = [
97
+ 'Connection time-out',
98
+ 'Connection timed out',
99
+ 'Timed out before name resolve',
100
+ 'server connect has timed out',
101
+ 'Resolving timed out',
102
+ 'name lookup timed out',
103
+ 'timed out before SSL',
104
+ 'connect() timed out'
105
+ ].freeze
88
106
 
89
107
  def connection_timed_out_message?(message)
90
- CURL_TIMEOUT_MESSAGES.any? { |curl_message| message.include?(curl_message) }
108
+ CURL_TIMEOUT_MESSAGES.any? do |curl_message|
109
+ message.include?(curl_message)
110
+ end
91
111
  end
92
-
93
112
  end
94
113
  end
95
114
  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,46 @@ 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
40
  timeout = env[:request][:timeout] || env[:request][:open_timeout]
43
41
  response = if timeout
44
- Timer.timeout(timeout, Faraday::Error::TimeoutError) { execute_request(env, rack_env) }
45
- else
46
- execute_request(env, rack_env)
42
+ Timer.timeout(timeout, Faraday::TimeoutError) do
43
+ execute_request(env, rack_env)
44
+ end
45
+ else
46
+ execute_request(env, rack_env)
47
+ end
48
+
49
+ if (req = env[:request]).stream_response?
50
+ warn "Streaming downloads for #{self.class.name} " \
51
+ 'are not yet implemented.'
52
+ req.on_data.call(response.body, response.body.bytesize)
47
53
  end
48
54
 
49
55
  save_response(env, response.status, response.body, response.headers)
50
56
  @app.call env
51
57
  end
52
58
 
59
+ private
60
+
53
61
  def execute_request(env, rack_env)
54
62
  @session.request(env[:url].to_s, rack_env)
55
63
  end
64
+
65
+ def build_rack_env(env)
66
+ {
67
+ method: env[:method],
68
+ input: env[:body].respond_to?(:read) ? env[:body].read : env[:body],
69
+ 'rack.url_scheme' => env[:url].scheme
70
+ }
71
+ end
56
72
  end
57
73
  end
58
74
  end