faraday 0.8.11 → 0.9.0.rc1

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 (70) hide show
  1. data/.document +6 -0
  2. data/CONTRIBUTING.md +36 -0
  3. data/Gemfile +7 -6
  4. data/LICENSE.md +1 -1
  5. data/README.md +38 -51
  6. data/Rakefile +2 -18
  7. data/faraday.gemspec +34 -0
  8. data/lib/faraday.rb +181 -67
  9. data/lib/faraday/adapter.rb +19 -34
  10. data/lib/faraday/adapter/em_http.rb +24 -10
  11. data/lib/faraday/adapter/em_synchrony.rb +1 -15
  12. data/lib/faraday/adapter/excon.rb +6 -12
  13. data/lib/faraday/adapter/httpclient.rb +92 -0
  14. data/lib/faraday/adapter/net_http.rb +2 -3
  15. data/lib/faraday/adapter/net_http_persistent.rb +3 -15
  16. data/lib/faraday/adapter/patron.rb +13 -21
  17. data/lib/faraday/adapter/rack.rb +0 -2
  18. data/lib/faraday/adapter/test.rb +35 -36
  19. data/lib/faraday/adapter/typhoeus.rb +10 -12
  20. data/lib/faraday/autoload.rb +87 -0
  21. data/lib/faraday/connection.rb +196 -99
  22. data/lib/faraday/error.rb +33 -33
  23. data/lib/faraday/options.rb +215 -0
  24. data/lib/faraday/parameters.rb +193 -0
  25. data/lib/faraday/{builder.rb → rack_builder.rb} +78 -21
  26. data/lib/faraday/request.rb +12 -25
  27. data/lib/faraday/request/authorization.rb +3 -3
  28. data/lib/faraday/request/basic_authentication.rb +1 -1
  29. data/lib/faraday/request/instrumentation.rb +38 -0
  30. data/lib/faraday/request/multipart.rb +10 -9
  31. data/lib/faraday/request/retry.rb +70 -6
  32. data/lib/faraday/request/token_authentication.rb +2 -2
  33. data/lib/faraday/request/url_encoded.rb +7 -6
  34. data/lib/faraday/response.rb +17 -22
  35. data/lib/faraday/response/logger.rb +4 -4
  36. data/lib/faraday/response/raise_error.rb +4 -5
  37. data/lib/faraday/utils.rb +54 -67
  38. data/script/console +7 -0
  39. data/script/release +6 -3
  40. data/script/server +3 -1
  41. data/script/test +7 -33
  42. data/test/adapters/em_http_test.rb +6 -1
  43. data/test/adapters/em_synchrony_test.rb +7 -1
  44. data/test/adapters/excon_test.rb +0 -7
  45. data/test/adapters/httpclient_test.rb +16 -0
  46. data/test/adapters/integration.rb +8 -39
  47. data/test/adapters/logger_test.rb +1 -1
  48. data/test/adapters/net_http_test.rb +0 -31
  49. data/test/adapters/patron_test.rb +1 -1
  50. data/test/adapters/rack_test.rb +0 -5
  51. data/test/adapters/test_middleware_test.rb +19 -4
  52. data/test/adapters/typhoeus_test.rb +20 -3
  53. data/test/authentication_middleware_test.rb +7 -7
  54. data/test/connection_test.rb +52 -75
  55. data/test/env_test.rb +33 -24
  56. data/test/helper.rb +15 -13
  57. data/test/live_server.rb +10 -4
  58. data/test/middleware/instrumentation_test.rb +75 -0
  59. data/test/middleware/retry_test.rb +44 -38
  60. data/test/middleware_stack_test.rb +12 -11
  61. data/test/options_test.rb +126 -0
  62. data/test/request_middleware_test.rb +17 -7
  63. data/test/response_middleware_test.rb +2 -4
  64. data/test/strawberry.rb +2 -0
  65. metadata +82 -28
  66. checksums.yaml +0 -7
  67. data/script/proxy-server +0 -41
  68. data/test/multibyte.txt +0 -1
  69. data/test/parameters_test.rb +0 -24
  70. data/test/utils_test.rb +0 -30
@@ -1,32 +1,22 @@
1
1
  module Faraday
2
+ # Public: This is a base class for all Faraday adapters. Adapters are
3
+ # responsible for fulfilling a Faraday request.
2
4
  class Adapter < Middleware
3
5
  CONTENT_LENGTH = 'Content-Length'.freeze
