faraday 0.9.0.rc5 → 0.9.0.rc6

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 (45) hide show
  1. data/Gemfile +6 -5
  2. data/README.md +0 -22
  3. data/faraday.gemspec +2 -2
  4. data/lib/faraday.rb +6 -2
  5. data/lib/faraday/adapter/em_http.rb +34 -14
  6. data/lib/faraday/adapter/em_http_ssl_patch.rb +56 -0
  7. data/lib/faraday/adapter/em_synchrony.rb +21 -20
  8. data/lib/faraday/adapter/excon.rb +16 -0
  9. data/lib/faraday/adapter/httpclient.rb +14 -0
  10. data/lib/faraday/adapter/net_http.rb +6 -2
  11. data/lib/faraday/adapter/net_http_persistent.rb +15 -3
  12. data/lib/faraday/adapter/patron.rb +13 -11
  13. data/lib/faraday/adapter/typhoeus.rb +11 -0
  14. data/lib/faraday/autoload.rb +2 -4
  15. data/lib/faraday/connection.rb +30 -3
  16. data/lib/faraday/error.rb +4 -1
  17. data/lib/faraday/options.rb +117 -23
  18. data/lib/faraday/request/instrumentation.rb +1 -3
  19. data/lib/faraday/request/multipart.rb +1 -1
  20. data/lib/faraday/request/retry.rb +38 -9
  21. data/lib/faraday/response.rb +1 -2
  22. data/lib/faraday/response/raise_error.rb +3 -0
  23. data/lib/faraday/utils.rb +10 -4
  24. data/script/proxy-server +42 -0
  25. data/script/server +1 -3
  26. data/script/test +35 -7
  27. data/test/adapters/excon_test.rb +4 -0
  28. data/test/adapters/httpclient_test.rb +5 -0
  29. data/test/adapters/integration.rb +48 -2
  30. data/test/adapters/net_http_persistent_test.rb +10 -1
  31. data/test/adapters/patron_test.rb +3 -0
  32. data/test/adapters/rack_test.rb +5 -0
  33. data/test/adapters/typhoeus_test.rb +3 -13
  34. data/test/authentication_middleware_test.rb +6 -6
  35. data/test/connection_test.rb +123 -49
  36. data/test/env_test.rb +19 -1
  37. data/test/helper.rb +2 -4
  38. data/test/live_server.rb +4 -2
  39. data/test/middleware/instrumentation_test.rb +13 -0
  40. data/test/middleware/retry_test.rb +47 -0
  41. data/test/multibyte.txt +1 -0
  42. data/test/options_test.rb +93 -17
  43. data/test/request_middleware_test.rb +6 -6
  44. data/test/utils_test.rb +34 -13
  45. metadata +69 -44
data/Gemfile CHANGED
@@ -1,17 +1,18 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'ffi-ncurses', '~> 0.3', :platforms => :jruby
4
- gem 'jruby-openssl', '~> 0.7', :platforms => :jruby
4
+ gem 'jruby-openssl', '~> 0.8.8', :platforms => :jruby
5
5
  gem 'rake'
6
6
 
7
7
  group :test do
8
8
  gem 'coveralls', :require => false
9
- gem 'em-http-request', '>= 1.0', :require => 'em-http'
10
- gem 'em-synchrony', '>= 1.0', :require => ['em-synchrony', 'em-synchrony/em-http']
11
- gem 'excon', '>= 0.16.1'
9
+ gem 'em-http-request', '>= 1.1', :require => 'em-http'
10
+ gem 'em-synchrony', '>= 1.0.3', :require => ['em-synchrony', 'em-synchrony/em-http']
11
+ gem 'excon', ['>= 0.25.3', '< 0.27.3']
12
12
  gem 'httpclient', '>= 2.2'
13
13
  gem 'leftright', '>= 0.9', :require => false
