faraday 0.6.0 → 0.8.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 (58) hide show
  1. data/Gemfile +22 -15
  2. data/{LICENSE → LICENSE.md} +1 -1
  3. data/README.md +216 -146
  4. data/Rakefile +14 -58
  5. data/config.ru +6 -0
  6. data/faraday.gemspec +31 -38
  7. data/lib/faraday/adapter/em_http.rb +204 -0
  8. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
  9. data/lib/faraday/adapter/em_synchrony.rb +67 -16
  10. data/lib/faraday/adapter/excon.rb +1 -2
  11. data/lib/faraday/adapter/net_http.rb +82 -39
  12. data/lib/faraday/adapter/net_http_persistent.rb +37 -0
  13. data/lib/faraday/adapter/patron.rb +42 -8
  14. data/lib/faraday/adapter/rack.rb +59 -0
  15. data/lib/faraday/adapter/test.rb +49 -9
  16. data/lib/faraday/adapter/typhoeus.rb +70 -15
  17. data/lib/faraday/adapter.rb +41 -18
  18. data/lib/faraday/builder.rb +34 -16
  19. data/lib/faraday/connection.rb +177 -115
  20. data/lib/faraday/error.rb +4 -2
  21. data/lib/faraday/middleware.rb +18 -10
  22. data/lib/faraday/request/authorization.rb +40 -0
  23. data/lib/faraday/request/basic_authentication.rb +13 -0
  24. data/lib/faraday/request/multipart.rb +5 -6
  25. data/lib/faraday/request/retry.rb +21 -0
  26. data/lib/faraday/request/token_authentication.rb +15 -0
  27. data/lib/faraday/request/url_encoded.rb +1 -3
  28. data/lib/faraday/request.rb +48 -38
  29. data/lib/faraday/response/raise_error.rb +1 -1
  30. data/lib/faraday/response.rb +6 -5
  31. data/lib/faraday/upload_io.rb +1 -1
  32. data/lib/faraday/utils.rb +196 -29
  33. data/lib/faraday.rb +69 -13
  34. data/test/adapters/default_test.rb +14 -0
  35. data/test/adapters/em_http_test.rb +14 -0
  36. data/test/adapters/em_synchrony_test.rb +14 -0
  37. data/test/adapters/excon_test.rb +23 -0
  38. data/test/adapters/integration.rb +190 -0
  39. data/test/adapters/logger_test.rb +2 -2
  40. data/test/adapters/net_http_persistent_test.rb +11 -0
  41. data/test/adapters/net_http_test.rb +37 -21
  42. data/test/adapters/patron_test.rb +17 -0
  43. data/test/adapters/rack_test.rb +26 -0
  44. data/test/adapters/test_middleware_test.rb +28 -1
  45. data/test/adapters/typhoeus_test.rb +14 -0
  46. data/test/authentication_middleware_test.rb +65 -0
  47. data/test/connection_test.rb +211 -81
  48. data/test/env_test.rb +80 -31
  49. data/test/helper.rb +23 -13
  50. data/test/live_server.rb +38 -29
  51. data/test/middleware/retry_test.rb +25 -0
  52. data/test/middleware_stack_test.rb +85 -4
  53. data/test/request_middleware_test.rb +42 -19
  54. data/test/response_middleware_test.rb +30 -3
  55. metadata +104 -110
  56. data/lib/faraday/adapter/action_dispatch.rb +0 -30
  57. data/lib/faraday/request/json.rb +0 -31
  58. data/test/adapters/live_test.rb +0 -186
data/faraday.gemspec CHANGED
@@ -1,59 +1,41 @@
1
- ## This is the rakegem gemspec template. Make sure you read and understand
2
- ## all of the comments. Some sections require modification, and others can
3
- ## be deleted if you don't need them. Once you understand the contents of
4
- ## this file, feel free to delete any comments that begin with two hash marks.
5
- ## You can find comprehensive Gem::Specification documentation, at
6
- ## http://docs.rubygems.org/read/chapter/20
7
1
  Gem::Specification.new do |s|