4
6
 
5
- extend AutoloadHelper
6
- extend MiddlewareRegistry
7
-
8
- autoload_all 'faraday/adapter',
9
- :NetHttp => 'net_http',
10
- :NetHttpPersistent => 'net_http_persistent',
11
- :Typhoeus => 'typhoeus',
12
- :EMSynchrony => 'em_synchrony',
13
- :EMHttp => 'em_http',
14
- :Patron => 'patron',
15
- :Excon => 'excon',
16
- :Test => 'test',
17
- :Rack => 'rack'
18
-
19
- register_middleware \
20
- :test => :Test,
21
- :net_http => :NetHttp,
22
- :net_http_persistent => :NetHttpPersistent,
23
- :typhoeus => :Typhoeus,
24
- :patron => :Patron,
25
- :em_synchrony => :EMSynchrony,
26
- :em_http => :EMHttp,
27
- :excon => :Excon,
28
- :rack => :Rack
29
-
7
+ register_middleware File.expand_path('../adapter', __FILE__),
8
+ :test => [:Test, 'test'],
9
+ :net_http => [:NetHttp, 'net_http'],
10
+ :net_http_persistent => [:NetHttpPersistent, 'net_http_persistent'],
11
+ :typhoeus => [:Typhoeus, 'typhoeus'],
12
+ :patron => [:Patron, 'patron'],
13
+ :em_synchrony => [:EMSynchrony, 'em_synchrony'],
14
+ :em_http => [:EMHttp, 'em_http'],
15
+ :excon => [:Excon, 'excon'],
16
+ :rack => [:Rack, 'rack'],
17
+ :httpclient => [:HTTPClient, 'httpclient']
18
+
19
+ # Public: This module marks an Adapter as supporting parallel requests.
30
20
  module Parallelism
31
21
  attr_writer :supports_parallel
32
22
  def supports_parallel?() @supports_parallel end
@@ -41,18 +31,13 @@ module Faraday
41
31
  self.supports_parallel = false
42
32
 
43
33
  def call(env)
44
- if !env[:body] and Connection::METHODS_WITH_BODIES.include? env[:method]
45
- # play nice and indicate we're sending an empty body
46
- env[:request_headers][CONTENT_LENGTH] = "0"
47
- # Typhoeus hangs on PUT requests if body is nil
48
- env[:body] = ''
49
- end
34
+ env.clear_body if env.needs_body?
50
35
  end
51
36
 
52
37
  def save_response(env, status, body, headers = nil)
53
- env[:status] = status
54
- env[:body] = body
55
- env[:response_headers] = Utils::Headers.new.tap do |response_headers|
38
+ env.status = status
39
+ env.body = body
40
+ env.response_headers = Utils::Headers.new.tap do |response_headers|
56
41
  response_headers.update headers unless headers.nil?
57
42
  yield response_headers if block_given?
58
43
  end
@@ -7,8 +7,10 @@ module Faraday
7
7
  module Options
8
8
  def connection_config(env)
9
9
  options = {}
10
+ configure_ssl(options, env)
10
11
  configure_proxy(options, env)
11
12
  configure_timeout(options, env)
13
+ configure_socket(options, env)
12
14
  options
13
15
  end
14
16
 
@@ -20,6 +22,9 @@ module Faraday
20
22
  # :file => 'path/to/file', # stream data off disk
21
23
  }
22
24
  configure_compression(options, env)
25
+ # configure_proxy_auth
26
+ # :proxy => {:authorization => [user, pass]}
27
+ # proxy[:username] && proxy[:password]
23
28
  options
24
29
  end
25
30
 
@@ -28,12 +33,29 @@ module Faraday
28
33
  body.respond_to?(:read) ? body.read : body
29
34
  end
30
35
 
36
+ def configure_ssl(options, env)
37
+ if ssl = env[:ssl]
38
+ # :ssl => {
39
+ # :private_key_file => '/tmp/server.key',
40
+ # :cert_chain_file => '/tmp/server.crt',
41
+ # :verify_peer => false
42
+ end
43
+ end
44
+
31
45
  def configure_proxy(options, env)
32
46
  if proxy = request_options(env)[:proxy]
