faraday 0.15.4 → 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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/README.md +18 -344
  4. data/lib/faraday.rb +93 -175
  5. data/lib/faraday/adapter.rb +36 -22
  6. data/lib/faraday/adapter/em_http.rb +142 -99
  7. data/lib/faraday/adapter/em_http_ssl_patch.rb +23 -17
  8. data/lib/faraday/adapter/em_synchrony.rb +104 -60
  9. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  10. data/lib/faraday/adapter/excon.rb +100 -55
  11. data/lib/faraday/adapter/httpclient.rb +61 -39
  12. data/lib/faraday/adapter/net_http.rb +104 -51
  13. data/lib/faraday/adapter/net_http_persistent.rb +48 -27
  14. data/lib/faraday/adapter/patron.rb +54 -35
  15. data/lib/faraday/adapter/rack.rb +28 -12
  16. data/lib/faraday/adapter/test.rb +86 -53
  17. data/lib/faraday/adapter/typhoeus.rb +4 -1
  18. data/lib/faraday/adapter_registry.rb +28 -0
  19. data/lib/faraday/autoload.rb +47 -36
  20. data/lib/faraday/connection.rb +321 -179
  21. data/lib/faraday/dependency_loader.rb +37 -0
  22. data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
  23. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  24. data/lib/faraday/error.rb +67 -33
  25. data/lib/faraday/file_part.rb +128 -0
  26. data/lib/faraday/logging/formatter.rb +92 -0
  27. data/lib/faraday/middleware.rb +4 -28
  28. data/lib/faraday/middleware_registry.rb +129 -0
  29. data/lib/faraday/options.rb +35 -186
  30. data/lib/faraday/options/connection_options.rb +22 -0
  31. data/lib/faraday/options/env.rb +181 -0
  32. data/lib/faraday/options/proxy_options.rb +28 -0
  33. data/lib/faraday/options/request_options.rb +21 -0
  34. data/lib/faraday/options/ssl_options.rb +59 -0
  35. data/lib/faraday/param_part.rb +53 -0
  36. data/lib/faraday/parameters.rb +4 -197
  37. data/lib/faraday/rack_builder.rb +67 -56
  38. data/lib/faraday/request.rb +68 -36
  39. data/lib/faraday/request/authorization.rb +42 -30
  40. data/lib/faraday/request/basic_authentication.rb +14 -7
  41. data/lib/faraday/request/instrumentation.rb +45 -27
  42. data/lib/faraday/request/multipart.rb +79 -48
  43. data/lib/faraday/request/retry.rb +198 -169
  44. data/lib/faraday/request/token_authentication.rb +15 -10
  45. data/lib/faraday/request/url_encoded.rb +41 -23
  46. data/lib/faraday/response.rb +23 -16
  47. data/lib/faraday/response/logger.rb +22 -69
  48. data/lib/faraday/response/raise_error.rb +36 -14
  49. data/lib/faraday/utils.rb +28 -245
  50. data/lib/faraday/utils/headers.rb +139 -0
  51. data/lib/faraday/utils/params_hash.rb +61 -0
  52. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  53. metadata +21 -5
  54. data/lib/faraday/upload_io.rb +0 -67
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # ConnectionOptions contains the configurable properties for a Faraday
5
+ # connection object.
6
+ class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
7
+ :parallel_manager, :params, :headers,
8
+ :builder_class)
9
+
10
+ options request: RequestOptions, ssl: SSLOptions
11
+
12
+ memoized(:request) { self.class.options_for(:request).new }
13
+
14
+ memoized(:ssl) { self.class.options_for(:ssl).new }
15
+
16
+ memoized(:builder_class) { RackBuilder }
17
+
18
+ def new_builder(block)
19
+ builder_class.new(&block)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # @!attribute method
5
+ # @return [Symbol] HTTP method (`:get`, `:post`)
6
+ #
7
+ # @!attribute body
8
+ # @return [String] The request body that will eventually be converted to a
9
+ # string.
10
+ #
11
+ # @!attribute url
12
+ # @return [URI] URI instance for the current request.
13
+ #
14
+ # @!attribute request
15
+ # @return [Hash] options for configuring the request.
16
+ # Options for configuring the request.
17
+ #
18
+ # - `:timeout` open/read timeout Integer in seconds
19
+ # - `:open_timeout` - read timeout Integer in seconds
20
+ # - `:on_data` - Proc for streaming
21
+ # - `:proxy` - Hash of proxy options
22
+ # - `:uri` - Proxy Server URI
23
+ # - `:user` - Proxy server username
24
+ # - `:password` - Proxy server password
25
+ #
26
+ # @!attribute request_headers
27
+ # @return [Hash] HTTP Headers to be sent to the server.
28
+ #
29
+ # @!attribute ssl
30
+ # @return [Hash] options for configuring SSL requests
31
+ #
32
+ # @!attribute parallel_manager
33
+ # @return [Object] sent if the connection is in parallel mode
34
+ #
35
+ # @!attribute params
36
+ # @return [Hash]
37
+ #
38
+ # @!attribute response
39
+ # @return [Response]
40
+ #
41
+ # @!attribute response_headers
42
+ # @return [Hash] HTTP headers from the server
43
+ #
44
+ # @!attribute status
45
+ # @return [Integer] HTTP response status code
46
+ #
47
+ # @!attribute reason_phrase
48
+ # @return [String]
49
+ class Env < Options.new(:method, :request_body, :url, :request,
50
+ :request_headers, :ssl, :parallel_manager, :params,
51
+ :response, :response_headers, :status,
52
+ :reason_phrase, :response_body)
53
+
54
+ # rubocop:disable Naming/ConstantName
55
+ ContentLength = 'Content-Length'
56
+ StatusesWithoutBody = Set.new [204, 304]
57
+ SuccessfulStatuses = (200..299).freeze
58
+ # rubocop:enable Naming/ConstantName
59
+
60
+ # A Set of HTTP verbs that typically send a body. If no body is set for
61
+ # these requests, the Content-Length header is set to 0.
62
+ MethodsWithBodies = Set.new(Faraday::METHODS_WITH_BODY.map(&:to_sym))
63
+
64
+ options request: RequestOptions,
65
+ request_headers: Utils::Headers, response_headers: Utils::Headers
66
+
67
+ extend Forwardable
68
+
69
+ def_delegators :request, :params_encoder
70
+
71
+ # Build a new Env from given value. Respects and updates `custom_members`.
72
+ #
73
+ # @param value [Object] a value fitting Option.from(v).
74
+ # @return [Env] from given value
75
+ def self.from(value)
76
+ env = super(value)
77
+ if value.respond_to?(:custom_members)
78
+ env.custom_members.update(value.custom_members)
79
+ end
80
+ env
81
+ end
82
+
83
+ # @param key [Object]
84
+ def [](key)
85
+ return self[current_body] if key == :body
86
+
87
+ if in_member_set?(key)
88
+ super(key)
89
+ else
90
+ custom_members[key]
91
+ end
92
+ end
93
+
94
+ # @param key [Object]
95
+ # @param value [Object]
96
+ def []=(key, value)
97
+ if key == :body
98
+ super(current_body, value)
99
+ return
100
+ end
101
+
102
+ if in_member_set?(key)
103
+ super(key, value)
104
+ else
105
+ custom_members[key] = value
106
+ end
107
+ end
108
+
109
+ def current_body
110
+ !!status ? :response_body : :request_body
111
+ end
112
+
113
+ def body
114
+ self[:body]
115
+ end
116
+
117
+ def body=(value)
118
+ self[:body] = value
119
+ end
120
+
121
+ # @return [Boolean] true if status is in the set of {SuccessfulStatuses}.
122
+ def success?
123
+ SuccessfulStatuses.include?(status)
124
+ end
125
+
126
+ # @return [Boolean] true if there's no body yet, and the method is in the
127
+ # set of {MethodsWithBodies}.
128
+ def needs_body?
129
+ !body && MethodsWithBodies.include?(method)
130
+ end
131
+
132
+ # Sets content length to zero and the body to the empty string.
133
+ def clear_body
134
+ request_headers[ContentLength] = '0'
135
+ self.body = ''
136
+ end
137
+
138
+ # @return [Boolean] true if the status isn't in the set of
139
+ # {StatusesWithoutBody}.
140
+ def parse_body?
141
+ !StatusesWithoutBody.include?(status)
142
+ end
143
+
144
+ # @return [Boolean] true if there is a parallel_manager
145
+ def parallel?
146
+ !!parallel_manager
147
+ end
148
+
149
+ def inspect
150
+ attrs = [nil]
151
+ members.each do |mem|
152
+ if (value = send(mem))
153
+ attrs << "@#{mem}=#{value.inspect}"
154
+ end
155
+ end
156
+ attrs << "@custom=#{custom_members.inspect}" unless custom_members.empty?
157
+ %(#<#{self.class}#{attrs.join(' ')}>)
158
+ end
159
+
160
+ # @private
161
+ def custom_members
162
+ @custom_members ||= {}
163
+ end
164
+
165
+ # @private
166
+ if members.first.is_a?(Symbol)
167
+ def in_member_set?(key)
168
+ self.class.member_set.include?(key.to_sym)
169
+ end
170
+ else
171
+ def in_member_set?(key)
172
+ self.class.member_set.include?(key.to_s)
173
+ end
174
+ end
175
+
176
+ # @private
177
+ def self.member_set
178
+ @member_set ||= Set.new(members)
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # ProxyOptions contains the configurable properties for the proxy
5
+ # configuration used when making an HTTP request.
6
+ class ProxyOptions < Options.new(:uri, :user, :password)
7
+ extend Forwardable
8
+ def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=,
9
+ :path, :path=
10
+
11
+ def self.from(value)
12
+ case value
13
+ when String
14
+ value = { uri: Utils.URI(value) }
15
+ when URI
16
+ value = { uri: value }
17
+ when Hash, Options
18
+ if (uri = value.delete(:uri))
19
+ value[:uri] = Utils.URI(uri)
20
+ end
21
+ end
22
+ super(value)
23
+ end
24
+
25
+ memoized(:user) { uri&.user && Utils.unescape(uri.user) }
26
+ memoized(:password) { uri&.password && Utils.unescape(uri.password) }
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # RequestOptions contains the configurable properties for a Faraday request.
5
+ class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
6
+ :timeout, :open_timeout, :write_timeout,
7
+ :boundary, :oauth, :context, :on_data)
8
+
9
+ def []=(key, value)
10
+ if key && key.to_sym == :proxy
11
+ super(key, value ? ProxyOptions.from(value) : nil)
12
+ else
13
+ super(key, value)
14
+ end
15
+ end
16
+
17
+ def stream_response?
18
+ on_data.is_a?(Proc)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # SSL-related options.
5
+ #
6
+ # @!attribute verify
7
+ # @return [Boolean] whether to verify SSL certificates or not
8
+ #
9
+ # @!attribute ca_file
10
+ # @return [String] CA file
11
+ #
12
+ # @!attribute ca_path
13
+ # @return [String] CA path
14
+ #
15
+ # @!attribute verify_mode
16
+ # @return [Integer] Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html)
17
+ #
18
+ # @!attribute cert_store
19
+ # @return [OpenSSL::X509::Store] certificate store
20
+ #
21
+ # @!attribute client_cert
22
+ # @return [String, OpenSSL::X509::Certificate] client certificate
23
+ #
24
+ # @!attribute client_key
25
+ # @return [String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] client key
26
+ #
27
+ # @!attribute certificate
28
+ # @return [OpenSSL::X509::Certificate] certificate (Excon only)
29
+ #
30
+ # @!attribute private_key
31
+ # @return [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] private key (Excon only)
32
+ #
33
+ # @!attribute verify_depth
34
+ # @return [Integer] maximum depth for the certificate chain verification
35
+ #
36
+ # @!attribute version
37
+ # @return [String, Symbol] SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D)
38
+ #
39
+ # @!attribute min_version
40
+ # @return [String, Symbol] minimum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D)
41
+ #
42
+ # @!attribute max_version
43
+ # @return [String, Symbol] maximum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D)
44
+ class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
45
+ :cert_store, :client_cert, :client_key,
46
+ :certificate, :private_key, :verify_depth,
47
+ :version, :min_version, :max_version)
48
+
49
+ # @return [Boolean] true if should verify
50
+ def verify?
51
+ verify != false
52
+ end
53
+
54
+ # @return [Boolean] true if should not verify
55
+ def disable?
56
+ !verify?
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # Multipart value used to POST data with a content type.
5
+ class ParamPart
6
+ # @param value [String] Uploaded content as a String.
7
+ # @param content_type [String] String content type of the value.
8
+ # @param content_id [String] Optional String of this value's Content-ID.
9
+ #
10
+ # @return [Faraday::ParamPart]
11
+ def initialize(value, content_type, content_id = nil)
12
+ @value = value
13
+ @content_type = content_type
14
+ @content_id = content_id
15
+ end
16
+
17
+ # Converts this value to a form part.
18
+ #
19
+ # @param boundary [String] String multipart boundary that must not exist in
20
+ # the content exactly.
21
+ # @param key [String] String key name for this value.
22
+ #
23
+ # @return [Faraday::Parts::Part]
24
+ def to_part(boundary, key)
25
+ Faraday::Parts::Part.new(boundary, key, value, headers)
26
+ end
27
+
28
+ # Returns a Hash of String key/value pairs.
29
+ #
30
+ # @return [Hash]
31
+ def headers
32
+ {
33
+ 'Content-Type' => content_type,
34
+ 'Content-ID' => content_id
35
+ }
36
+ end
37
+
38
+ # The content to upload.
39
+ #
40
+ # @return [String]
41
+ attr_reader :value
42
+
43
+ # The value's content type.
44
+ #
45
+ # @return [String]
46
+ attr_reader :content_type
47
+
48
+ # The value's content ID, if given.
49
+ #
50
+ # @return [String, nil]
51
+ attr_reader :content_id
52
+ end
53
+ end
@@ -1,198 +1,5 @@
1
- require "forwardable"
1
+ # frozen_string_literal: true
2
2
 