14
- gem 'minitest', '>= 4.3'
14
+ gem 'mime-types', '~> 1.25', :platforms => :ruby_18
15
+ gem 'minitest', '~> 5.0.5'
15
16
  gem 'net-http-persistent', '>= 2.5', :require => false
16
17
  gem 'patron', '>= 0.4.2', :platforms => :ruby
17
18
  gem 'rack-test', '>= 0.6', :require => 'rack/test'
data/README.md CHANGED
@@ -24,17 +24,6 @@ conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
24
24
  faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
25
25
  end
26
26
 
27
- # set proxy with string
28
- conn.options.proxy = "http://user:password@example.org/"
29
-
30
- # set proxy with hash
31
- conn.options.proxy = { :uri => 'http://user:passwordexample.org' }
32
-
33
- # specify proxy user/pass
34
- conn.options.proxy = { :uri => 'http://user:pass.org',
35
- :user => 'user',
36
- :password => 'pass' }
37
-
38
27
  ## GET ##
39
28
 
40
29
  response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json
@@ -64,17 +53,6 @@ conn.get do |req|
64
53
  req.url '/search'
65
54
  req.options.timeout = 5 # open/read timeout in seconds
66
55
  req.options.open_timeout = 2 # connection open timeout in seconds
67
-
68
- # set proxy with string
69
- req.options.proxy = "http://user:password@example.org/"
70
-
71
- # set proxy with hash
72
- req.options.proxy = { :uri => 'http://user:passwordexample.org' }
73
-
74
- # specify proxy user/pass
75
- req.options.proxy = { :uri => 'http://user:pass.org',
76
- :user => 'user',
77
- :password => 'pass' }
78
56
  end
