faraday 0.11.0 → 0.17.4

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 (65) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +232 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +151 -13
  5. data/Rakefile +13 -0
  6. data/lib/faraday/adapter/em_http.rb +9 -9
  7. data/lib/faraday/adapter/em_synchrony.rb +5 -5
  8. data/lib/faraday/adapter/excon.rb +6 -4
  9. data/lib/faraday/adapter/httpclient.rb +5 -5
  10. data/lib/faraday/adapter/net_http.rb +27 -9
  11. data/lib/faraday/adapter/net_http_persistent.rb +34 -16
  12. data/lib/faraday/adapter/patron.rb +32 -13
  13. data/lib/faraday/adapter/rack.rb +1 -1
  14. data/lib/faraday/adapter/test.rb +21 -13
  15. data/lib/faraday/adapter/typhoeus.rb +4 -115
  16. data/lib/faraday/adapter.rb +2 -0
  17. data/lib/faraday/autoload.rb +1 -1
  18. data/lib/faraday/connection.rb +59 -12
  19. data/lib/faraday/deprecate.rb +109 -0
  20. data/lib/faraday/error.rb +130 -35
  21. data/lib/faraday/options.rb +31 -25
  22. data/lib/faraday/parameters.rb +2 -1
  23. data/lib/faraday/rack_builder.rb +26 -2
  24. data/lib/faraday/request/multipart.rb +7 -2
  25. data/lib/faraday/request/retry.rb +76 -17
  26. data/lib/faraday/request.rb +20 -0
  27. data/lib/faraday/response/logger.rb +3 -3
  28. data/lib/faraday/response/raise_error.rb +7 -3
  29. data/lib/faraday/response.rb +3 -3
  30. data/lib/faraday/utils.rb +18 -9
  31. data/lib/faraday.rb +9 -5
  32. data/spec/faraday/deprecate_spec.rb +147 -0
  33. data/spec/faraday/error_spec.rb +102 -0
  34. data/spec/faraday/response/raise_error_spec.rb +106 -0
  35. data/spec/spec_helper.rb +105 -0
  36. data/test/adapters/default_test.rb +14 -0
  37. data/test/adapters/em_http_test.rb +30 -0
  38. data/test/adapters/em_synchrony_test.rb +32 -0
  39. data/test/adapters/excon_test.rb +30 -0
  40. data/test/adapters/httpclient_test.rb +34 -0
  41. data/test/adapters/integration.rb +263 -0
  42. data/test/adapters/logger_test.rb +136 -0
  43. data/test/adapters/net_http_persistent_test.rb +114 -0
  44. data/test/adapters/net_http_test.rb +79 -0
  45. data/test/adapters/patron_test.rb +40 -0
  46. data/test/adapters/rack_test.rb +38 -0
  47. data/test/adapters/test_middleware_test.rb +157 -0
  48. data/test/adapters/typhoeus_test.rb +38 -0
  49. data/test/authentication_middleware_test.rb +65 -0
  50. data/test/composite_read_io_test.rb +109 -0
  51. data/test/connection_test.rb +738 -0
  52. data/test/env_test.rb +268 -0
  53. data/test/helper.rb +75 -0
  54. data/test/live_server.rb +67 -0
  55. data/test/middleware/instrumentation_test.rb +88 -0
  56. data/test/middleware/retry_test.rb +282 -0
  57. data/test/middleware_stack_test.rb +260 -0
  58. data/test/multibyte.txt +1 -0
  59. data/test/options_test.rb +333 -0
  60. data/test/parameters_test.rb +157 -0
  61. data/test/request_middleware_test.rb +126 -0
  62. data/test/response_middleware_test.rb +72 -0
  63. data/test/strawberry.rb +2 -0
  64. data/test/utils_test.rb +98 -0
  65. metadata +48 -7
@@ -11,6 +11,7 @@ module Faraday
11
11
  class NetHttp < Faraday::Adapter