3
- module Faraday
4
- module NestedParamsEncoder
5
- class << self
6
- extend Forwardable
7
- def_delegators :'Faraday::Utils', :escape, :unescape
8
- end
9
-
10
- def self.encode(params)
11
- return nil if params == nil
12
-
13
- if !params.is_a?(Array)
14
- if !params.respond_to?(:to_hash)
15
- raise TypeError,
16
- "Can't convert #{params.class} into Hash."
17
- end
18
- params = params.to_hash
19
- params = params.map do |key, value|
20
- key = key.to_s if key.kind_of?(Symbol)
21
- [key, value]
22
- end
23
- # Useful default for OAuth and caching.
24
- # Only to be used for non-Array inputs. Arrays should preserve order.
25
- params.sort!
26
- end
27
-
28
- # Helper lambda
29
- to_query = lambda do |parent, value|
30
- if value.is_a?(Hash)
31
- value = value.map do |key, val|
32
- key = escape(key)
33
- [key, val]
34
- end
35
- value.sort!
36
- buffer = ""
37
- value.each do |key, val|
38
- new_parent = "#{parent}%5B#{key}%5D"
39
- buffer << "#{to_query.call(new_parent, val)}&"
40
- end
41
- return buffer.chop
42
- elsif value.is_a?(Array)
43
- new_parent = "#{parent}%5B%5D"
44
- return new_parent if value.empty?
45
- buffer = ""
46
- value.each_with_index do |val, i|
47
- buffer << "#{to_query.call(new_parent, val)}&"
48
- end
49
- return buffer.chop
50
- elsif value.nil?
51
- return parent
52
- else
53
- encoded_value = escape(value)
54
- return "#{parent}=#{encoded_value}"
55
- end
56
- end
57
-
58
- # The params have form [['key1', 'value1'], ['key2', 'value2']].
59
- buffer = ''
60
- params.each do |parent, value|
61
- encoded_parent = escape(parent)
62
- buffer << "#{to_query.call(encoded_parent, value)}&"
63
- end
64
- return buffer.chop
65
- end
66
-
67
- def self.decode(query)
68
- return nil if query == nil
69
-
70
- params = {}
71
- query.split("&").each do |pair|
72
- next if pair.empty?
73
- key, value = pair.split("=", 2)
74
- key = unescape(key)
75
- value = unescape(value.gsub(/\+/, ' ')) if value
76
-
77
- subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
78
- context = params
79
- subkeys.each_with_index do |subkey, i|
80
- is_array = subkey =~ /[\[\]]+\Z/
81
- subkey = $` if is_array
82
- last_subkey = i == subkeys.length - 1
83
-
84
- if !last_subkey || is_array
85
- value_type = is_array ? Array : Hash
86
- if context[subkey] && !context[subkey].is_a?(value_type)
87
- raise TypeError, "expected %s (got %s) for param `%s'" % [
88
- value_type.name,
89
- context[subkey].class.name,
90
- subkey
91
- ]
92
- end
93
- context = (context[subkey] ||= value_type.new)
94
- end
95
-
96
- if context.is_a?(Array) && !is_array
97
- if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
98
- context << {}
99
- end
100
- context = context.last
101
- end
102
-
103
- if last_subkey
104
- if is_array
105
- context << value
106
- else
107
- context[subkey] = value
108
- end
109
- end
110
- end
111
- end
112
-
113
- dehash(params, 0)
114
- end
115
-
116
- # Internal: convert a nested hash with purely numeric keys into an array.
117
- # FIXME: this is not compatible with Rack::Utils.parse_nested_query
118
- def self.dehash(hash, depth)
119
- hash.each do |key, value|
120
- hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
121
- end
122
-
123
- if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
124
- hash.keys.sort.inject([]) { |all, key| all << hash[key] }
125
- else
126
- hash
127
- end
128
- end
129
- end
130
-
131
- module FlatParamsEncoder
132
- class << self
133
- extend Forwardable
134
- def_delegators :'Faraday::Utils', :escape, :unescape
135
- end
136
-
137
- def self.encode(params)
138
- return nil if params == nil
139
-
140
- if !params.is_a?(Array)
141
- if !params.respond_to?(:to_hash)
142
- raise TypeError,
143
- "Can't convert #{params.class} into Hash."
144
- end
145
- params = params.to_hash
146
- params = params.map do |key, value|
147
- key = key.to_s if key.kind_of?(Symbol)
148
- [key, value]
149
- end
150
- # Useful default for OAuth and caching.
151
- # Only to be used for non-Array inputs. Arrays should preserve order.
152
- params.sort!
153
- end
154
-
155
- # The params have form [['key1', 'value1'], ['key2', 'value2']].
156
- buffer = ''
157
- params.each do |key, value|
158
- encoded_key = escape(key)
159
- value = value.to_s if value == true || value == false
160
- if value == nil
161
- buffer << "#{encoded_key}&"
162
- elsif value.kind_of?(Array)
163
- value.each do |sub_value|
164
- encoded_value = escape(sub_value)
165
- buffer << "#{encoded_key}=#{encoded_value}&"
166
- end
167
- else
168
- encoded_value = escape(value)
169
- buffer << "#{encoded_key}=#{encoded_value}&"
170
- end
171
- end
172
- return buffer.chop
173
- end
174
-
175
- def self.decode(query)
176
- empty_accumulator = {}
177
- return nil if query == nil
178
- split_query = (query.split('&').map do |pair|
179
- pair.split('=', 2) if pair && !pair.empty?
180
- end).compact
181
- return split_query.inject(empty_accumulator.dup) do |accu, pair|
182
- pair[0] = unescape(pair[0])
183
- pair[1] = true if pair[1].nil?
184
- if pair[1].respond_to?(:to_str)
185
- pair[1] = unescape(pair[1].to_str.gsub(/\+/, " "))
186
- end
187
- if accu[pair[0]].kind_of?(Array)
188
- accu[pair[0]] << pair[1]
189
- elsif accu[pair[0]]
190
- accu[pair[0]] = [accu[pair[0]], pair[1]]
191
- else
192
- accu[pair[0]] = pair[1]
193
- end
194
- accu
195
- end
196
- end
197
- end
198
- end
3
+ require 'forwardable'
4
+ require 'faraday/encoders/nested_params_encoder'
5
+ require 'faraday/encoders/flat_params_encoder'