33
47
  options[:proxy] = {
34
48
  :host => proxy[:uri].host,
35
- :port => proxy[:uri].port,
36
- :authorization => [proxy[:user], proxy[:password]]
49
+ :port => proxy[:uri].port
50
+ }
51
+ end
52
+ end
53
+
54
+ def configure_socket(options, env)
55
+ if bind = request_options(env)[:bind]
56
+ options[:bind] = {
57
+ :host => bind[:host],
58
+ :port => bind[:port]
37
59
  }
38
60
  end
39
61
  end
@@ -102,12 +124,6 @@ module Faraday
102
124
  }
103
125
  end
104
126
  end
105
- rescue EventMachine::Connectify::CONNECTError => err
106
- if err.message.include?("Proxy Authentication Required")
107
- raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
108
- else
109
- raise Error::ConnectionFailed, err
110
- end
111
127
  end
112
128
 
113
129
  # TODO: reuse the connection to support pipelining
@@ -134,8 +150,6 @@ module Faraday
134
150
  elsif msg == Errno::ECONNREFUSED
135
151
  errklass = Faraday::Error::ConnectionFailed
136
152
  msg = "connection refused"
137
- elsif msg == "connection closed by server"
138
- errklass = Faraday::Error::ConnectionFailed
139
153
  end
140
154
  raise errklass, msg
141
155
  end
@@ -19,7 +19,7 @@ module Faraday
19
19
 
20
20
  def call(env)
21
21
  super
22
- request = EventMachine::HttpRequest.new(URI::parse(env[:url].to_s), connection_config(env)) # end
22
+ request = EventMachine::HttpRequest.new(URI::parse(env[:url].to_s), connection_config(env))
23
23
 
24
24
  http_method = env[:method].to_s.downcase.to_sym
25
25
 
@@ -52,8 +52,6 @@ module Faraday
52
52
  client = block.call
53
53
  end
54
54
 
55
- raise client.error if client.error
56
-
57
55
  save_response(env, client.response_header.status, client.response) do |resp_headers|
58
56
  client.response_header.each do |name, value|
59
57
  resp_headers[name.to_sym] = value
@@ -64,18 +62,6 @@ module Faraday
64
62
  @app.call env
65
63
  rescue Errno::ECONNREFUSED
66
64
  raise Error::ConnectionFailed, $!
67
- rescue EventMachine::Connectify::CONNECTError => err
68
- if err.message.include?("Proxy Authentication Required")
69
- raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
70
- else
71
- raise Error::ConnectionFailed, err
72
- end
73
- rescue RuntimeError => err
74
- if err.message == "connection closed by server"
75
- raise Error::ConnectionFailed, err
76
- else
77
- raise
78
- end
79
65
  end
80
66
  end
81
67
  end
@@ -3,6 +3,11 @@ module Faraday
3
3
  class Excon < Faraday::Adapter
4
4
  dependency 'excon'
5
5
 
6
+ def initialize(app, connection_options = {})
7
+ @connection_options = connection_options
8
+ super(app)
9
+ end
10
+
6
11
  def call(env)
7
12
  super
8
13
 
@@ -28,20 +33,9 @@ module Faraday
28
33
  opts[:connect_timeout] = req[:open_timeout]
29
34
  opts[:write_timeout] = req[:open_timeout]
30
35
  end
31
-
32
- if req[:proxy]
33
- opts[:proxy] = {
34
- :host => req[:proxy][:uri].host,
35
- :hostname => req[:proxy][:uri].hostname,
36
- :port => req[:proxy][:uri].port,
37
- :scheme => req[:proxy][:uri].scheme,
38
- :user => req[:proxy][:user],
39
- :password => req[:proxy][:password]
40
- }
41
- end
42
36
  end
43
37
 
44
- conn = ::Excon.new(env[:url].to_s, opts)
38
+ conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
45
39
 
46
40
  resp = conn.request \
47
41
  :method => env[:method].to_s.upcase,
@@ -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
@@ -24,7 +24,6 @@ module Faraday
24
24
  ]
25
25
 
26
26
  NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
27
- NET_HTTP_EXCEPTIONS << Net::OpenTimeout if defined?(Net::OpenTimeout)
28
27
 
29
28
  def call(env)
30
29
  super
@@ -41,7 +40,7 @@ module Faraday
41
40
  raise Error::ConnectionFailed, $!
42
41
  end
43
42
 
44
- save_response(env, http_response.code.to_i, http_response.body) do |response_headers|
43
+ save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers|
45
44
  http_response.each_header do |key, value|
46
45
  response_headers[key] = value
47
46
  end