12
12
  NET_HTTP_EXCEPTIONS = [
13
13
  IOError,
14
+ Errno::EADDRNOTAVAIL,
14
15
  Errno::ECONNABORTED,
15
16
  Errno::ECONNREFUSED,
16
17
  Errno::ECONNRESET,
@@ -28,6 +29,11 @@ module Faraday
28
29
  NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
29
30
  NET_HTTP_EXCEPTIONS << Net::OpenTimeout if defined?(Net::OpenTimeout)
30
31
 
32
+ def initialize(app = nil, opts = {}, &block)
33
+ @cert_store = nil
34
+ super(app, opts, &block)
35
+ end
36
+
31
37
  def call(env)
32
38
  super
33
39
  with_net_http_connection(env) do |http|
@@ -40,7 +46,7 @@ module Faraday
40
46
  if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
41
47
  raise Faraday::SSLError, err
42
48
  else
43
- raise Error::ConnectionFailed, err
49
+ raise Faraday::ConnectionFailed, err
44
50
  end
45
51
  end
46
52
 
@@ -53,9 +59,11 @@ module Faraday
53
59
 
54
60
  @app.call env
55
61
  rescue Timeout::Error, Errno::ETIMEDOUT => err
56
- raise Faraday::Error::TimeoutError, err
62
+ raise Faraday::TimeoutError, err
57
63
  end
58
64
 
65
+ private
66
+
59
67
  def create_request(env)
60
68
  request = Net::HTTPGenericRequest.new \
61
69
  env[:method].to_s.upcase, # request method
@@ -87,10 +95,10 @@ module Faraday
87
95
 
88
96
  def net_http_connection(env)
89
97
  if proxy = env[:request][:proxy]
90
- Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
98
+ Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
91
99
  else
92
100
  Net::HTTP
93
- end.new(env[:url].host, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
101
+ end.new(env[:url].hostname, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
94
102
  end
95
103
 
96
104
  def configure_ssl(http, ssl)
@@ -104,21 +112,31 @@ module Faraday
104
112
  http.ca_path = ssl[:ca_path] if ssl[:ca_path]
105
113
  http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
106
114
  http.ssl_version = ssl[:version] if ssl[:version]
115
+ http.min_version = ssl[:min_version] if ssl[:min_version]
116
+ http.max_version = ssl[:max_version] if ssl[:max_version]
107
117
  end
108
118
 
109
119
  def configure_request(http, req)
110
- http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
111
- http.open_timeout = req[:open_timeout] if req[:open_timeout]
120
+ if req[:timeout]
121
+ http.read_timeout = req[:timeout]
122
+ http.open_timeout = req[:timeout]
123
+ http.write_timeout = req[:timeout] if http.respond_to?(:write_timeout=)
124
+ end
125
+ http.open_timeout = req[:open_timeout] if req[:open_timeout]
126
+ http.write_timeout = req[:write_timeout] if req[:write_timeout] && http.respond_to?(:write_timeout=)
127
+ # Only set if Net::Http supports it, since Ruby 2.5.
128
+ http.max_retries = 0 if http.respond_to?(:max_retries=)
112
129
 
113
130
  @config_block.call(http) if @config_block
114
131
  end
115
132
 
116
133
  def ssl_cert_store(ssl)
117
134
  return ssl[:cert_store] if ssl[:cert_store]
135
+ return @cert_store if @cert_store
118
136
  # Use the default cert store by default, i.e. system ca certs
119
- cert_store = OpenSSL::X509::Store.new
120
- cert_store.set_default_paths
121
- cert_store
137
+ @cert_store = OpenSSL::X509::Store.new
138
+ @cert_store.set_default_paths
139
+ @cert_store
122
140
  end
123
141
 
124
142
  def ssl_verify_mode(ssl)
@@ -1,13 +1,27 @@
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'
4
-
5
1
  module Faraday
6
2
  class Adapter
7
3
  class NetHttpPersistent < NetHttp
8
4
  dependency 'net/http/persistent'
9
5
 
6
+ private
7
+
10
8
  def net_http_connection(env)
9
+ @cached_connection ||=
10
+ if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == [:key, :name]
11
+ options = {name: 'Faraday'}
12
+ options[:pool_size] = @connection_options[:pool_size] if @connection_options.key?(:pool_size)
13
+ Net::HTTP::Persistent.new(**options)
14
+ else
15
+ Net::HTTP::Persistent.new('Faraday')
16
+ end
17
+
18
+ proxy_uri = proxy_uri(env)
19
+ @cached_connection.proxy = proxy_uri if @cached_connection.proxy_uri != proxy_uri
20
+ @cached_connection
21
+ end
22
+
23
+ def proxy_uri(env)
24
+ proxy_uri = nil
11
25
  if (proxy = env[:request][:proxy])
12
26
  proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
13
27
  proxy_uri.user = proxy_uri.password = nil
@@ -16,34 +30,38 @@ module Faraday
16
30
  define_method(:user) { proxy[:user] }
17
31
  define_method(:password) { proxy[:password] }
18
32
  end if proxy[:user]
19
- return Net::HTTP::Persistent.new 'Faraday', proxy_uri
20
33
  end
21
-
22
- Net::HTTP::Persistent.new 'Faraday'
34
+ proxy_uri
23
35
  end
24
36
 
25
37
  def perform_request(http, env)
26
38
  http.request env[:url], create_request(env)
27
39
  rescue Errno::ETIMEDOUT => error
28
- raise Faraday::Error::TimeoutError, error
40
+ raise Faraday::TimeoutError, error
29
41
  rescue Net::HTTP::Persistent::Error => error
30
42
  if error.message.include? 'Timeout'
31
- raise Faraday::Error::TimeoutError, error
43
+ raise Faraday::TimeoutError, error
32
44
  elsif error.message.include? 'connection refused'
33
- raise Faraday::Error::ConnectionFailed, error
45
+ raise Faraday::ConnectionFailed, error
34
46
  else
35
47
  raise
36
48
  end
37
49
  end
38
50
 
39
51
  def configure_ssl(http, ssl)
40
- http.verify_mode = ssl_verify_mode(ssl)
41
- http.cert_store = ssl_cert_store(ssl)
52
+ http_set(http, :verify_mode, ssl_verify_mode(ssl))
53
+ http_set(http, :cert_store, ssl_cert_store(ssl))
54
+
55
+ http_set(http, :certificate, ssl[:client_cert]) if ssl[:client_cert]
56
+ http_set(http, :private_key, ssl[:client_key]) if ssl[:client_key]
57
+ http_set(http, :ca_file, ssl[:ca_file]) if ssl[:ca_file]
58
+ http_set(http, :ssl_version, ssl[:version]) if ssl[:version]
59
+ end
42
60
 
43
- http.certificate = ssl[:client_cert] if ssl[:client_cert]
44
- http.private_key = ssl[:client_key] if ssl[:client_key]
45
- http.ca_file = ssl[:ca_file] if ssl[:ca_file]
46
- http.ssl_version = ssl[:version] if ssl[:version]
61
+ def http_set(http, attr, value)
62
+ if http.send(attr) != value
63
+ http.send("#{attr}=", value)
64
+ end
47
65
  end
48
66
  end
49
67
  end
@@ -5,11 +5,12 @@ module Faraday
5
5
 
6
6
  def call(env)
7
7
  super
8
-
9
8
  # TODO: support streaming requests
10
9
  env[:body] = env[:body].read if env[:body].respond_to? :read
11
10
 
12
- session = @session ||= create_session
11
+ 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]
13
14
 
14
15
  if req = env[:request]
15
16
  session.timeout = session.connect_timeout = req[:timeout] if req[:timeout]
@@ -27,7 +28,7 @@ module Faraday
27
28
  data = env[:body] ? env[:body].to_s : nil
28
29
  session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data)
29
30
  rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
30
- raise Error::ConnectionFailed, $!
31
+ raise Faraday::ConnectionFailed, $!
31
32
  end
32
33
 
33
34
  # Remove the "HTTP/1.1 200", leaving just the reason phrase
@@ -37,16 +38,16 @@ module Faraday
37
38
 
38
39
  @app.call env
39
40
  rescue ::Patron::TimeoutError => err
40
- if err.message == "Connection time-out"
41
- raise Faraday::Error::ConnectionFailed, err
41
+ if connection_timed_out_message?(err.message)
42
+ raise Faraday::ConnectionFailed, err
42
43
  else
43
- raise Faraday::Error::TimeoutError, err
44
+ raise Faraday::TimeoutError, err
44
45
  end
45
46
  rescue ::Patron::Error => err
46
47
  if err.message.include?("code 407")
47
- raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
48
+ raise Faraday::ConnectionFailed, %{407 "Proxy Authentication Required "}
48
49
  else
49
- raise Error::ConnectionFailed, err
50
+ raise Faraday::ConnectionFailed, err
50
51
  end
51
52
  end
52
53
 
@@ -65,12 +66,30 @@ module Faraday
65
66
  end
66
67
  end
67
68
 
68
- def create_session
69
- session = ::Patron::Session.new
70
- session.insecure = true
71
- @config_block.call(session) if @config_block
72
- session
69
+ def configure_ssl(session, ssl)
70
+ if ssl.fetch(:verify, true)
71
+ session.cacert = ssl[:ca_file]
72
+ else
73
+ session.insecure = true
74
+ end
75
+ end
76
+
77
+ private
78
+
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
88
+
89
+ def connection_timed_out_message?(message)
90
+ CURL_TIMEOUT_MESSAGES.any? { |curl_message| message.include?(curl_message) }
73
91
  end
92
+
74
93
  end
75
94
  end
76
95
  end
@@ -41,7 +41,7 @@ module Faraday
41
41
 
42
42
  timeout = env[:request][:timeout] || env[:request][:open_timeout]
43
43
  response = if timeout
44
- Timer.timeout(timeout, Faraday::Error::TimeoutError) { execute_request(env, rack_env) }
44
+ Timer.timeout(timeout, Faraday::TimeoutError) { execute_request(env, rack_env) }
45
45
  else
46
46
  execute_request(env, rack_env)
47
47
  end
@@ -53,17 +53,17 @@ module Faraday
53
53
  @stack.empty?
54
54
  end
55
55
 
56
- def match(request_method, path, headers, body)
56
+ def match(request_method, host, path, headers, body)
57
57
  return false if !@stack.key?(request_method)
58
58
  stack = @stack[request_method]
59
59
  consumed = (@consumed[request_method] ||= [])
60
60
 
61
- stub, meta = matches?(stack, path, headers, body)
61
+ stub, meta = matches?(stack, host, path, headers, body)
62
62
  if stub
63
63
  consumed << stack.delete(stub)
64
64
  return stub, meta
65
65
  end
66
- matches?(consumed, path, headers, body)
66
+ matches?(consumed, host, path, headers, body)
67
67
  end
68
68
 
69
69
  def get(path, headers = {}, &block)
@@ -110,29 +110,35 @@ module Faraday
110
110
  protected
111
111
 
112
112
  def new_stub(request_method, path, headers = {}, body=nil, &block)
113
- normalized_path = path.is_a?(Regexp) ? path : Faraday::Utils.normalize_path(path)
114
- (@stack[request_method] ||= []) << Stub.new(normalized_path, headers, body, block)
113
+ normalized_path, host =
114
+ if path.is_a?(Regexp)
115
+ path
116
+ else
117
+ [Faraday::Utils.normalize_path(path), Faraday::Utils.URI(path).host]
118
+ end
119
+
120
+ (@stack[request_method] ||= []) << Stub.new(host, normalized_path, headers, body, block)
115
121
  end
116
122
 
117
- def matches?(stack, path, headers, body)
123
+ def matches?(stack, host, path, headers, body)
118
124
  stack.each do |stub|
119
- match_result, meta = stub.matches?(path, headers, body)
125
+ match_result, meta = stub.matches?(host, path, headers, body)
120
126
  return stub, meta if match_result
121
127
  end
122
128
  nil
123
129
  end
124
130
  end
125
131
 
126
- class Stub < Struct.new(:path, :params, :headers, :body, :block)
127
- def initialize(full, headers, body, block)
132
+ class Stub < Struct.new(:host, :path, :params, :headers, :body, :block)
133
+ def initialize(host, full, headers, body, block)
128
134
  path, query = full.respond_to?(:split) ? full.split("?") : full
129
135
  params = query ?
130
136
  Faraday::Utils.parse_nested_query(query) :
131
137
  {}
132
- super(path, params, headers, body, block)
138
+ super(host, path, params, headers, body, block)
133
139
  end
134
140
 
135
- def matches?(request_uri, request_headers, request_body)
141
+ def matches?(request_host, request_uri, request_headers, request_body)
136
142
  request_path, request_query = request_uri.split('?')
137
143
  request_params = request_query ?
138
144
  Faraday::Utils.parse_nested_query(request_query) :
@@ -140,7 +146,8 @@ module Faraday
140
146
  # meta is a hash use as carrier
141
147
  # that will be yielded to consumer block
142
148
  meta = {}
143
- return path_match?(request_path, meta) &&
149
+ return (host.nil? || host == request_host) &&
150
+ path_match?(request_path, meta) &&
144
151
  params_match?(request_params) &&
145
152
  (body.to_s.size.zero? || request_body == body) &&
146
153
  headers_match?(request_headers), meta
@@ -183,10 +190,11 @@ module Faraday
183
190
 
184
191
  def call(env)
185
192
  super
193
+ host = env[:url].host
186
194
  normalized_path = Faraday::Utils.normalize_path(env[:url])
187
195
  params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder
188
196
 
189
- stub, meta = stubs.match(env[:method], normalized_path, env.request_headers, env[:body])
197
+ stub, meta = stubs.match(env[:method], host, normalized_path, env.request_headers, env[:body])
190
198
  if stub
191
199
  env[:params] = (query = env[:url].query) ?
192
200
  params_encoder.decode(query) : {}
@@ -1,123 +1,12 @@
1
1
  module Faraday
2
2
  class Adapter
3
+ # This class is just a stub, the real adapter is in https://github.com/philsturgeon/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
3
4
  class Typhoeus < Faraday::Adapter
4
- self.supports_parallel = true
5
-
6
- def self.setup_parallel_manager(options = {})
7
- options.empty? ? ::Typhoeus::Hydra.hydra : ::Typhoeus::Hydra.new(options)
8
- end
5
+ # Needs to define this method in order to support Typhoeus <= 1.3.0
6
+ def call; end
9
7
 
10
8
  dependency 'typhoeus'
11
-
12
- def call(env)
13
- super
14
- perform_request env
15
- @app.call env
16
- end
17
-
18
- def perform_request(env)
19
- read_body env
20
-
21
- hydra = env[:parallel_manager] || self.class.setup_parallel_manager
22
- hydra.queue request(env)
23
- hydra.run unless parallel?(env)
24
- rescue Errno::ECONNREFUSED
25
- raise Error::ConnectionFailed, $!
26
- end
27
-
28
- # TODO: support streaming requests
29
- def read_body(env)
30
- env[:body] = env[:body].read if env[:body].respond_to? :read
31
- end
32
-
33
- def request(env)
34
- method = env[:method]
35
- # For some reason, prevents Typhoeus from using "100-continue".
36
- # We want this because Webrick 1.3.1 can't seem to handle it w/ PUT.
37
- method = method.to_s.upcase if method == :put
38
-
39
- req = ::Typhoeus::Request.new env[:url].to_s,
40
- :method => method,
41
- :body => env[:body],
42
- :headers => env[:request_headers],
43
- :disable_ssl_peer_verification => (env[:ssl] && env[:ssl].disable?)
44
-
45
- configure_ssl req, env
46
- configure_proxy req, env
47
- configure_timeout req, env
48
- configure_socket req, env
49
-
50
- req.on_complete do |resp|
51
- if resp.timed_out?
52
- if parallel?(env)
53
- # TODO: error callback in async mode
54
- else
55
- raise Faraday::Error::TimeoutError, "request timed out"
56
- end
57
- end
58
-
59
- case resp.curl_return_code
60
- when 0
61
- # everything OK
62
- when 7
63
- raise Error::ConnectionFailed, resp.curl_error_message
64
- when 60
65
- raise Faraday::SSLError, resp.curl_error_message
66
- else
67
- raise Error::ClientError, resp.curl_error_message
68
- end
69
-
70
- save_response(env, resp.code, resp.body) do |response_headers|
71
- response_headers.parse resp.headers
72
- end
73
- # in async mode, :response is initialized at this point
74
- env[:response].finish(env) if parallel?(env)
75
- end
76
-
77
- req
78
- end
79
-
80
- def configure_ssl(req, env)
81
- ssl = env[:ssl]
82
-
83
- req.ssl_version = ssl[:version] if ssl[:version]
84
- req.ssl_cert = ssl[:client_cert] if ssl[:client_cert]
85
- req.ssl_key = ssl[:client_key] if ssl[:client_key]
86
- req.ssl_cacert = ssl[:ca_file] if ssl[:ca_file]
87
- req.ssl_capath = ssl[:ca_path] if ssl[:ca_path]
88
- end
89
-
90
- def configure_proxy(req, env)
91
- proxy = request_options(env)[:proxy]
92
- return unless proxy
93
-
94
- req.proxy = "#{proxy[:uri].host}:#{proxy[:uri].port}"
95
-
96
- if proxy[:user] && proxy[:password]
97
- req.proxy_username = proxy[:user]
98
- req.proxy_password = proxy[:password]
99
- end
100
- end
101
-
102
- def configure_timeout(req, env)
103
- env_req = request_options(env)
104
- req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout]
105
- req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout]
106
- end
107
-
108
- def configure_socket(req, env)
109
- if bind = request_options(env)[:bind]
110
- req.interface = bind[:host]
111
- end
112
- end
113
-
114
- def request_options(env)
115
- env[:request]
116
- end
117
-
118
- def parallel?(env)
119
- !!env[:parallel_manager]
120
- end
9
+ dependency 'typhoeus/adapters/faraday'
121
10
  end
