faraday 0.9.1 → 0.16.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 (98) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.md +1 -1
  3. data/README.md +30 -195
  4. data/lib/faraday/adapter/em_http.rb +148 -99
  5. data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
  6. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  7. data/lib/faraday/adapter/em_synchrony.rb +107 -49
  8. data/lib/faraday/adapter/excon.rb +102 -55
  9. data/lib/faraday/adapter/httpclient.rb +80 -36
  10. data/lib/faraday/adapter/net_http.rb +119 -44
  11. data/lib/faraday/adapter/net_http_persistent.rb +68 -27
  12. data/lib/faraday/adapter/patron.rb +76 -34
  13. data/lib/faraday/adapter/rack.rb +28 -12
  14. data/lib/faraday/adapter/test.rb +136 -52
  15. data/lib/faraday/adapter/typhoeus.rb +7 -115
  16. data/lib/faraday/adapter.rb +43 -20
  17. data/lib/faraday/adapter_registry.rb +28 -0
  18. data/lib/faraday/autoload.rb +47 -36
  19. data/lib/faraday/connection.rb +359 -165
  20. data/lib/faraday/dependency_loader.rb +37 -0
  21. data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
  22. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  23. data/lib/faraday/error.rb +71 -24
  24. data/lib/faraday/file_part.rb +128 -0
  25. data/lib/faraday/logging/formatter.rb +92 -0
  26. data/lib/faraday/middleware.rb +4 -28
  27. data/lib/faraday/middleware_registry.rb +129 -0
  28. data/lib/faraday/options/connection_options.rb +22 -0
  29. data/lib/faraday/options/env.rb +181 -0
  30. data/lib/faraday/options/proxy_options.rb +28 -0
  31. data/lib/faraday/options/request_options.rb +21 -0
  32. data/lib/faraday/options/ssl_options.rb +59 -0
  33. data/lib/faraday/options.rb +57 -185
  34. data/lib/faraday/param_part.rb +53 -0
  35. data/lib/faraday/parameters.rb +4 -180
  36. data/lib/faraday/rack_builder.rb +74 -38
  37. data/lib/faraday/request/authorization.rb +42 -31
  38. data/lib/faraday/request/basic_authentication.rb +14 -7
  39. data/lib/faraday/request/instrumentation.rb +45 -27
  40. data/lib/faraday/request/multipart.rb +81 -45
  41. data/lib/faraday/request/retry.rb +212 -121
  42. data/lib/faraday/request/token_authentication.rb +15 -10
  43. data/lib/faraday/request/url_encoded.rb +41 -23
  44. data/lib/faraday/request.rb +84 -30
  45. data/lib/faraday/response/logger.rb +22 -48
  46. data/lib/faraday/response/raise_error.rb +36 -14
  47. data/lib/faraday/response.rb +29 -18
  48. data/lib/faraday/utils/headers.rb +139 -0
  49. data/lib/faraday/utils/params_hash.rb +61 -0
  50. data/lib/faraday/utils.rb +28 -216
  51. data/lib/faraday.rb +102 -204
  52. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  53. metadata +24 -94
  54. data/.document +0 -6
  55. data/CHANGELOG.md +0 -20
  56. data/CONTRIBUTING.md +0 -36
  57. data/Gemfile +0 -25
  58. data/Rakefile +0 -71
  59. data/faraday.gemspec +0 -34
  60. data/lib/faraday/upload_io.rb +0 -67
  61. data/script/cached-bundle +0 -46
  62. data/script/console +0 -7
  63. data/script/generate_certs +0 -42
  64. data/script/package +0 -7
  65. data/script/proxy-server +0 -42
  66. data/script/release +0 -17
  67. data/script/s3-put +0 -71
  68. data/script/server +0 -36
  69. data/script/test +0 -172
  70. data/test/adapters/default_test.rb +0 -14
  71. data/test/adapters/em_http_test.rb +0 -20
  72. data/test/adapters/em_synchrony_test.rb +0 -20
  73. data/test/adapters/excon_test.rb +0 -20
  74. data/test/adapters/httpclient_test.rb +0 -21
  75. data/test/adapters/integration.rb +0 -254
  76. data/test/adapters/logger_test.rb +0 -82
  77. data/test/adapters/net_http_persistent_test.rb +0 -20
  78. data/test/adapters/net_http_test.rb +0 -14
  79. data/test/adapters/patron_test.rb +0 -20
  80. data/test/adapters/rack_test.rb +0 -31
  81. data/test/adapters/test_middleware_test.rb +0 -114
  82. data/test/adapters/typhoeus_test.rb +0 -28
  83. data/test/authentication_middleware_test.rb +0 -65
  84. data/test/composite_read_io_test.rb +0 -111
  85. data/test/connection_test.rb +0 -522
  86. data/test/env_test.rb +0 -218
  87. data/test/helper.rb +0 -81
  88. data/test/live_server.rb +0 -67
  89. data/test/middleware/instrumentation_test.rb +0 -88
  90. data/test/middleware/retry_test.rb +0 -177
  91. data/test/middleware_stack_test.rb +0 -173
  92. data/test/multibyte.txt +0 -1
  93. data/test/options_test.rb +0 -252
  94. data/test/parameters_test.rb +0 -64
  95. data/test/request_middleware_test.rb +0 -142
  96. data/test/response_middleware_test.rb +0 -72
  97. data/test/strawberry.rb +0 -2
  98. data/test/utils_test.rb +0 -58