8
2
  s.specification_version = 2 if s.respond_to? :specification_version=
9
3
  s.required_rubygems_version = Gem::Requirement.new(">= 1.3.5") if s.respond_to? :required_rubygems_version=
10
4
 
11
- ## Leave these as is they will be modified for you by the rake gemspec task.
12
- ## If your rubyforge_project name is different, then edit it and comment out
13
- ## the sub! line in the Rakefile
14
- s.name = 'faraday'
15
- s.version = '0.6.0'
16
- s.date = '2011-03-31'
17
- s.rubyforge_project = 'faraday'
5
+ s.name = 'faraday'
6
+ s.version = '0.8.0'
18
7
 
19
- ## Make sure your summary is short. The description may be as long
20
- ## as you like.
21
8
  s.summary = "HTTP/REST API client library."
22
- s.description = "HTTP/REST API client library."
9
+ # TODO: s.description
23
10
 
24
- ## List the primary authors. If there are a bunch of authors, it's probably
25
- ## better to set the email to an email list or something. If you don't have
26
- ## a custom homepage, consider using your GitHub URL or the like.
27
11
  s.authors = ["Rick Olson"]
28
12
  s.email = 'technoweenie@gmail.com'
29
- s.homepage = 'http://github.com/technoweenie/faraday'
13
+ s.homepage = 'https://github.com/technoweenie/faraday'
30
14
 
31
- ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
32
- ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
33
- s.require_paths = %w[lib]
15
+ s.add_dependency 'multipart-post', '~> 1.1'
16
+ s.add_development_dependency 'rake'
17
+ s.add_development_dependency 'simplecov'
18
+ s.add_development_dependency 'test-unit'
19
+ s.add_development_dependency 'webmock'
34
20
 
35
- s.add_development_dependency('rake', '~> 0.8')
36
- s.add_runtime_dependency('addressable', '~> 2.2.4')
37
- s.add_runtime_dependency('multipart-post', '~> 1.1.0')
38
- s.add_runtime_dependency('rack', ['>= 1.1.0', "< 2"])
39
-
40
- ## Leave this section as-is. It will be automatically generated from the
41
- ## contents of your Git repository via the gemspec task. DO NOT REMOVE
42
- ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
43
21
  # = MANIFEST =
44
22
  s.files = %w[
45
23
  Gemfile
46
- LICENSE
24
+ LICENSE.md
47
25
  README.md
48
26
  Rakefile
27
+ config.ru
49
28
  faraday.gemspec
50
29
  lib/faraday.rb
51
30
  lib/faraday/adapter.rb
52
- lib/faraday/adapter/action_dispatch.rb
31
+ lib/faraday/adapter/em_http.rb
53
32
  lib/faraday/adapter/em_synchrony.rb
33
+ lib/faraday/adapter/em_synchrony/parallel_manager.rb
54
34
  lib/faraday/adapter/excon.rb
55
35
  lib/faraday/adapter/net_http.rb
36
+ lib/faraday/adapter/net_http_persistent.rb
56
37
  lib/faraday/adapter/patron.rb
38
+ lib/faraday/adapter/rack.rb
57
39
  lib/faraday/adapter/test.rb
58
40
  lib/faraday/adapter/typhoeus.rb
59
41
  lib/faraday/builder.rb
@@ -61,29 +43,40 @@ Gem::Specification.new do |s|
61
43
  lib/faraday/error.rb
62
44
  lib/faraday/middleware.rb
63
45
  lib/faraday/request.rb
64
- lib/faraday/request/json.rb
46
+ lib/faraday/request/authorization.rb
47
+ lib/faraday/request/basic_authentication.rb
65
48
  lib/faraday/request/multipart.rb
49
+ lib/faraday/request/retry.rb
50
+ lib/faraday/request/token_authentication.rb
66
51
  lib/faraday/request/url_encoded.rb
67
52
  lib/faraday/response.rb
68
53
  lib/faraday/response/logger.rb
69
54
  lib/faraday/response/raise_error.rb
70
55
  lib/faraday/upload_io.rb
71
56
  lib/faraday/utils.rb
72
- test/adapters/live_test.rb
57
+ test/adapters/default_test.rb
58
+ test/adapters/em_http_test.rb
59
+ test/adapters/em_synchrony_test.rb
60
+ test/adapters/excon_test.rb
61
+ test/adapters/integration.rb
73
62
  test/adapters/logger_test.rb
63
+ test/adapters/net_http_persistent_test.rb
74
64
  test/adapters/net_http_test.rb
65
+ test/adapters/patron_test.rb
66
+ test/adapters/rack_test.rb
75
67
  test/adapters/test_middleware_test.rb
68
+ test/adapters/typhoeus_test.rb
69
+ test/authentication_middleware_test.rb
76
70
  test/connection_test.rb
77
71
  test/env_test.rb
78
72
  test/helper.rb
79
73
  test/live_server.rb
74
+ test/middleware/retry_test.rb
80
75
  test/middleware_stack_test.rb
81
76
  test/request_middleware_test.rb
82
77
  test/response_middleware_test.rb
83
78
  ]
