faraday 0.8.11 → 0.9.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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.