avdi-faraday 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/Gemfile +27 -0
  2. data/LICENSE.md +20 -0
  3. data/README.md +250 -0
  4. data/Rakefile +87 -0
  5. data/config.ru +6 -0
  6. data/faraday.gemspec +86 -0
  7. data/lib/faraday.rb +276 -0
  8. data/lib/faraday/adapter.rb +71 -0
  9. data/lib/faraday/adapter/em_http.rb +217 -0
  10. data/lib/faraday/adapter/em_synchrony.rb +89 -0
  11. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
  12. data/lib/faraday/adapter/excon.rb +59 -0
  13. data/lib/faraday/adapter/httpclient.rb +92 -0
  14. data/lib/faraday/adapter/net_http.rb +116 -0
  15. data/lib/faraday/adapter/net_http_persistent.rb +37 -0
  16. data/lib/faraday/adapter/patron.rb +65 -0
  17. data/lib/faraday/adapter/rack.rb +57 -0
  18. data/lib/faraday/adapter/test.rb +162 -0
  19. data/lib/faraday/adapter/typhoeus.rb +107 -0
  20. data/lib/faraday/builder.rb +184 -0
  21. data/lib/faraday/connection.rb +468 -0
  22. data/lib/faraday/error.rb +40 -0
  23. data/lib/faraday/middleware.rb +41 -0
  24. data/lib/faraday/request.rb +101 -0
  25. data/lib/faraday/request/authorization.rb +40 -0
  26. data/lib/faraday/request/basic_authentication.rb +13 -0
  27. data/lib/faraday/request/multipart.rb +62 -0
  28. data/lib/faraday/request/retry.rb +67 -0
  29. data/lib/faraday/request/token_authentication.rb +15 -0
  30. data/lib/faraday/request/url_encoded.rb +35 -0
  31. data/lib/faraday/response.rb +99 -0
  32. data/lib/faraday/response/logger.rb +34 -0
  33. data/lib/faraday/response/raise_error.rb +16 -0
  34. data/lib/faraday/upload_io.rb +23 -0
  35. data/lib/faraday/utils.rb +274 -0
  36. data/script/test +91 -0
  37. data/test/adapters/default_test.rb +14 -0
  38. data/test/adapters/em_http_test.rb +19 -0
  39. data/test/adapters/em_synchrony_test.rb +20 -0
  40. data/test/adapters/excon_test.rb +15 -0
  41. data/test/adapters/httpclient_test.rb +16 -0
  42. data/test/adapters/integration.rb +193 -0
  43. data/test/adapters/logger_test.rb +37 -0
  44. data/test/adapters/net_http_persistent_test.rb +11 -0
  45. data/test/adapters/net_http_test.rb +49 -0
  46. data/test/adapters/patron_test.rb +17 -0
  47. data/test/adapters/rack_test.rb +26 -0
  48. data/test/adapters/test_middleware_test.rb +70 -0
  49. data/test/adapters/typhoeus_test.rb +20 -0
  50. data/test/authentication_middleware_test.rb +65 -0
  51. data/test/connection_test.rb +375 -0
  52. data/test/env_test.rb +183 -0
  53. data/test/helper.rb +75 -0
  54. data/test/live_server.rb +57 -0
  55. data/test/middleware/retry_test.rb +62 -0
  56. data/test/middleware_stack_test.rb +203 -0
  57. data/test/middleware_test.rb +12 -0
  58. data/test/request_middleware_test.rb +108 -0
  59. data/test/response_middleware_test.rb +74 -0
  60. metadata +182 -0