122
11
  end
123
12
  end
@@ -40,6 +40,8 @@ module Faraday
40
40
  env.clear_body if env.needs_body?
41
41
  end
42
42
 
43
+ private
44
+
43
45
  def save_response(env, status, body, headers = nil, reason_phrase = nil)
44
46
  env.status = status
45
47
  env.body = body
@@ -53,9 +53,9 @@ module Faraday
53
53
  autoload_all 'faraday/adapter',
54
54
  :NetHttp => 'net_http',
55
55
  :NetHttpPersistent => 'net_http_persistent',
56
- :Typhoeus => 'typhoeus',
57
56
  :EMSynchrony => 'em_synchrony',
58
57
  :EMHttp => 'em_http',
58
+ :Typhoeus => 'typhoeus',
59
59
  :Patron => 'patron',
60
60
  :Excon => 'excon',
61
61
  :Test => 'test',
@@ -39,6 +39,9 @@ module Faraday
39
39
  # Public: Sets the default parallel manager for this connection.
40
40
  attr_writer :default_parallel_manager
41
41
 
42
+ # Public: Gets or Sets the Hash proxy options.
43
+ # attr_reader :proxy
44
+
42
45
  # Public: Initializes a new Faraday::Connection.
43
46
  #
44
47
  # url - URI or String base URL to use as a prefix for all