@@ -1,45 +1,51 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'openssl'
2
4
  require 'em-http'
3
5
 
6
+ # EventMachine patch to make SSL work.
4
7
  module EmHttpSslPatch
5
8
  def ssl_verify_peer(cert_string)
6
- cert = nil
7
9
  begin
8
- cert = OpenSSL::X509::Certificate.new(cert_string)
10
+ @last_seen_cert = OpenSSL::X509::Certificate.new(cert_string)
9
11
  rescue OpenSSL::X509::CertificateError
10
12
  return false
11
13
  end
12
14
 
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}"))
15
+ unless certificate_store.verify(@last_seen_cert)
16
+ raise OpenSSL::SSL::SSLError,
17
+ %(unable to verify the server certificate for "#{host}")
18
+ end
19
+
20
+ begin
21
+ certificate_store.add_cert(@last_seen_cert)
22
+ rescue OpenSSL::X509::StoreError => e
23
+ raise e unless e.message == 'cert already in hash table'
24
24
  end
25
+ true
25
26
  end
26
27
 
27
28
  def ssl_handshake_completed
28
29
  return true unless verify_peer?
29
30
 
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
31
+ unless verified_cert_identity?
32
+ raise OpenSSL::SSL::SSLError,
33
+ %(host "#{host}" does not match the server certificate)
34
34
  end
35
+
36
+ true
35
37
  end
36
38
 
37
39
  def verify_peer?
38
40
  parent.connopts.tls[:verify_peer]
39
41
  end
40
42
 
43
+ def verified_cert_identity?
44
+ OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
45
+ end
46
+
41
47
  def host
42
- parent.connopts.host
48
+ parent.uri.host
43
49
  end
44
50
 
45
51
  def certificate_store
@@ -1,16 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
3
5
  class EMSynchrony < Faraday::Adapter
6
+ # A parallel manager for EMSynchrony.
4
7
  class ParallelManager
5
-
6
- # Add requests to queue. The `request` argument should be a
7
- # `EM::HttpRequest` object.
8
+ # Add requests to queue.
9
+ #
10
+ # @param request [EM::HttpRequest]
11
+ # @param method [Symbol, String] HTTP method
12
+ # @param args [Array] the rest of the positional arguments
8
13
  def add(request, method, *args, &block)
9
14
  queue << {
10
- :request => request,
11
- :method => method,
12
- :args => args,
13
- :block => block
15
+ request: request,
16
+ method: method,
17
+ args: args,
18
+ block: block
14
19
  }
15
20
  end
16
21
 