@@ -82,7 +81,7 @@ module Faraday
82
81
  Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
83
82
  else
84
83
  Net::HTTP
85
- end.new(env[:url].host, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
84
+ end.new(env[:url].host, env[:url].port)
86
85
  end
87
86
 
88
87
  def configure_ssl(http, ssl)
@@ -1,6 +1,4 @@
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
+ require 'faraday/adapter/net_http'
4
2
 
5
3
  module Faraday
6
4
  class Adapter
@@ -9,16 +7,8 @@ module Faraday
9
7
  dependency 'net/http/persistent'
10
8
 
11
9
  def net_http_connection(env)
12
- if proxy = env[:request][:proxy]
13
- proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
14
- proxy_uri.user = proxy_uri.password = nil
15
- # awful patch for net-http-persistent 2.8 not unescaping user/password
16
- (class << proxy_uri; self; end).class_eval do
17
- define_method(:user) { proxy[:user] }
18
- define_method(:password) { proxy[:password] }
19
- end if proxy[:user]
20
- end
21
- Net::HTTP::Persistent.new 'Faraday', proxy_uri
10
+ Net::HTTP::Persistent.new 'Faraday',
11
+ env[:request][:proxy] ? env[:request][:proxy][:uri] : nil
22
12
  end
23
13
 
24
14
  def perform_request(http, env)
@@ -26,8 +16,6 @@ module Faraday
26
16
  rescue Net::HTTP::Persistent::Error => error
27
17
  if error.message.include? 'Timeout'
28
18
  raise Faraday::Error::TimeoutError, error
29
- elsif error.message.include? 'connection refused'
30
- raise Faraday::Error::ConnectionFailed, error
31
19
  else
32
20
  raise
33
21
  end
@@ -5,7 +5,7 @@ module Faraday
5
5
 
6
6
  def initialize(app, &block)
7
7
  super(app)
8
- @block = block
8
+ @block = block if block_given?
9
9
  end
10
10
 
11
11
  def call(env)
@@ -19,19 +19,19 @@ module Faraday
19
19
  if req = env[:request]
20
20
  session.timeout = session.connect_timeout = req[:timeout] if req[:timeout]
21
21
  session.connect_timeout = req[:open_timeout] if req[:open_timeout]
22
-
22
+
23
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
24
+ session.proxy = proxy[:uri].to_s
25
+ if proxy[:user] && proxy[:password]
26
+ prepend_proxy_auth_string(proxy, session)
27
+ end
28
28
  end
29
29
  end
30
30
 
31
31
  response = begin
32
32
  data = env[:body] ? env[:body].to_s : nil
33
33
  session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data)
34
- rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
34
+ rescue Errno::ECONNREFUSED
35
35
  raise Error::ConnectionFailed, $!
36
36
  end
37
37
 
@@ -40,26 +40,14 @@ module Faraday
40
40
  @app.call env
41
41
  rescue ::Patron::TimeoutError => err
42
42
  raise Faraday::Error::TimeoutError, err
43
- rescue ::Patron::Error => err
44
- if err.message.include?("code 407")
45
- raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
46
- else
47
- raise Error::ConnectionFailed, err
48
- end
49
43
  end
50
44
 
51
45
  if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
52
46
  # HAX: helps but doesn't work completely
53
47
  # https://github.com/toland/patron/issues/34
54
48
  ::Patron::Request::VALID_ACTIONS.tap do |actions|
55
- if actions[0].is_a?(Symbol)
56
- actions << :patch unless actions.include? :patch
57
- actions << :options unless actions.include? :options
58
- else
59
- # Patron 0.4.20 and up
60
- actions << "PATCH" unless actions.include? "PATCH"
61
- actions << "OPTIONS" unless actions.include? "OPTIONS"
62
- end
49
+ actions << :patch unless actions.include? :patch
50
+ actions << :options unless actions.include? :options
63
51
  end
64
52
  end
65
53
 
@@ -70,5 +58,9 @@ module Faraday
70
58
  session
71
59
  end
72
60
  end
61
+
62
+ def prepend_proxy_auth_string(proxy, session)
63
+ session.proxy.insert(7, "#{proxy[:user]}:#{proxy[:password]}@")
64
+ end
73
65
  end
74
66
  end
@@ -1,5 +1,3 @@
1
- require 'timeout'
2
-
3
1
  module Faraday
4
2
  class Adapter
5
3
  # Sends requests to a Rack app.