@@ -0,0 +1,89 @@
1
+ require 'uri'
2
+
3
+ module Faraday
4
+ class Adapter
5
+ class EMSynchrony < Faraday::Adapter
6
+ include EMHttp::Options
7
+
8
+ dependency do
9
+ require 'em-synchrony/em-http'
10
+ require 'em-synchrony/em-multi'
11
+ require 'fiber'
12
+ end
13
+
14
+ self.supports_parallel = true
15
+
16
+ def self.setup_parallel_manager(options = {})
17
+ ParallelManager.new
18
+ end
19
+
20
+ def call(env)
21
+ super
22
+ request = EventMachine::HttpRequest.new(URI::parse(env[:url].to_s), connection_config(env))
23
+
24
+ http_method = env[:method].to_s.downcase.to_sym
25
+
26
+ # Queue requests for parallel execution.
27
+ if env[:parallel_manager]
28
+ env[:parallel_manager].add(request, http_method, request_config(env)) do |resp|
29
+ save_response(env, resp.response_header.status, resp.response) do |resp_headers|
30
+ resp.response_header.each do |name, value|
31
+ resp_headers[name.to_sym] = value
32
+ end
33
+ end
34
+
35
+ # Finalize the response object with values from `env`.
36
+ env[:response].finish(env)
37
+ end
38
+
39
+ # Execute single request.
40
+ else
41
+ client = nil
42
+ block = lambda { request.send(http_method, request_config(env)) }
43
+
44
+ if !EM.reactor_running?
45
+ EM.run do
46
+ Fiber.new {
47
+ client = block.call
48
+ EM.stop
49
+ }.resume
50
+ end
51
+ else
52
+ client = block.call
53
+ end
54
+
55
+ save_response(env, client.response_header.status, client.response) do |resp_headers|
56
+ client.response_header.each do |name, value|
57
+ resp_headers[name.to_sym] = value
58
+ end
59
+ end
60
+ end
61
+
62
+ @app.call env
63
+ rescue Errno::ECONNREFUSED
64
+ raise Error::ConnectionFailed, $!
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ require 'faraday/adapter/em_synchrony/parallel_manager'
71
+
72
+ # add missing patch(), options() methods
73
+ EventMachine::HTTPMethods.module_eval do
74
+ ([:patch, :options] - instance_methods).each do |type|
75
+ module_eval %[
76
+ def #{type}(options = {}, &blk)
77
+ f = Fiber.current
78
+ conn = setup_request(:#{type}, options, &blk)
79
+ if conn.error.nil?
80
+ conn.callback { f.resume(conn) }
81
+ conn.errback { f.resume(conn) }
82
+ Fiber.yield
83
+ else
84
+ conn
85
+ end
86
+ end
87
+ ]
88
+ end
89
+ 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
@@ -0,0 +1,59 @@
1
+ module Faraday
2
+ class Adapter
3
+ class Excon < Faraday::Adapter
4
+ dependency 'excon'
5
+
6
+ def initialize(app, connection_options = {})
7
+ @connection_options = connection_options
8
+ super(app)
9
+ end
10
+
11
+ def call(env)
12
+ super
13
+
14
+ opts = {}
15
+ if env[:url].scheme == 'https' && ssl = env[:ssl]
16
+ opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true)
17
+ opts[:ssl_ca_path] = ssl[:ca_file] if ssl[:ca_file]
18
+ end
19
+
20
+ if ( req = env[:request] )
21
+ if req[:timeout]
22
+ opts[:read_timeout] = req[:timeout]
23
+ opts[:connect_timeout] = req[:timeout]
24
+ opts[:write_timeout] = req[:timeout]
25
+ end
26
+
27
+ if req[:open_timeout]
28
+ opts[:connect_timeout] = req[:open_timeout]
29
+ opts[:write_timeout] = req[:open_timeout]
30
+ end
31
+ end
32
+
33
+ conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
34
+
35
+ resp = conn.request \
36
+ :method => env[:method].to_s.upcase,
37
+ :headers => env[:request_headers],
38
+ :body => read_body(env)
39
+
40
+ save_response(env, resp.status.to_i, resp.body, resp.headers)
41
+
42
+ @app.call env
43
+ rescue ::Excon::Errors::SocketError => err
44
+ if err.message =~ /\btimeout\b/
45
+ raise Error::TimeoutError, err
46
+ else
47
+ raise Error::ConnectionFailed, err
48
+ end
49
+ rescue ::Excon::Errors::Timeout => err
50
+ raise Error::TimeoutError, err
51
+ end
52
+
53
+ # TODO: support streaming requests
54
+ def read_body(env)
55
+ env[:body].respond_to?(:read) ? env[:body].read : env[:body]
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,92 @@
1
+ module Faraday
2
+ class Adapter
3
+ class HTTPClient < Faraday::Adapter
4
+ dependency 'httpclient'
5
+
6
+ def client
7
+ @client ||= ::HTTPClient.new
8
+ end
9
+
10
+ def call(env)
11
+ super
12
+
13
+ if req = env[:request]
14
+ if proxy = req[:proxy]
15
+ configure_proxy proxy
16
+ end
17
+
18
+ if bind = req[:bind]
19
+ configure_socket bind
20
+ end
21
+
22
+ configure_timeouts req
23
+ end
24
+
25
+ if env[:url].scheme == 'https' && ssl = env[:ssl]
26
+ configure_ssl ssl
27
+ end
28
+
29
+ # TODO Don't stream yet.
30
+ # https://github.com/nahi/httpclient/pull/90
31
+ env[:body] = env[:body].read if env[:body].respond_to? :read
32
+
33
+ resp = client.request env[:method], env[:url],
34
+ :body => env[:body],
35
+ :header => env[:request_headers]
36
+
37
+ save_response env, resp.status, resp.body, resp.headers
38
+
39
+ @app.call env
40
+ rescue ::HTTPClient::TimeoutError
41
+ raise Faraday::Error::TimeoutError, $!
42
+ end
43
+
44
+ def configure_socket(bind)
45
+ client.socket_local.host = bind[:host]
46
+ client.socket_local.port = bind[:port]
47
+ end
48
+
49
+ def configure_proxy(proxy)
50
+ client.proxy = proxy[:uri]
51
+ if proxy[:user] && proxy[:password]
52
+ client.set_proxy_auth proxy[:user], proxy[:password]
53
+ end
54
+ end
55
+
56
+ def configure_ssl(ssl)
57
+ ssl_config = client.ssl_config
58
+
59
+ ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file]
60
+ ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path]
61
+ ssl_config.cert_store = ssl[:cert_store] if ssl[:cert_store]
62
+ ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert]
63
+ ssl_config.client_key = ssl[:client_key] if ssl[:client_key]
64
+ ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
65
+ ssl_config.verify_mode = ssl_verify_mode(ssl)
66
+ end
67
+
68
+ def configure_timeouts(req)
69
+ if req[:timeout]
70
+ client.connect_timeout = req[:timeout]
71
+ client.receive_timeout = req[:timeout]
72
+ client.send_timeout = req[:timeout]
73
+ end
74
+
75
+ if req[:open_timeout]
76
+ client.connect_timeout = req[:open_timeout]
77
+ client.send_timeout = req[:open_timeout]
78
+ end
79
+ end
80
+
81
+ def ssl_verify_mode(ssl)
82
+ ssl[:verify_mode] || begin
83
+ if ssl.fetch(:verify, true)
84
+ OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
85
+ else
86
+ OpenSSL::SSL::VERIFY_NONE
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,116 @@
1
+ begin
2
+ require 'net/https'
3
+ rescue LoadError
4
+ warn "Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support"
5
+ require 'net/http'
6
+ end
7
+
8
+ module Faraday
9
+ class Adapter
10
+ class NetHttp < Faraday::Adapter
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
+ ]
22
+
23
+ NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
24
+
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]
29
+
30
+ req = env[:request]
31
+ http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
32
+ http.open_timeout = req[:open_timeout] if req[:open_timeout]
33
+
34
+ begin
35
+ http_response = perform_request(http, env)
36
+ rescue *NET_HTTP_EXCEPTIONS
37
+ raise Error::ConnectionFailed, $!
38
+ end
39
+
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
44
+ end
45
+
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
74
+ end
75
+
76
+ def net_http_connection(env)
77
+ if proxy = env[:request][:proxy]
78
+ Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
79
+ else
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
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,37 @@
1
+ require 'faraday/adapter/net_http'
2
+
3
+ module Faraday
4
+ class Adapter
5
+ # Experimental adapter for net-http-persistent
6
+ class NetHttpPersistent < NetHttp
7
+ dependency 'net/http/persistent'
8
+
9
+ # TODO: investigate is it safe to create a new Persistent instance for
10
+ # every request, or does it defy the purpose of persistent connections
11
+ def net_http_connection(env)
12
+ Net::HTTP::Persistent.new 'Faraday',
13
+ env[:request][:proxy] ? env[:request][:proxy][:uri] : nil
14
+ end
15
+
16
+ def perform_request(http, env)
17
+ http.request env[:url], create_request(env)
18
+ rescue Net::HTTP::Persistent::Error => error
19
+ if error.message.include? 'Timeout::Error'
20
+ raise Faraday::Error::TimeoutError, error
21
+ else
22
+ raise
23
+ end
24
+ end
25
+
26
+ def configure_ssl(http, ssl)
27
+ http.verify_mode = ssl_verify_mode(ssl)
28
+ http.cert_store = ssl_cert_store(ssl)
29
+
30
+ http.certificate = ssl[:client_cert] if ssl[:client_cert]
31
+ http.private_key = ssl[:client_key] if ssl[:client_key]
32
+ http.ca_file = ssl[:ca_file] if ssl[:ca_file]
33
+ http.ssl_version = ssl[:version] if ssl[:version]
34
+ end
35
+ end
36
+ end
37
+ end