@@ -19,19 +24,18 @@ module Faraday
19
24
  def run
20
25
  result = nil
21
26
  if !EM.reactor_running?
22
- EM.run {
27
+ EM.run do
23
28
  Fiber.new do
24
29
  result = perform
25
30
  EM.stop
26
31
  end.resume
27
- }
32
+ end
28
33
  else
29
34
  result = perform
30
35
  end
31
36
  result
32
37
  end
33
38
 
34
-
35
39
  private
36
40
 
37
41
  # The request queue.
@@ -59,8 +63,7 @@ module Faraday
59
63
  # Block fiber until all requests have returned.
60
64
  multi.perform
61
65
  end
62
-
63
- end # ParallelManager
64
- end # EMSynchrony
65
- end # Adapter
66
- end # Faraday
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
 
3
5
  module Faraday
4
6
  class Adapter
7
+ # EventMachine Synchrony adapter.
5
8
  class EMSynchrony < Faraday::Adapter
6
9
  include EMHttp::Options
7
10
 
@@ -13,69 +16,121 @@ module Faraday
13
16
 
14
17
  self.supports_parallel = true
15
18
 
16
- def self.setup_parallel_manager(options = {})
19
+ # @return [ParallelManager]
20
+ def self.setup_parallel_manager(_options = nil)
17
21
  ParallelManager.new
18
22
  end
19
23
 
20
24
  def call(env)
21
25
  super
22
- request = EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env))
26
+ request = create_request(env)
23
27
 
24
28
  http_method = env[:method].to_s.downcase.to_sym
25
29
 
26
- # Queue requests for parallel execution.
27
30
  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
31
+ # Queue requests for parallel execution.
32
+ execute_parallel_request(env, request, http_method)
33
+ else
34
+ # Execute single request.
35
+ execute_single_request(env, request, http_method)
36
+ end
34
37
 
35
- # Finalize the response object with values from `env`.
36
- env[:response].finish(env)
37
- end
38
+ @app.call env
39
+ rescue Errno::ECONNREFUSED
40
+ raise Faraday::ConnectionFailed, $ERROR_INFO
41
+ rescue EventMachine::Connectify::CONNECTError => e
42
+ if e.message.include?('Proxy Authentication Required')
43
+ raise Faraday::ConnectionFailed,
44
+ %(407 "Proxy Authentication Required")
45
+ end
38
46
 
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
47
+ raise Faraday::ConnectionFailed, e
48
+ rescue Errno::ETIMEDOUT => e
49
+ raise Faraday::TimeoutError, e
50
+ rescue RuntimeError => e
51
+ if e.message == 'connection closed by server'
52
+ raise Faraday::ConnectionFailed, e
53
+ end
54
+
55
+ raise Faraday::TimeoutError, e if e.message.include?('timeout error')
56
+
57
+ raise
58
+ rescue StandardError => e
59
+ if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
60
+ raise Faraday::SSLError, e
61
+ end
62
+
63
+ raise
64
+ end
65
+
66
+ def create_request(env)
67
+ EventMachine::HttpRequest.new(
68
+ Utils::URI(env[:url].to_s),
69
+ connection_config(env).merge(@connection_options)
70
+ )
71
+ end
54
72
 
55
- raise client.error if client.error
73
+ private
56
74
 
57
- save_response(env, client.response_header.status, client.response) do |resp_headers|
58
- client.response_header.each do |name, value|
75
+ def execute_parallel_request(env, request, http_method)
76
+ env[:parallel_manager].add(request, http_method,
77
+ request_config(env)) do |resp|
78
+ if (req = env[:request]).stream_response?
79
+ warn "Streaming downloads for #{self.class.name} " \
80
+ 'are not yet implemented.'
81
+ req.on_data.call(resp.response, resp.response.bytesize)
82
+ end
83
+
84
+ save_response(env, resp.response_header.status,
85
+ resp.response) do |resp_headers|
86
+ resp.response_header.each do |name, value|
59
87
  resp_headers[name.to_sym] = value