@@ -55,9 +58,9 @@ module Faraday
55
58
  # :user - String (optional)
56
59
  # :password - String (optional)
57
60
  def initialize(url = nil, options = nil)
58
- options = ConnectionOptions.from(options) unless options and options.is_a?(ConnectionOptions)
61
+ options = ConnectionOptions.from(options)
59
62
 
60
- if url.is_a?(Hash)
63
+ if url.is_a?(Hash) || url.is_a?(ConnectionOptions)
61
64
  options = options.merge(url)
62
65
  url = options.url
63
66
  end
@@ -79,14 +82,9 @@ module Faraday
79
82
  @params.update(options.params) if options.params
80
83
  @headers.update(options.headers) if options.headers
81
84
 
82
- @proxy = nil
83
- proxy(options.fetch(:proxy) {
84
- uri = ENV['http_proxy']
85
- if uri && !uri.empty?
86
- uri = 'http://' + uri if uri !~ /^http/i
87
- uri
88
- end
89
- })
85
+ @manual_proxy = !!options.proxy
86
+ @proxy = options.proxy ? ProxyOptions.from(options.proxy) : proxy_from_env(url)
87
+ @temp_proxy = @proxy
90
88
 
91
89
  yield(self) if block_given?
92
90
 
@@ -283,9 +281,17 @@ module Faraday
283
281
  # Public: Gets or Sets the Hash proxy options.