79
57
  ```
80
58
 
@@ -17,13 +17,13 @@ Gem::Specification.new do |spec|
17
17
  spec.homepage = 'https://github.com/lostisland/faraday'
18
18
  spec.licenses = ['MIT']
19
19
 
20
- spec.add_dependency 'multipart-post', '~> 1.1'
20
+ spec.add_dependency 'multipart-post', '~> 1.2.0'
21
21
  spec.add_development_dependency 'bundler', '~> 1.0'
22
22
 
23
23
  spec.files = %w(.document CHANGELOG.md CONTRIBUTING.md Gemfile LICENSE.md README.md Rakefile)
24
24
  spec.files << "#{lib}.gemspec"
25
25
  spec.files += Dir.glob("lib/**/*.rb")
26
- spec.files += Dir.glob("test/**/*.rb")
26
+ spec.files += Dir.glob("test/**/*.{rb,txt}")
27
27
  spec.files += Dir.glob("script/*")
28
28
 
29
29
  dev_null = File.exist?('/dev/null') ? '/dev/null' : 'NUL'
@@ -14,7 +14,7 @@ require 'forwardable'
14
14
  # conn.get '/'
15
15
  #
16
16
  module Faraday
17
- VERSION = "0.9.0.rc5"
17
+ VERSION = "0.9.0.rc6"
18
18
 
19
19
  class << self
20
20
  # Public: Gets or sets the root path that Faraday is being loaded from.
@@ -26,7 +26,7 @@ module Faraday
26
26
 
27
27
  # Public: Gets or sets the Symbol key identifying a default Adapter to use
28
28
  # for the default Faraday::Connection.
29
- attr_accessor :default_adapter
29
+ attr_reader :default_adapter
30
30
 
31
31
  # Public: Sets the default Faraday::Connection for simple scripts that
32
32
  # access the Faraday constant directly.
@@ -238,6 +238,10 @@ module Faraday
238
238
 
239
239
  require_libs "utils", "options", "connection", "rack_builder", "parameters",
240
240
  "middleware", "adapter", "request", "response", "upload_io", "error"
241
+
242
+ if !ENV["FARADAY_NO_AUTOLOAD"]
243
+ require_lib 'autoload'
244
+ end
241
245
  end
242
246
 
243
247
  # not pulling in active-support JUST for this method. And I love this method.
@@ -7,10 +7,10 @@ module Faraday
7
7
  module Options
8
8
  def connection_config(env)
9
9
  options = {}
10
- configure_ssl(options, env)
11
10
  configure_proxy(options, env)
12
11
  configure_timeout(options, env)
13
12
  configure_socket(options, env)
13
+ configure_ssl(options, env)
14
14
  options
15
15
  end
16
16
 
@@ -22,9 +22,6 @@ module Faraday
22
22
  # :file => 'path/to/file', # stream data off disk
23
23
  }
24
24
  configure_compression(options, env)
25
- # configure_proxy_auth
26
- # :proxy => {:authorization => [user, pass]}
27
- # proxy[:username] && proxy[:password]
28
25
  options
29
26
  end
30
27
 
@@ -33,20 +30,12 @@ module Faraday
33
30
  body.respond_to?(:read) ? body.read : body
34
31
  end
35
32
 
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
-
45
33
  def configure_proxy(options, env)
46
34
  if proxy = request_options(env)[:proxy]
47
35
  options[:proxy] = {
48
36
  :host => proxy[:uri].host,
49
- :port => proxy[:uri].port
37
+ :port => proxy[:uri].port,
38
+ :authorization => [proxy[:user], proxy[:password]]
50
39
  }
51
40
  end
52
41
  end
@@ -60,6 +49,15 @@ module Faraday
60
49
  end
61
50
  end
62
51
 
52
+ def configure_ssl(options, env)
53
+ if env[:url].scheme == 'https' && env[:ssl]
54
+ options[:ssl] = {
55
+ :cert_chain_file => env[:ssl][:ca_file],
56
+ :verify_peer => env[:ssl].fetch(:verify, true)
57
+ }
58
+ end
59
+ end
60
+
63
61
  def configure_timeout(options, env)
64
62
  timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout)
65
63
  options[:connect_timeout] = options[:inactivity_timeout] = timeout
@@ -124,6 +122,18 @@ module Faraday
124
122
  }
125
123
  end
126
124
  end
125
+ rescue EventMachine::Connectify::CONNECTError => err
126
+ if err.message.include?("Proxy Authentication Required")
127
+ raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
128
+ else
129
+ raise Error::ConnectionFailed, err
130
+ end
131
+ rescue => err
132
+ if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
133
+ raise Faraday::SSLError, err
134
+ else
135
+ raise
136
+ end
127
137
  end
128
138
 
129
139
  # TODO: reuse the connection to support pipelining
@@ -150,6 +160,8 @@ module Faraday
150
160
  elsif msg == Errno::ECONNREFUSED
151
161
  errklass = Faraday::Error::ConnectionFailed
152
162
  msg = "connection refused"
163
+ elsif msg == "connection closed by server"
164
+ errklass = Faraday::Error::ConnectionFailed
153
165
  end
154
166
  raise errklass, msg
155
167
  end
@@ -215,3 +227,11 @@ module Faraday
215
227
  end
216
228
  end
217
229
  end
230
+
231
+ begin
232
+ require 'openssl'
233
+ rescue LoadError
234
+ warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support"
235
+ else
236
+ require 'faraday/adapter/em_http_ssl_patch'
237
+ end if Faraday::Adapter::EMHttp.loaded?
@@ -0,0 +1,56 @@
1
+ require 'openssl'
2
+ require 'em-http'
3
+
4
+ module EmHttpSslPatch
5
+ def ssl_verify_peer(cert_string)
6
+ cert = nil
7
+ begin
8
+ cert = OpenSSL::X509::Certificate.new(cert_string)
9
+ rescue OpenSSL::X509::CertificateError
10
+ return false
11
+ end
12
+
13
+ @last_seen_cert = cert
14
+
15
+ if certificate_store.verify(@last_seen_cert)
16
+ begin
17
+ certificate_store.add_cert(@last_seen_cert)
18
+ rescue OpenSSL::X509::StoreError => e
19
+ raise e unless e.message == 'cert already in hash table'
20
+ end
21
+ true
22
+ else
23
+ raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}"))
24
+ end
25
+ end
26
+
27
+ def ssl_handshake_completed
28
+ return true unless verify_peer?
29
+
30
+ unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
31
+ raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate))
32
+ else
33
+ true
34
+ end
35
+ end
36
+
37
+ def verify_peer?
38
+ parent.connopts.tls[:verify_peer]
39
+ end
40
+
41
+ def host
42
+ parent.connopts.host
43
+ end
44
+
45
+ def certificate_store
46
+ @certificate_store ||= begin
47
+ store = OpenSSL::X509::Store.new
48
+ store.set_default_paths
49
+ ca_file = parent.connopts.tls[:cert_chain_file]
50
+ store.add_file(ca_file) if ca_file
51
+ store
52
+ end
53
+ end
54
+ end
55
+
56
+ EventMachine::HttpStubConnection.send(:include, EmHttpSslPatch)
@@ -52,6 +52,8 @@ module Faraday
52
52
  client = block.call
53
53
  end
54
54
 
55
+ raise client.error if client.error
56
+
55
57
  save_response(env, client.response_header.status, client.response) do |resp_headers|
56
58
  client.response_header.each do |name, value|
57
59
  resp_headers[name.to_sym] = value
@@ -62,6 +64,18 @@ module Faraday
62
64
  @app.call env
63
65
  rescue Errno::ECONNREFUSED
64
66
  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 => err
74
+ if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
75
+ raise Faraday::SSLError, err
76
+ else
77
+ raise
78
+ end
65
79
  end
66
80
  end
67
81
  end
@@ -69,23 +83,10 @@ end
69
83
 
70
84
  require 'faraday/adapter/em_synchrony/parallel_manager'
71
85
 
72
- # add missing patch(), options() methods
73
- EventMachine::HTTPMethods.module_eval do
74
- [:patch, :options].each do |type|
75
- next if method_defined? :"a#{type}"
76
- alias_method :"a#{type}", type if method_defined? type
77
- module_eval %[
78
- def #{type}(options = {}, &blk)
79
- f = Fiber.current
80
- conn = setup_request(:#{type}, options, &blk)
81
- if conn.error.nil?
82
- conn.callback { f.resume(conn) }
83
- conn.errback { f.resume(conn) }
84
- Fiber.yield
85
- else
86
- conn
87
- end
88
- end
89
- ]
90
- end
91
- end
86
+ begin
87
+ require 'openssl'
88
+ rescue LoadError
89
+ warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support"
90
+ else
91
+ require 'faraday/adapter/em_http_ssl_patch'
92
+ end if Faraday::Adapter::EMSynchrony.loaded?
@@ -16,6 +16,10 @@ module Faraday
16
16
  opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true)
17
17
  opts[:ssl_ca_path] = ssl[:ca_path] if ssl[:ca_path]
18
18
  opts[:ssl_ca_file] = ssl[:ca_file] if ssl[:ca_file]
19
+ opts[:client_cert] = ssl[:client_cert] if ssl[:client_cert]
20
+ opts[:client_key] = ssl[:client_key] if ssl[:client_key]
21
+ opts[:certificate] = ssl[:certificate] if ssl[:certificate]
22
+ opts[:private_key] = ssl[:private_key] if ssl[:private_key]
19
23
 
20
24
  # https://github.com/geemus/excon/issues/106
21
25
  # https://github.com/jruby/jruby-ossl/issues/19
@@ -33,6 +37,16 @@ module Faraday
33
37
  opts[:connect_timeout] = req[:open_timeout]
34
38
  opts[:write_timeout] = req[:open_timeout]
35
39
  end
40
+
41
+ if req[:proxy]
42
+ opts[:proxy] = {
43
+ :host => req[:proxy][:uri].host,
44
+ :port => req[:proxy][:uri].port,
45
+ :scheme => req[:proxy][:uri].scheme,
46
+ :user => req[:proxy][:user],
47
+ :password => req[:proxy][:password]
48
+ }
49
+ end
36
50
  end
37
51
 
38
52
  conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
@@ -48,6 +62,8 @@ module Faraday
48
62
  rescue ::Excon::Errors::SocketError => err
49
63
  if err.message =~ /\btimeout\b/
50
64
  raise Error::TimeoutError, err
65
+ elsif err.message =~ /\bcertificate\b/
66
+ raise Faraday::SSLError, err
51
67
  else
52
68
  raise Error::ConnectionFailed, err
53
69
  end
@@ -39,6 +39,20 @@ module Faraday
39
39
  @app.call env
40
40
  rescue ::HTTPClient::TimeoutError
41
41
  raise Faraday::Error::TimeoutError, $!
42
+ rescue ::HTTPClient::BadResponseError => err
43
+ if err.message.include?('status 407')
44
+ raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
45
+ else
46
+ raise Faraday::Error::ClientError, $!
47
+ end
48
+ rescue Errno::ECONNREFUSED, EOFError
49
+ raise Faraday::Error::ConnectionFailed, $!
50
+ rescue => err
51
+ if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
52
+ raise Faraday::SSLError, err
53
+ else
54
+ raise
55
+ end
42
56
  end
43
57
 
44
58
  def configure_socket(bind)
@@ -36,8 +36,12 @@ module Faraday
36
36
 
37
37
  begin
38
38
  http_response = perform_request(http, env)
39
- rescue *NET_HTTP_EXCEPTIONS
40
- raise Error::ConnectionFailed, $!
39
+ rescue *NET_HTTP_EXCEPTIONS => err
40
+ if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
41
+ raise Faraday::SSLError, err
42
+ else
43
+ raise Error::ConnectionFailed, err
44
+ end
41
45
  end
42
46
 
43
47
  save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers|
@@ -1,4 +1,6 @@
1
- require 'faraday/adapter/net_http'
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'
2
4
 
3
5
  module Faraday
4
6
  class Adapter
@@ -7,8 +9,16 @@ module Faraday
7
9
  dependency 'net/http/persistent'
8
10
 
9
11
  def net_http_connection(env)
10
- Net::HTTP::Persistent.new 'Faraday',
11
- env[:request][:proxy] ? env[:request][:proxy][:uri] : nil
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
12
22
  end
13
23
 
14
24
  def perform_request(http, env)
@@ -16,6 +26,8 @@ module Faraday
16
26
  rescue Net::HTTP::Persistent::Error => error
17
27
  if error.message.include? 'Timeout'
18
28
  raise Faraday::Error::TimeoutError, error
29
+ elsif error.message.include? 'connection refused'
30
+ raise Faraday::Error::ConnectionFailed, error
19
31
  else
20
32
  raise
21
33
  end
@@ -5,7 +5,7 @@ module Faraday
5
5
 
6
6
  def initialize(app, &block)
7
7
  super(app)
8
- @block = block if block_given?
8
+ @block = block
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
- session.proxy = proxy[:uri].to_s
25
- if proxy[:user] && proxy[:password]
26
- prepend_proxy_auth_string(proxy, session)
27
- end
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
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
34
+ rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
35
35
  raise Error::ConnectionFailed, $!
36
36
  end
37
37
 
@@ -40,6 +40,12 @@ 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
43
49
  end
44
50
 
45
51
  if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
@@ -58,9 +64,5 @@ module Faraday
58
64
  session
59
65
  end
60
66
  end
61
-
62
- def prepend_proxy_auth_string(proxy, session)
63
- session.proxy.insert(7, "#{proxy[:user]}:#{proxy[:password]}@")
64
- end
65
67
  end
66
68
  end