60
88
  end
61
89
  end
90
+
91
+ # Finalize the response object with values from `env`.
92
+ env[:response].finish(env)
62
93
  end
94
+ end
63
95
 
64
- @app.call env
65
- rescue Errno::ECONNREFUSED
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
96
+ def execute_single_request(env, request, http_method)
97
+ block = -> { request.send(http_method, request_config(env)) }
98
+ client = call_block(block)
99
+
100
+ raise client.error if client&.error
101
+
102
+ if env[:request].stream_response?
103
+ warn "Streaming downloads for #{self.class.name} " \
104
+ 'are not yet implemented.'
105
+ env[:request].on_data.call(
106
+ client.response,
107
+ client.response.bytesize
108
+ )
72
109
  end
73
- rescue => err
74
- if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
75
- raise Faraday::SSLError, err
110
+ status = client.response_header.status
111
+ reason = client.response_header.http_reason
112
+ save_response(env, status, client.response, nil, reason) do |headers|
113
+ client.response_header.each do |name, value|
114
+ headers[name.to_sym] = value
115
+ end
116
+ end
117
+ end
118
+
119
+ def call_block(block)
120
+ client = nil
121
+
122
+ if EM.reactor_running?
123
+ client = block.call
76
124
  else
77
- raise
125
+ EM.run do
126
+ Fiber.new do
127
+ client = block.call
128
+ EM.stop
129
+ end.resume
130
+ end
78
131
  end
132
+
133
+ client
79
134
  end
80
135
  end
81
136
  end
@@ -83,10 +138,13 @@ end
83
138
 
84
139
  require 'faraday/adapter/em_synchrony/parallel_manager'
85
140
 
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?
141
+ if Faraday::Adapter::EMSynchrony.loaded?
142
+ begin
143
+ require 'openssl'
144
+ rescue LoadError
145
+ warn 'Warning: no such file to load -- openssl. ' \
146
+ 'Make sure it is installed if you want HTTPS support'
147
+ else
148
+ require 'faraday/adapter/em_http_ssl_patch'
149
+ end
150
+ end
@@ -1,80 +1,127 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
5
+ # Excon adapter.
3
6
  class Excon < Faraday::Adapter
4
7
  dependency 'excon'
5
8
 
6
- def initialize(app, connection_options = {})
7
- @connection_options = connection_options
8
- super(app)
9
- end
10
-
11
9
  def call(env)
12
10
  super
13
11
 
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_path] if ssl[:ca_path]
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]
23
-
24
- # https://github.com/geemus/excon/issues/106
25
- # https://github.com/jruby/jruby-ossl/issues/19
26
- opts[:nonblock] = false
27
- end
12
+ opts = opts_from_env(env)
13
+ conn = create_connection(env, opts)
28
14
 
29
- if ( req = env[:request] )
30
- if req[:timeout]
31
- opts[:read_timeout] = req[:timeout]
32
- opts[:connect_timeout] = req[:timeout]
33
- opts[:write_timeout] = req[:timeout]
34
- end
35
-
36
- if req[:open_timeout]
37
- opts[:connect_timeout] = req[:open_timeout]
38
- opts[:write_timeout] = req[:open_timeout]
39
- end
15
+ req_opts = {
16
+ method: env[:method].to_s.upcase,
17
+ headers: env[:request_headers],
18
+ body: read_body(env)
19
+ }
40
20
 
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
- }
21
+ req = env[:request]
22
+ if req&.stream_response?
23
+ total = 0
24
+ req_opts[:response_block] = lambda do |chunk, _remain, _total|
25
+ req.on_data.call(chunk, total += chunk.size)
49
26
  end
50
27
  end
51
28
 
52
- conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
29
+ resp = conn.request(req_opts)
30
+ save_response(env, resp.status.to_i, resp.body, resp.headers,
31
+ resp.reason_phrase)
53
32
 