284
282
  def proxy(arg = nil)
285
283
  return @proxy if arg.nil?
284
+ warn 'Warning: use of proxy(new_value) to set connection proxy have been DEPRECATED and will be removed in Faraday 1.0'
285
+ @manual_proxy = true
286
286
  @proxy = ProxyOptions.from(arg)
287
287
  end
288
288
 
289
+ # Public: Sets the Hash proxy options.
290
+ def proxy=(new_value)
291
+ @manual_proxy = true
292
+ @proxy = new_value ? ProxyOptions.from(new_value) : nil
293
+ end
294
+
289
295
  def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port=
290
296
  def_delegator :url_prefix, :path, :path_prefix
291
297
 
@@ -304,7 +310,7 @@ module Faraday
304
310
  #
305
311
  # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
306
312
  #
307
- # Returns the parsed URI from teh given input..
313
+ # Returns the parsed URI from the given input..
308
314
  def url_prefix=(url, encoder = nil)
309
315
  uri = @url_prefix = Utils.URI(url)
310
316
  self.path_prefix = uri.path
@@ -367,7 +373,11 @@ module Faraday
367
373
  raise ArgumentError, "unknown http method: #{method}"
368
374
  end
369
375
 
376
+ # Resets temp_proxy
377
+ @temp_proxy = proxy_for_request(url)
378
+
370
379
  request = build_request(method) do |req|
