faraday 0.16.2 → 0.17.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.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +347 -18
- data/lib/faraday.rb +175 -93
- data/lib/faraday/adapter.rb +22 -36
- data/lib/faraday/adapter/em_http.rb +99 -142
- data/lib/faraday/adapter/em_http_ssl_patch.rb +17 -23
- data/lib/faraday/adapter/em_synchrony.rb +60 -104
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +15 -18
- data/lib/faraday/adapter/excon.rb +55 -100
- data/lib/faraday/adapter/httpclient.rb +39 -61
- data/lib/faraday/adapter/net_http.rb +51 -104
- data/lib/faraday/adapter/net_http_persistent.rb +27 -48
- data/lib/faraday/adapter/patron.rb +35 -54
- data/lib/faraday/adapter/rack.rb +12 -28
- data/lib/faraday/adapter/test.rb +53 -86
- data/lib/faraday/adapter/typhoeus.rb +1 -4
- data/lib/faraday/autoload.rb +36 -47
- data/lib/faraday/connection.rb +179 -321
- data/lib/faraday/error.rb +32 -80
- data/lib/faraday/middleware.rb +28 -4
- data/lib/faraday/options.rb +186 -35
- data/lib/faraday/parameters.rb +197 -4
- data/lib/faraday/rack_builder.rb +56 -67
- data/lib/faraday/request.rb +36 -68
- data/lib/faraday/request/authorization.rb +30 -42
- data/lib/faraday/request/basic_authentication.rb +7 -14
- data/lib/faraday/request/instrumentation.rb +27 -45
- data/lib/faraday/request/multipart.rb +48 -79
- data/lib/faraday/request/retry.rb +170 -197
- data/lib/faraday/request/token_authentication.rb +10 -15
- data/lib/faraday/request/url_encoded.rb +23 -41
- data/lib/faraday/response.rb +16 -23
- data/lib/faraday/response/logger.rb +69 -22
- data/lib/faraday/response/raise_error.rb +14 -36
- data/lib/faraday/upload_io.rb +67 -0
- data/lib/faraday/utils.rb +245 -28
- metadata +5 -22
- data/lib/faraday/adapter_registry.rb +0 -28
- data/lib/faraday/dependency_loader.rb +0 -37
- data/lib/faraday/deprecated_class.rb +0 -28
- data/lib/faraday/encoders/flat_params_encoder.rb +0 -94
- data/lib/faraday/encoders/nested_params_encoder.rb +0 -171
- data/lib/faraday/file_part.rb +0 -128
- data/lib/faraday/logging/formatter.rb +0 -92
- data/lib/faraday/middleware_registry.rb +0 -129
- data/lib/faraday/options/connection_options.rb +0 -22
- data/lib/faraday/options/env.rb +0 -181
- data/lib/faraday/options/proxy_options.rb +0 -28
- data/lib/faraday/options/request_options.rb +0 -21
- data/lib/faraday/options/ssl_options.rb +0 -59
- data/lib/faraday/param_part.rb +0 -53
- data/lib/faraday/utils/headers.rb +0 -139
- data/lib/faraday/utils/params_hash.rb +0 -61
- data/spec/external_adapters/faraday_specs_setup.rb +0 -14
data/lib/faraday/response.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require 'forwardable'
|
4
2
|
|
5
3
|
module Faraday
|
6
|
-
# Response represents an HTTP response from making an HTTP request.
|
7
4
|
class Response
|
8
5
|
# Used for simple response middleware.
|
9
6
|
class Middleware < Faraday::Middleware
|
@@ -23,9 +20,9 @@ module Faraday
|
|
23
20
|
extend Forwardable
|
24
21
|
extend MiddlewareRegistry
|
25
22
|
|
26
|
-
register_middleware File.expand_path('response',
|
27
|
-
|
28
|
-
|
23
|
+
register_middleware File.expand_path('../response', __FILE__),
|
24
|
+
:raise_error => [:RaiseError, 'raise_error'],
|
25
|
+
:logger => [:Logger, 'logger']
|
29
26
|
|
30
27
|
def initialize(env = nil)
|
31
28
|
@env = Env.from(env) if env
|
@@ -34,6 +31,8 @@ module Faraday
|
|
34
31
|
|
35
32
|
attr_reader :env
|
36
33
|
|
34
|
+
def_delegators :env, :to_hash
|
35
|
+
|
37
36
|
def status
|
38
37
|
finished? ? env.status : nil
|
39
38
|
end
|
@@ -55,37 +54,32 @@ module Faraday
|
|
55
54
|
!!env
|
56
55
|
end
|
57
56
|
|
58
|
-
def on_complete
|
59
|
-
if
|
60
|
-
@on_complete_callbacks <<
|
57
|
+
def on_complete
|
58
|
+
if not finished?
|
59
|
+
@on_complete_callbacks << Proc.new
|
61
60
|
else
|
62
61
|
yield(env)
|
63
62
|
end
|
64
|
-
self
|
63
|
+
return self
|
65
64
|
end
|
66
65
|
|
67
66
|
def finish(env)
|
68
|
-
raise
|
69
|
-
|
67
|
+
raise "response already finished" if finished?
|
70
68
|
@env = env.is_a?(Env) ? env : Env.from(env)
|
71
69
|
@on_complete_callbacks.each { |callback| callback.call(@env) }
|
72
|
-
self
|
70
|
+
return self
|
73
71
|
end
|
74
72
|
|
75
73
|
def success?
|
76
74
|
finished? && env.success?
|
77
75
|
end
|
78
76
|
|
79
|
-
def to_hash
|
80
|
-
{
|
81
|
-
status: env.status, body: env.body,
|
82
|
-
response_headers: env.response_headers
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
77
|
# because @on_complete_callbacks cannot be marshalled
|
87
78
|
def marshal_dump
|
88
|
-
finished? ?
|
79
|
+
!finished? ? nil : {
|
80
|
+
:status => @env.status, :body => @env.body,
|
81
|
+
:response_headers => @env.response_headers
|
82
|
+
}
|
89
83
|
end
|
90
84
|
|
91
85
|
def marshal_load(env)
|
@@ -96,9 +90,8 @@ module Faraday
|
|
96
90
|
# Useful for applying request params after restoring a marshalled Response.
|
97
91
|
def apply_request(request_env)
|
98
92
|
raise "response didn't finish yet" unless finished?
|
99
|
-
|
100
93
|
@env = Env.from(request_env).update(@env)
|
101
|
-
self
|
94
|
+
return self
|
102
95
|
end
|
103
96
|
end
|
104
97
|
end
|
@@ -1,33 +1,80 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require 'forwardable'
|
4
|
-
require 'faraday/logging/formatter'
|
5
2
|
|
6
3
|
module Faraday
|
7
|
-
class Response
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
4
|
+
class Response::Logger < Response::Middleware
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
DEFAULT_OPTIONS = { :headers => true, :bodies => false }
|
8
|
+
|
9
|
+
def initialize(app, logger = nil, options = {})
|
10
|
+
super(app)
|
11
|
+
@logger = logger || begin
|
12
|
+
require 'logger'
|
13
|
+
::Logger.new($stdout)
|
14
|
+
end
|
15
|
+
@filter = []
|
16
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
17
|
+
yield self if block_given?
|
18
|
+
end
|
19
|
+
|
20
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
info('request') { "#{env.method.upcase} #{apply_filters(env.url.to_s)}" }
|
24
|
+
debug('request') { apply_filters( dump_headers env.request_headers ) } if log_headers?(:request)
|
25
|
+
debug('request') { apply_filters( dump_body(env[:body]) ) } if env[:body] && log_body?(:request)
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_complete(env)
|
30
|
+
info('response') { "Status #{env.status.to_s}" }
|
31
|
+
debug('response') { apply_filters( dump_headers env.response_headers ) } if log_headers?(:response)
|
32
|
+
debug('response') { apply_filters( dump_body env[:body] ) } if env[:body] && log_body?(:response)
|
33
|
+
end
|
34
|
+
|
35
|
+
def filter(filter_word, filter_replacement)
|
36
|
+
@filter.push([ filter_word, filter_replacement ])
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def dump_headers(headers)
|
42
|
+
headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
def dump_body(body)
|
46
|
+
if body.respond_to?(:to_str)
|
47
|
+
body.to_str
|
48
|
+
else
|
49
|
+
pretty_inspect(body)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def pretty_inspect(body)
|
54
|
+
require 'pp' unless body.respond_to?(:pretty_inspect)
|
55
|
+
body.pretty_inspect
|
56
|
+
end
|
57
|
+
|
58
|
+
def log_headers?(type)
|
59
|
+
case @options[:headers]
|
60
|
+
when Hash then @options[:headers][type]
|
61
|
+
else @options[:headers]
|
21
62
|
end
|
63
|
+
end
|
22
64
|
|
23
|
-
|
24
|
-
|
25
|
-
|
65
|
+
def log_body?(type)
|
66
|
+
case @options[:bodies]
|
67
|
+
when Hash then @options[:bodies][type]
|
68
|
+
else @options[:bodies]
|
26
69
|
end
|
70
|
+
end
|
27
71
|
|
28
|
-
|
29
|
-
|
72
|
+
def apply_filters(output)
|
73
|
+
@filter.each do |pattern, replacement|
|
74
|
+
output = output.to_s.gsub(pattern, replacement)
|
30
75
|
end
|
76
|
+
output
|
31
77
|
end
|
78
|
+
|
32
79
|
end
|
33
80
|
end
|
@@ -1,43 +1,21 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Faraday
|
4
|
-
class Response
|
5
|
-
|
6
|
-
# client or server error responses.
|
7
|
-
class RaiseError < Middleware
|
8
|
-
# rubocop:disable Naming/ConstantName
|
9
|
-
ClientErrorStatuses = (400...500).freeze
|
10
|
-
ServerErrorStatuses = (500...600).freeze
|
11
|
-
# rubocop:enable Naming/ConstantName
|
2
|
+
class Response::RaiseError < Response::Middleware
|
3
|
+
ClientErrorStatuses = 400...600
|
12
4
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
raise Faraday::ResourceNotFound, response_values(env)
|
23
|
-
when 407
|
24
|
-
# mimic the behavior that we get with proxy requests with HTTPS
|
25
|
-
msg = %(407 "Proxy Authentication Required")
|
26
|
-
raise Faraday::ProxyAuthError.new(msg, response_values(env))
|
27
|
-
when 409
|
28
|
-
raise Faraday::ConflictError, response_values(env)
|
29
|
-
when 422
|
30
|
-
raise Faraday::UnprocessableEntityError, response_values(env)
|
31
|
-
when ClientErrorStatuses
|
32
|
-
raise Faraday::ClientError, response_values(env)
|
33
|
-
when ServerErrorStatuses
|
34
|
-
raise Faraday::ServerError, response_values(env)
|
35
|
-
end
|
5
|
+
def on_complete(env)
|
6
|
+
case env[:status]
|
7
|
+
when 404
|
8
|
+
raise Faraday::Error::ResourceNotFound, response_values(env)
|
9
|
+
when 407
|
10
|
+
# mimic the behavior that we get with proxy requests with HTTPS
|
11
|
+
raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
|
12
|
+
when ClientErrorStatuses
|
13
|
+
raise Faraday::Error::ClientError, response_values(env)
|
36
14
|
end
|
15
|
+
end
|
37
16
|
|
38
|
-
|
39
|
-
|
40
|
-
end
|
17
|
+
def response_values(env)
|
18
|
+
{:status => env.status, :headers => env.response_headers, :body => env.body}
|
41
19
|
end
|
42
20
|
end
|
43
21
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
begin
|
2
|
+
require 'composite_io'
|
3
|
+
require 'parts'
|
4
|
+
require 'stringio'
|
5
|
+
rescue LoadError
|
6
|
+
$stderr.puts "Install the multipart-post gem."
|
7
|
+
raise
|
8
|
+
end
|
9
|
+
|
10
|
+
module Faraday
|
11
|
+
# Similar but not compatible with ::CompositeReadIO provided by multipart-post.
|
12
|
+
class CompositeReadIO
|
13
|
+
def initialize(*parts)
|
14
|
+
@parts = parts.flatten
|
15
|
+
@ios = @parts.map { |part| part.to_io }
|
16
|
+
@index = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def length
|
20
|
+
@parts.inject(0) { |sum, part| sum + part.length }
|
21
|
+
end
|
22
|
+
|
23
|
+
def rewind
|
24
|
+
@ios.each { |io| io.rewind }
|
25
|
+
@index = 0
|
26
|
+
end
|
27
|
+
|
28
|
+
# Read from IOs in order until `length` bytes have been received.
|
29
|
+
def read(length = nil, outbuf = nil)
|
30
|
+
got_result = false
|
31
|
+
outbuf = outbuf ? outbuf.replace("") : ""
|
32
|
+
|
33
|
+
while io = current_io
|
34
|
+
if result = io.read(length)
|
35
|
+
got_result ||= !result.nil?
|
36
|
+
result.force_encoding("BINARY") if result.respond_to?(:force_encoding)
|
37
|
+
outbuf << result
|
38
|
+
length -= result.length if length
|
39
|
+
break if length == 0
|
40
|
+
end
|
41
|
+
advance_io
|
42
|
+
end
|
43
|
+
(!got_result && length) ? nil : outbuf
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
@ios.each { |io| io.close }
|
48
|
+
end
|
49
|
+
|
50
|
+
def ensure_open_and_readable
|
51
|
+
# Rubinius compatibility
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def current_io
|
57
|
+
@ios[@index]
|
58
|
+
end
|
59
|
+
|
60
|
+
def advance_io
|
61
|
+
@index += 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
UploadIO = ::UploadIO
|
66
|
+
Parts = ::Parts
|
67
|
+
end
|
data/lib/faraday/utils.rb
CHANGED
@@ -1,12 +1,193 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'faraday/utils/headers'
|
4
|
-
require 'faraday/utils/params_hash'
|
1
|
+
require 'thread'
|
5
2
|
|
6
3
|
module Faraday
|
7
|
-
# Utils contains various static helper methods.
|
8
4
|
module Utils
|
9
|
-
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# Adapted from Rack::Utils::HeaderHash
|
8
|
+
class Headers < ::Hash
|
9
|
+
def self.from(value)
|
10
|
+
new(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.allocate
|
14
|
+
new_self = super
|
15
|
+
new_self.initialize_names
|
16
|
+
new_self
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(hash = nil)
|
20
|
+
super()
|
21
|
+
@names = {}
|
22
|
+
self.update(hash || {})
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize_names
|
26
|
+
@names = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
# on dup/clone, we need to duplicate @names hash
|
30
|
+
def initialize_copy(other)
|
31
|
+
super
|
32
|
+
@names = other.names.dup
|
33
|
+
end
|
34
|
+
|
35
|
+
# need to synchronize concurrent writes to the shared KeyMap
|
36
|
+
keymap_mutex = Mutex.new
|
37
|
+
|
38
|
+
# symbol -> string mapper + cache
|
39
|
+
KeyMap = Hash.new do |map, key|
|
40
|
+
value = if key.respond_to?(:to_str)
|
41
|
+
key
|
42
|
+
else
|
43
|
+
key.to_s.split('_'). # :user_agent => %w(user agent)
|
44
|
+
each { |w| w.capitalize! }. # => %w(User Agent)
|
45
|
+
join('-') # => "User-Agent"
|
46
|
+
end
|
47
|
+
keymap_mutex.synchronize { map[key] = value }
|
48
|
+
end
|
49
|
+
KeyMap[:etag] = "ETag"
|
50
|
+
|
51
|
+
def [](k)
|
52
|
+
k = KeyMap[k]
|
53
|
+
super(k) || super(@names[k.downcase])
|
54
|
+
end
|
55
|
+
|
56
|
+
def []=(k, v)
|
57
|
+
k = KeyMap[k]
|
58
|
+
k = (@names[k.downcase] ||= k)
|
59
|
+
# join multiple values with a comma
|
60
|
+
v = v.to_ary.join(', ') if v.respond_to? :to_ary
|
61
|
+
super(k, v)
|
62
|
+
end
|
63
|
+
|
64
|
+
def fetch(k, *args, &block)
|
65
|
+
k = KeyMap[k]
|
66
|
+
key = @names.fetch(k.downcase, k)
|
67
|
+
super(key, *args, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def delete(k)
|
71
|
+
k = KeyMap[k]
|
72
|
+
if k = @names[k.downcase]
|
73
|
+
@names.delete k.downcase
|
74
|
+
super(k)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def include?(k)
|
79
|
+
@names.include? k.downcase
|
80
|
+
end
|
81
|
+
|
82
|
+
alias_method :has_key?, :include?
|
83
|
+
alias_method :member?, :include?
|
84
|
+
alias_method :key?, :include?
|
85
|
+
|
86
|
+
def merge!(other)
|
87
|
+
other.each { |k, v| self[k] = v }
|
88
|
+
self
|
89
|
+
end
|
90
|
+
alias_method :update, :merge!
|
91
|
+
|
92
|
+
def merge(other)
|
93
|
+
hash = dup
|
94
|
+
hash.merge! other
|
95
|
+
end
|
96
|
+
|
97
|
+
def replace(other)
|
98
|
+
clear
|
99
|
+
@names.clear
|
100
|
+
self.update other
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_hash() ::Hash.new.update(self) end
|
105
|
+
|
106
|
+
def parse(header_string)
|
107
|
+
return unless header_string && !header_string.empty?
|
108
|
+
|
109
|
+
headers = header_string.split(/\r\n/)
|
110
|
+
|
111
|
+
# Find the last set of response headers.
|
112
|
+
start_index = headers.rindex { |x| x.match(/^HTTP\//) } || 0
|
113
|
+
last_response = headers.slice(start_index, headers.size)
|
114
|
+
|
115
|
+
last_response.
|
116
|
+
tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line
|
117
|
+
map { |h| h.split(/:\s*/, 2) }.reject { |p| p[0].nil? }. # split key and value, ignore blank lines
|
118
|
+
each { |key, value|
|
119
|
+
# join multiple values with a comma
|
120
|
+
if self[key]
|
121
|
+
self[key] << ', ' << value
|
122
|
+
else
|
123
|
+
self[key] = value
|
124
|
+
end
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
protected
|
129
|
+
|
130
|
+
def names
|
131
|
+
@names
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# hash with stringified keys
|
136
|
+
class ParamsHash < Hash
|
137
|
+
def [](key)
|
138
|
+
super(convert_key(key))
|
139
|
+
end
|
140
|
+
|
141
|
+
def []=(key, value)
|
142
|
+
super(convert_key(key), value)
|
143
|
+
end
|
144
|
+
|
145
|
+
def delete(key)
|
146
|
+
super(convert_key(key))
|
147
|
+
end
|
148
|
+
|
149
|
+
def include?(key)
|
150
|
+
super(convert_key(key))
|
151
|
+
end
|
152
|
+
|
153
|
+
alias_method :has_key?, :include?
|
154
|
+
alias_method :member?, :include?
|
155
|
+
alias_method :key?, :include?
|
156
|
+
|
157
|
+
def update(params)
|
158
|
+
params.each do |key, value|
|
159
|
+
self[key] = value
|
160
|
+
end
|
161
|
+
self
|
162
|
+
end
|
163
|
+
alias_method :merge!, :update
|
164
|
+
|
165
|
+
def merge(params)
|
166
|
+
dup.update(params)
|
167
|
+
end
|
168
|
+
|
169
|
+
def replace(other)
|
170
|
+
clear
|
171
|
+
update(other)
|
172
|
+
end
|
173
|
+
|
174
|
+
def merge_query(query, encoder = nil)
|
175
|
+
if query && !query.empty?
|
176
|
+
update((encoder || Utils.default_params_encoder).decode(query))
|
177
|
+
end
|
178
|
+
self
|
179
|
+
end
|
180
|
+
|
181
|
+
def to_query(encoder = nil)
|
182
|
+
(encoder || Utils.default_params_encoder).encode(self)
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def convert_key(key)
|
188
|
+
key.to_s
|
189
|
+
end
|
190
|
+
end
|
10
191
|
|
11
192
|
def build_query(params)
|
12
193
|
FlatParamsEncoder.encode(params)
|
@@ -16,19 +197,17 @@ module Faraday
|
|
16
197
|
NestedParamsEncoder.encode(params)
|
17
198
|
end
|
18
199
|
|
19
|
-
ESCAPE_RE = /[^a-zA-Z0-9 .~_-]
|
200
|
+
ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
|
20
201
|
|
21
|
-
def escape(
|
22
|
-
|
202
|
+
def escape(s)
|
203
|
+
s.to_s.gsub(ESCAPE_RE) {|match|
|
23
204
|
'%' + match.unpack('H2' * match.bytesize).join('%').upcase
|
24
|
-
|
205
|
+
}.tr(' ', '+')
|
25
206
|
end
|
26
207
|
|
27
|
-
def unescape(
|
28
|
-
CGI.unescape str.to_s
|
29
|
-
end
|
208
|
+
def unescape(s) CGI.unescape s.to_s end
|
30
209
|
|
31
|
-
DEFAULT_SEP = /[&;] */n
|
210
|
+
DEFAULT_SEP = /[&;] */n
|
32
211
|
|
33
212
|
# Adapted from Rack
|
34
213
|
def parse_query(query)
|
@@ -47,18 +226,55 @@ module Faraday
|
|
47
226
|
attr_writer :default_params_encoder
|
48
227
|
end
|
49
228
|
|
229
|
+
# Stolen from Rack
|
230
|
+
def normalize_params(params, name, v = nil)
|
231
|
+
name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
|
232
|
+
k = $1 || ''
|
233
|
+
after = $' || ''
|
234
|
+
|
235
|
+
return if k.empty?
|
236
|
+
|
237
|
+
if after == ""
|
238
|
+
if params[k]
|
239
|
+
params[k] = Array[params[k]] unless params[k].kind_of?(Array)
|
240
|
+
params[k] << v
|
241
|
+
else
|
242
|
+
params[k] = v
|
243
|
+
end
|
244
|
+
elsif after == "[]"
|
245
|
+
params[k] ||= []
|
246
|
+
raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
|
247
|
+
params[k] << v
|
248
|
+
elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
|
249
|
+
child_key = $1
|
250
|
+
params[k] ||= []
|
251
|
+
raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
|
252
|
+
if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
|
253
|
+
normalize_params(params[k].last, child_key, v)
|
254
|
+
else
|
255
|
+
params[k] << normalize_params({}, child_key, v)
|
256
|
+
end
|
257
|
+
else
|
258
|
+
params[k] ||= {}
|
259
|
+
raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
|
260
|
+
params[k] = normalize_params(params[k], after, v)
|
261
|
+
end
|
262
|
+
|
263
|
+
return params
|
264
|
+
end
|
265
|
+
|
50
266
|
# Normalize URI() behavior across Ruby versions
|
51
267
|
#
|
52
268
|
# url - A String or URI.
|
53
269
|
#
|
54
270
|
# Returns a parsed URI.
|
55
|
-
def URI(url)
|
271
|
+
def URI(url)
|
56
272
|
if url.respond_to?(:host)
|
57
273
|
url
|
58
274
|
elsif url.respond_to?(:to_str)
|
59
275
|
default_uri_parser.call(url)
|
60
276
|
else
|
61
|
-
raise ArgumentError,
|
277
|
+
raise ArgumentError, "bad argument (expected URI object or URI string)"
|
62
278
|
end
|
63
279
|
end
|
64
280
|
|
@@ -71,28 +287,27 @@ module Faraday
|
|
71
287
|
|
72
288
|
def default_uri_parser=(parser)
|
73
289
|
@default_uri_parser = if parser.respond_to?(:call) || parser.nil?
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
290
|
+
parser
|
291
|
+
else
|
292
|
+
parser.method(:parse)
|
293
|
+
end
|
78
294
|
end
|
79
295
|
|
80
|
-
# Receives a String or URI and returns just
|
81
|
-
# the path with the query string sorted.
|
296
|
+
# Receives a String or URI and returns just the path with the query string sorted.
|
82
297
|
def normalize_path(url)
|
83
298
|
url = URI(url)
|
84
299
|
(url.path.start_with?('/') ? url.path : '/' + url.path) +
|
85
|
-
|
300
|
+
(url.query ? "?#{sort_query_params(url.query)}" : "")
|
86
301
|
end
|
87
302
|
|
88
303
|
# Recursive hash update
|
89
304
|
def deep_merge!(target, hash)
|
90
305
|
hash.each do |key, value|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
306
|
+
if Hash === value and Hash === target[key]
|
307
|
+
target[key] = deep_merge(target[key], value)
|
308
|
+
else
|
309
|
+
target[key] = value
|
310
|
+
end
|
96
311
|
end
|
97
312
|
target
|
98
313
|
end
|
@@ -102,6 +317,8 @@ module Faraday
|
|
102
317
|
deep_merge!(source.dup, hash)
|
103
318
|
end
|
104
319
|
|
320
|
+
protected
|
321
|
+
|
105
322
|
def sort_query_params(query)
|
106
323
|
query.split('&').sort.join('&')
|
107
324
|
end
|