54
- resp = conn.request \
55
- :method => env[:method].to_s.upcase,
56
- :headers => env[:request_headers],
57
- :body => read_body(env)
33
+ @app.call(env)
34
+ rescue ::Excon::Errors::SocketError => e
35
+ raise Faraday::TimeoutError, e if e.message =~ /\btimeout\b/
58
36
 
59
- save_response(env, resp.status.to_i, resp.body, resp.headers)
37
+ raise Faraday::SSLError, e if e.message =~ /\bcertificate\b/
60
38
 
61
- @app.call env
62
- rescue ::Excon::Errors::SocketError => err
63
- if err.message =~ /\btimeout\b/
64
- raise Error::TimeoutError, err
65
- elsif err.message =~ /\bcertificate\b/
66
- raise Faraday::SSLError, err
67
- else
68
- raise Error::ConnectionFailed, err
69
- end
70
- rescue ::Excon::Errors::Timeout => err
71
- raise Error::TimeoutError, err
39
+ raise Faraday::ConnectionFailed, e
40
+ rescue ::Excon::Errors::Timeout => e
41
+ raise Faraday::TimeoutError, e
42
+ end
43
+
44
+ # @return [Excon]
45
+ def create_connection(env, opts)
46
+ ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
72
47
  end
73
48
 
74
49
  # TODO: support streaming requests
75
50
  def read_body(env)
76
51
  env[:body].respond_to?(:read) ? env[:body].read : env[:body]
77
52
  end
53
+
54
+ private
55
+
56
+ def opts_from_env(env)
57
+ opts = {}
58
+ amend_opts_with_ssl!(opts, env[:ssl]) if needs_ssl_settings?(env)
59
+
60
+ if (req = env[:request])
61
+ amend_opts_with_timeouts!(opts, req)
62
+ amend_opts_with_proxy_settings!(opts, req)
63
+ end
64
+
65
+ opts
66
+ end
67
+
68
+ def needs_ssl_settings?(env)
69
+ env[:url].scheme == 'https' && env[:ssl]
70
+ end
71
+
72
+ OPTS_KEYS = [
73
+ %i[client_cert client_cert],
74
+ %i[client_key client_key],
75
+ %i[certificate certificate],
76
+ %i[private_key private_key],
77
+ %i[ssl_ca_path ca_path],
78
+ %i[ssl_ca_file ca_file],
79
+ %i[ssl_version version],
80
+ %i[ssl_min_version min_version],
81
+ %i[ssl_max_version max_version]
82
+ ].freeze
83
+
84
+ def amend_opts_with_ssl!(opts, ssl)
85
+ opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true)
86
+ # https://github.com/geemus/excon/issues/106
87
+ # https://github.com/jruby/jruby-ossl/issues/19
88
+ opts[:nonblock] = false
89
+
90
+ OPTS_KEYS.each do |(key_in_opts, key_in_ssl)|
91
+ next unless ssl[key_in_ssl]
92
+
93
+ opts[key_in_opts] = ssl[key_in_ssl]
94
+ end
95
+ end
96
+
97
+ def amend_opts_with_timeouts!(opts, req)
98
+ timeout = req[:timeout]
99
+ return unless timeout
100
+
101
+ opts[:read_timeout] = timeout
102
+ opts[:connect_timeout] = timeout
103
+ opts[:write_timeout] = timeout
104
+
105
+ open_timeout = req[:open_timeout]
106
+ return unless open_timeout
107
+
108
+ opts[:connect_timeout] = open_timeout
109
+ end
110
+
111
+ def amend_opts_with_proxy_settings!(opts, req)
112
+ opts[:proxy] = proxy_settings_for_opts(req[:proxy]) if req[:proxy]
113
+ end
114
+
115
+ def proxy_settings_for_opts(proxy)
116
+ {
117
+ host: proxy[:uri].host,
118
+ hostname: proxy[:uri].hostname,
119
+ port: proxy[:uri].port,
120
+ scheme: proxy[:uri].scheme,
121
+ user: proxy[:user],
122
+ password: proxy[:password]
123
+ }
124
+ end
78
125
  end
79
126
  end
80
127
  end