380
+ req.options = req.options.merge(:proxy => @temp_proxy)
371
381
  req.url(url) if url
372
382
  req.headers.update(headers) if headers
373
383
  req.body = body if body
@@ -384,7 +394,7 @@ module Faraday
384
394
  Request.create(method) do |req|
385
395
  req.params = self.params.dup
386
396
  req.headers = self.headers.dup
387
- req.options = self.options.merge(:proxy => self.proxy)
397
+ req.options = self.options
388
398
  yield(req) if block_given?
389
399
  end
390
400
  end
@@ -433,5 +443,42 @@ module Faraday
433
443
  header(*args)
434
444
  headers[Faraday::Request::Authorization::KEY] = header
435
445
  end
446
+
447
+ def proxy_from_env(url)
448
+ return if Faraday.ignore_env_proxy
449
+ uri = nil
450
+ if URI.parse('').respond_to?(:find_proxy)
451
+ case url
452
+ when String
453
+ uri = Utils.URI(url)
454
+ uri = URI.parse("#{uri.scheme}://#{uri.hostname}").find_proxy
455
+ when URI
456
+ uri = url.find_proxy
457
+ when nil
458
+ uri = find_default_proxy
459
+ end
460
+ else
461
+ warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
462
+ uri = find_default_proxy
463
+ end
464
+ ProxyOptions.from(uri) if uri
465
+ end
466
+
467
+ def find_default_proxy
468
+ uri = ENV['http_proxy']
469
+ if uri && !uri.empty?
470
+ uri = 'http://' + uri if uri !~ /^http/i
471
+ uri
472
+ end
473
+ end
474
+
475
+ def proxy_for_request(url)
476
+ return self.proxy if @manual_proxy
477
+ if url && Utils.URI(url).absolute?
478
+ proxy_from_env(url)
479
+ else
480
+ self.proxy
481
+ end
482
+ end
436
483
  end
437
484
  end