84
79
  # = MANIFEST =
85
80
 
86
- ## Test files will be grabbed from the file list. Make sure the path glob
87
- ## matches what you actually use.
88
- s.test_files = s.files.select { |path| path =~ /^test\/.*_test\.rb/ }
81
+ s.test_files = s.files.select { |path| path =~ %r{^test/*/.+\.rb} }
89
82
  end
@@ -0,0 +1,204 @@
1
+ module Faraday
2
+ class Adapter
3
+ # EventMachine adapter is useful for either asynchronous requests
4
+ # when in EM reactor loop or for making parallel requests in
5
+ # synchronous code.
6
+ class EMHttp < Faraday::Adapter
7
+
8
+ dependency 'em-http'
9
+
10
+ self.supports_parallel = true
11
+
12
+ def self.setup_parallel_manager(options = nil)
13
+ Manager.new
14
+ end
15
+
16
+ def call(env)
17
+ super
18
+ perform_request env
19
+ @app.call env
20
+ end
21
+
22
+ def perform_request(env)
23
+ if parallel?(env)
24
+ manager = env[:parallel_manager]
25
+ manager.add {
26
+ perform_single_request(env).
27
+ callback { env[:response].finish(env) }
28
+ }
29
+ else
30
+ unless EventMachine.reactor_running?
31
+ error = nil
32
+ # start EM, block until request is completed
33
+ EventMachine.run do
34
+ perform_single_request(env).
35
+ callback { EventMachine.stop }.
36
+ errback { |client|
37
+ error = error_message(client)
38
+ EventMachine.stop
39
+ }
40
+ end
41
+ raise_error(error) if error
42
+ else
43
+ # EM is running: instruct upstream that this is an async request
44
+ env[:parallel_manager] = true
45
+ perform_single_request(env).
46
+ callback { env[:response].finish(env) }.
47
+ errback {
48
+ # TODO: no way to communicate the error in async mode
49
+ raise NotImplementedError
50
+ }
51
+ end
52
+ end
53
+ end
54
+
55
+ # TODO: reuse the connection to support pipelining
56
+ def perform_single_request(env)
57
+ req = EventMachine::HttpRequest.new(env[:url], connection_config(env))
58
+ req.setup_request(env[:method], request_config(env)).callback { |client|
59
+ save_response(env, client.response_header.status, client.response) do |resp_headers|
60
+ client.response_header.each do |name, value|
61
+ resp_headers[name.to_sym] = value
62
+ end
63
+ end
64
+ }
65
+ end
66
+
67
+ def error_message(client)
68
+ client.error or "request failed"
69
+ end
70
+
71
+ def raise_error(msg)
72
+ errklass = Faraday::Error::ClientError
73
+ if msg == Errno::ETIMEDOUT
74
+ errklass = Faraday::Error::TimeoutError
75
+ msg = "request timed out"
76
+ elsif msg == Errno::ECONNREFUSED
77
+ errklass = Faraday::Error::ConnectionFailed
78
+ msg = "connection refused"
79
+ end
80
+ raise errklass, msg
81
+ end
82
+
83
+ def connection_config(env)
84
+ options = {}
85
+ configure_ssl(options, env)
86
+ configure_proxy(options, env)
87
+ configure_timeout(options, env)
88
+ options
89
+ end
90
+
91
+ def request_config(env)
92
+ options = {
93
+ :body => read_body(env),
94
+ :head => env[:request_headers],
95
+ # :keepalive => true,
96
+ # :file => 'path/to/file', # stream data off disk
97
+ }
98
+ configure_compression(options, env)
99
+ # configure_proxy_auth
100
+ # :proxy => {:authorization => [user, pass]}
101
+ # proxy[:username] && proxy[:password]
102
+ options
103
+ end
104
+
105
+ def read_body(env)
106
+ body = env[:body]
107
+ body.respond_to?(:read) ? body.read : body
108
+ end
109
+
110
+ def configure_ssl(options, env)
111
+ if ssl = env[:ssl]
112
+ # :ssl => {
113
+ # :private_key_file => '/tmp/server.key',
114
+ # :cert_chain_file => '/tmp/server.crt',
115
+ # :verify_peer => false
116
+ end
117
+ end
118
+
119
+ def configure_proxy(options, env)
120
+ if proxy = request_options(env)[:proxy]
121
+ options[:proxy] = {
122
+ :host => proxy[:uri].host,
123
+ :port => proxy[:uri].port
124
+ }
125
+ end
126
+ end
127
+
128
+ def configure_timeout(options, env)
129
+ timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout)
130
+ options[:connect_timeout] = options[:inactivity_timeout] = timeout
131
+ options[:connect_timeout] = open_timeout if open_timeout
132
+ end
133
+
134
+ def configure_compression(options, env)
135
+ if env[:method] == :get and not options[:head].key? 'accept-encoding'
136
+ options[:head]['accept-encoding'] = 'gzip, compressed'
137
+ end
138
+ end
139
+
140
+ def request_options(env)
141
+ env[:request]
142
+ end
143
+
144
+ def parallel?(env)
145
+ !!env[:parallel_manager]
146
+ end
147
+
148
+ # The parallel manager is designed to start an EventMachine loop
149
+ # and block until all registered requests have been completed.
150
+ class Manager
151
+ def initialize
152
+ reset
153
+ end
154
+
155
+ def reset
156
+ @registered_procs = []
157
+ @num_registered = 0
158
+ @num_succeeded = 0
159
+ @errors = []
160
+ @running = false
161
+ end
162
+
163
+ def running?() @running end
164
+
165
+ def add
166
+ if running?
167
+ perform_request { yield }
168
+ else
169
+ @registered_procs << Proc.new
170
+ end
171
+ @num_registered += 1
172
+ end
173
+
174
+ def run
175
+ if @num_registered > 0
176
+ @running = true
177
+ EventMachine.run do
178
+ @registered_procs.each do |proc|
179
+ perform_request(&proc)
180
+ end
181
+ end
182
+ if @errors.size > 0
183
+ raise Faraday::Error::ClientError, @errors.first || "connection failed"
184
+ end
185
+ end
186
+ ensure
187
+ reset
188
+ end
189
+
190
+ def perform_request
191
+ client = yield
192
+ client.callback { @num_succeeded += 1; check_finished }
193
+ client.errback { @errors << client.error; check_finished }
194
+ end
195
+
196
+ def check_finished
197
+ if @num_succeeded + @errors.size == @num_registered
198
+ EventMachine.stop
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,66 @@
1
+ module Faraday
2
+ class Adapter
3
+ class EMSynchrony < Faraday::Adapter
4
+ class ParallelManager
5
+
6
+ # Add requests to queue. The `request` argument should be a
7
+ # `EM::HttpRequest` object.
8
+ def add(request, method, *args, &block)
9
+ queue << {
10
+ :request => request,
11
+ :method => method,
12
+ :args => args,
13
+ :block => block
14
+ }
15
+ end
16
+
17
+ # Run all requests on queue with `EM::Synchrony::Multi`, wrapping
18
+ # it in a reactor and fiber if needed.
19
+ def run
20
+ result = nil
21
+ if !EM.reactor_running?
22
+ EM.run {
23
+ Fiber.new do
24
+ result = perform
25
+ EM.stop
26
+ end.resume
27
+ }
28
+ else
29
+ result = perform
30
+ end
31
+ result
32
+ end
33
+
34
+
35
+ private
36
+
37
+ # The request queue.
38
+ def queue
39
+ @queue ||= []
40
+ end
41
+
42
+ # Main `EM::Synchrony::Multi` performer.
43
+ def perform
44
+ multi = ::EM::Synchrony::Multi.new
45
+
46
+ queue.each do |item|
47
+ method = "a#{item[:method]}".to_sym
48
+
49
+ req = item[:request].send(method, *item[:args])
50
+ req.callback(&item[:block])
51
+
52
+ req_name = "req_#{multi.requests.size}".to_sym
53
+ multi.add(req_name, req)
54
+ end
55
+
56
+ # Clear the queue, so parallel manager objects can be reused.
57
+ @queue = []
58
+
59
+ # Block fiber until all requests have returned.
60
+ multi.perform
61
+ end
62
+
63
+ end # ParallelManager
64
+ end # EMSynchrony
65
+ end # Adapter
66
+ end # Faraday
@@ -1,11 +1,21 @@
1
+ require 'uri'
2
+
1
3
  module Faraday
2
4
  class Adapter
3
5
  class EMSynchrony < Faraday::Adapter
6
+
4
7
  dependency do
5
8
  require 'em-synchrony/em-http'
9
+ require 'em-synchrony/em-multi'
6
10
  require 'fiber'
7
11
  end
8
12
 
13
+ self.supports_parallel = true
14
+
15
+ def self.setup_parallel_manager(options = {})
16
+ ParallelManager.new
17
+ end
18
+
9
19
  def call(env)
10
20
  super
11
21
  request = EventMachine::HttpRequest.new(URI::parse(env[:url].to_s))
@@ -22,10 +32,10 @@ module Faraday
22
32
 
23
33
  if req = env[:request]
24
34
  if proxy = req[:proxy]
25
- uri = Addressable::URI.parse(proxy[:uri])
35
+ uri = URI.parse(proxy[:uri])
26
36
  options[:proxy] = {
27
37
  :host => uri.host,
28
- :port => uri.inferred_port
38
+ :port => uri.port
29
39
  }
30
40
  if proxy[:username] && proxy[:password]
31
41
  options[:proxy][:authorization] = [proxy[:username], proxy[:password]]
@@ -38,23 +48,43 @@ module Faraday
38
48
  end
39
49
  end
40
50
 
41
- client = nil
42
- block = lambda { request.send env[:method].to_s.downcase.to_sym, options }
43
- if !EM.reactor_running?
44
- EM.run {
45
- Fiber.new do
46
- client = block.call
47
- EM.stop
48
- end.resume
49
- }
51
+ http_method = env[:method].to_s.downcase.to_sym
52
+
53
+ # Queue requests for parallel execution.
54
+ if env[:parallel_manager]
55
+ env[:parallel_manager].add(request, http_method, options) do |resp|
56
+ save_response(env, resp.response_header.status, resp.response) do |resp_headers|
57
+ resp.response_header.each do |name, value|
58
+ resp_headers[name.to_sym] = value
59
+ end
60
+ end
61
+
62
+ # Finalize the response object with values from `env`.
63
+ env[:response].finish(env)
64
+ end
65
+
66
+ # Execute single request.
50
67
  else
51
- client = block.call
52
- end
68
+ client = nil
69
+ block = lambda { request.send(http_method, options) }
70
+
71
+ if !EM.reactor_running?
72
+ EM.run do
73
+ Fiber.new {
74
+ client = block.call
75
+ EM.stop
76
+ }.resume
77
+ end
78
+ else
79
+ client = block.call
80
+ end
53
81
 
54
- client.response_header.each do |name, value|
55
- response_headers(env)[name.to_sym] = value
82
+ save_response(env, client.response_header.status, client.response) do |resp_headers|
83
+ client.response_header.each do |name, value|
84
+ resp_headers[name.to_sym] = value
85
+ end
86
+ end
56
87
  end
57
- env.update :status => client.response_header.status, :body => client.response
58
88
 
59
89
  @app.call env
60
90
  rescue Errno::ECONNREFUSED
@@ -63,3 +93,24 @@ module Faraday
63
93
  end
64
94
  end
65
95
  end
96
+
97
+ require 'faraday/adapter/em_synchrony/parallel_manager'
98
+
99
+ # add missing patch(), options() methods
100
+ EventMachine::HTTPMethods.module_eval do
101
+ ([:patch, :options] - instance_methods).each do |type|
102
+ module_eval %[
103
+ def #{type}(options = {}, &blk)
104
+ f = Fiber.current
105
+ conn = setup_request(:#{type}, options, &blk)
106
+ if conn.error.nil?
107
+ conn.callback { f.resume(conn) }
108
+ conn.errback { f.resume(conn) }
109
+ Fiber.yield
110
+ else
111
+ conn
112
+ end
113
+ end
114
+ ]
115
+ end
116
+ end
@@ -17,8 +17,7 @@ module Faraday
17
17
  :headers => env[:request_headers],
18
18
  :body => env[:body]
19
19
 
20
- env.update :status => resp.status.to_i, :body => resp.body
21
- response_headers(env).update resp.headers
20
+ save_response(env, resp.status.to_i, resp.body, resp.headers)
22
21
 
23
22
  @app.call env
24
23
  rescue ::Excon::Errors::SocketError
@@ -8,64 +8,107 @@ end
8
8
  module Faraday
9
9
  class Adapter
10
10
  class NetHttp < Faraday::Adapter
11
- def call(env)
12
- super
13
- url = env[:url]
14
- req = env[:request]
11
+ NET_HTTP_EXCEPTIONS = [
12
+ EOFError,
13
+ Errno::ECONNABORTED,
14
+ Errno::ECONNREFUSED,
15
+ Errno::ECONNRESET,
16
+ Errno::EINVAL,
17
+ Net::HTTPBadResponse,
18
+ Net::HTTPHeaderSyntaxError,
19
+ Net::ProtocolError,
20
+ SocketError
21
+ ]
15
22
 
16
- http = net_http_class(env).new(url.host, url.inferred_port)
23
+ NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
17
24
 
18
- if http.use_ssl = (url.scheme == 'https' && env[:ssl])
19
- ssl = env[:ssl]
20
- http.verify_mode = ssl[:verify_mode] || ssl.fetch(:verify, true) ?
21
- OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
22
- http.cert = ssl[:client_cert] if ssl[:client_cert]
23
- http.key = ssl[:client_key] if ssl[:client_key]
24
- http.ca_file = ssl[:ca_file] if ssl[:ca_file]
25
- http.cert_store = ssl[:cert_store] if ssl[:cert_store]
26
- end
25
+ def call(env)
26
+ super
27
+ http = net_http_connection(env)
28
+ configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
27
29
 
30
+ req = env[:request]
28
31
  http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
29
32
  http.open_timeout = req[:open_timeout] if req[:open_timeout]
30
33
 
31
- if :get != env[:method]
32
- http_request = Net::HTTPGenericRequest.new \
33
- env[:method].to_s.upcase, # request method
34
- !!env[:body], # is there data
35
- true, # does net/http love you, true or false?
36
- url.request_uri, # request uri path
37
- env[:request_headers] # request headers
38
-
39
- if env[:body].respond_to?(:read)
40
- http_request.body_stream = env[:body]
41
- env[:body] = nil
42
- end
43
- end
44
-
45
34
  begin
46
- http_response = if :get == env[:method]
47
- # prefer `get` to `request` because the former handles gzip (ruby 1.9)
48
- http.get url.request_uri, env[:request_headers]
49
- else
50
- http.request http_request, env[:body]
51
- end
52
- rescue Errno::ECONNREFUSED
35
+ http_response = perform_request(http, env)
36
+ rescue *NET_HTTP_EXCEPTIONS
53
37
  raise Error::ConnectionFailed, $!
54
38
  end
55
39
 
56
- http_response.each_header do |key, value|
57
- response_headers(env)[key] = value
40
+ save_response(env, http_response.code.to_i, http_response.body) do |response_headers|
41
+ http_response.each_header do |key, value|
42
+ response_headers[key] = value
43
+ end
58
44
  end
59
- env.update :status => http_response.code.to_i, :body => http_response.body
60
45
 
61
46
  @app.call env
47
+ rescue Timeout::Error => err
48
+ raise Faraday::Error::TimeoutError, err
49
+ end
50
+
51
+ def create_request(env)
52
+ request = Net::HTTPGenericRequest.new \
53
+ env[:method].to_s.upcase, # request method
54
+ !!env[:body], # is there request body
55
+ :head != env[:method], # is there response body
56
+ env[:url].request_uri, # request uri path
57
+ env[:request_headers] # request headers
58
+
59
+ if env[:body].respond_to?(:read)
60
+ request.body_stream = env[:body]
61
+ else
62
+ request.body = env[:body]
63
+ end
64
+ request
65
+ end
66
+
67
+ def perform_request(http, env)
68
+ if :get == env[:method] and !env[:body]
69
+ # prefer `get` to `request` because the former handles gzip (ruby 1.9)
70
+ http.get env[:url].request_uri, env[:request_headers]
71
+ else
72
+ http.request create_request(env)
73
+ end
62
74
  end
63
75
 
64
- def net_http_class(env)
76
+ def net_http_connection(env)
65
77
  if proxy = env[:request][:proxy]
66
78
  Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
67
79
  else
68
80
  Net::HTTP
81
+ end.new(env[:url].host, env[:url].port)
82
+ end
83
+
84
+ def configure_ssl(http, ssl)
85
+ http.use_ssl = true
86
+ http.verify_mode = ssl_verify_mode(ssl)
87
+ http.cert_store = ssl_cert_store(ssl)
88
+
89
+ http.cert = ssl[:client_cert] if ssl[:client_cert]
90
+ http.key = ssl[:client_key] if ssl[:client_key]
91
+ http.ca_file = ssl[:ca_file] if ssl[:ca_file]
92
+ http.ca_path = ssl[:ca_path] if ssl[:ca_path]
93
+ http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
94
+ http.ssl_version = ssl[:version] if ssl[:version]
95
+ end
96
+
97
+ def ssl_cert_store(ssl)
98
+ return ssl[:cert_store] if ssl[:cert_store]
99
+ # Use the default cert store by default, i.e. system ca certs
100
+ cert_store = OpenSSL::X509::Store.new
101
+ cert_store.set_default_paths
102
+ cert_store
103
+ end
104
+
105
+ def ssl_verify_mode(ssl)
106
+ ssl[:verify_mode] || begin
107
+ if ssl.fetch(:verify, true)
108
+ OpenSSL::SSL::VERIFY_PEER
109
+ else
110
+ OpenSSL::SSL::VERIFY_NONE
111
+ end
69
112
  end
70
113
  end
71
114
  end