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.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +18 -344
- data/lib/faraday.rb +93 -175
- data/lib/faraday/adapter.rb +36 -22
- data/lib/faraday/adapter/em_http.rb +142 -99
- data/lib/faraday/adapter/em_http_ssl_patch.rb +23 -17
- data/lib/faraday/adapter/em_synchrony.rb +104 -60
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/excon.rb +100 -55
- data/lib/faraday/adapter/httpclient.rb +61 -39
- data/lib/faraday/adapter/net_http.rb +104 -51
- data/lib/faraday/adapter/net_http_persistent.rb +48 -27
- data/lib/faraday/adapter/patron.rb +54 -35
- data/lib/faraday/adapter/rack.rb +28 -12
- data/lib/faraday/adapter/test.rb +86 -53
- data/lib/faraday/adapter/typhoeus.rb +4 -1
- data/lib/faraday/adapter_registry.rb +28 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +321 -179
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +67 -33
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +92 -0
- data/lib/faraday/middleware.rb +4 -28
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options.rb +35 -186
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +28 -0
- data/lib/faraday/options/request_options.rb +21 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -197
- data/lib/faraday/rack_builder.rb +67 -56
- data/lib/faraday/request.rb +68 -36
- data/lib/faraday/request/authorization.rb +42 -30
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/multipart.rb +79 -48
- data/lib/faraday/request/retry.rb +198 -169
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +41 -23
- data/lib/faraday/response.rb +23 -16
- data/lib/faraday/response/logger.rb +22 -69
- data/lib/faraday/response/raise_error.rb +36 -14
- data/lib/faraday/utils.rb +28 -245
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- metadata +21 -5
- data/lib/faraday/upload_io.rb +0 -67
@@ -1,15 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
|
-
class Request
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
class Request
|
5
|
+
# TokenAuthentication is a middleware that adds a 'Token' header to a
|
6
|
+
# Faraday request.
|
7
|
+
class TokenAuthentication < load_middleware(:authorization)
|
8
|
+
# Public
|
9
|
+
def self.header(token, options = nil)
|
10
|
+
options ||= {}
|
11
|
+
options[:token] = token
|
12
|
+
super(:Token, options)
|
13
|
+
end
|
9
14
|
|
10
|
-
|
11
|
-
|
15
|
+
def initialize(app, token, options = nil)
|
16
|
+
super(app, token, options)
|
17
|
+
end
|
12
18
|
end
|
13
19
|
end
|
14
20
|
end
|
15
|
-
|
@@ -1,36 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
|
-
class Request
|
3
|
-
|
4
|
+
class Request
|
5
|
+
# Middleware for supporting urlencoded requests.
|
6
|
+
class UrlEncoded < Faraday::Middleware
|
7
|
+
CONTENT_TYPE = 'Content-Type' unless defined? CONTENT_TYPE
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
+
class << self
|
10
|
+
attr_accessor :mime_type
|
11
|
+
end
|
12
|
+
self.mime_type = 'application/x-www-form-urlencoded'
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
# Encodes as "application/x-www-form-urlencoded" if not already encoded or
|
15
|
+
# of another type.
|
16
|
+
#
|
17
|
+
# @param env [Faraday::Env]
|
18
|
+
def call(env)
|
19
|
+
match_content_type(env) do |data|
|
20
|
+
params = Faraday::Utils::ParamsHash[data]
|
21
|
+
env.body = params.to_query(env.params_encoder)
|
22
|
+
end
|
23
|
+
@app.call env
|
14
24
|
end
|
15
|
-
@app.call env
|
16
|
-
end
|
17
25
|
|
18
|
-
|
19
|
-
|
26
|
+
# @param env [Faraday::Env]
|
27
|
+
# @yield [request_body] Body of the request
|
28
|
+
def match_content_type(env)
|
29
|
+
return unless process_request?(env)
|
30
|
+
|
20
31
|
env.request_headers[CONTENT_TYPE] ||= self.class.mime_type
|
21
32
|
yield(env.body) unless env.body.respond_to?(:to_str)
|
22
33
|
end
|
23
|
-
end
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
35
|
+
# @param env [Faraday::Env]
|
36
|
+
#
|
37
|
+
# @return [Boolean] True if the request has a body and its Content-Type is
|
38
|
+
# urlencoded.
|
39
|
+
def process_request?(env)
|
40
|
+
type = request_type(env)
|
41
|
+
env.body && (type.empty? || (type == self.class.mime_type))
|
42
|
+
end
|
29
43
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
44
|
+
# @param env [Faraday::Env]
|
45
|
+
#
|
46
|
+
# @return [String]
|
47
|
+
def request_type(env)
|
48
|
+
type = env.request_headers[CONTENT_TYPE].to_s
|
49
|
+
type = type.split(';', 2).first if type.index(';')
|
50
|
+
type
|
51
|
+
end
|
34
52
|
end
|
35
53
|
end
|
36
54
|
end
|
data/lib/faraday/response.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
|
3
5
|
module Faraday
|
6
|
+
# Response represents an HTTP response from making an HTTP request.
|
4
7
|
class Response
|
5
8
|
# Used for simple response middleware.
|
6
9
|
class Middleware < Faraday::Middleware
|
@@ -20,9 +23,9 @@ module Faraday
|
|
20
23
|
extend Forwardable
|
21
24
|
extend MiddlewareRegistry
|
22
25
|
|
23
|
-
register_middleware File.expand_path('
|
24
|
-
|
25
|
-
|
26
|
+
register_middleware File.expand_path('response', __dir__),
|
27
|
+
raise_error: [:RaiseError, 'raise_error'],
|
28
|
+
logger: [:Logger, 'logger']
|
26
29
|
|
27
30
|
def initialize(env = nil)
|
28
31
|
@env = Env.from(env) if env
|
@@ -31,8 +34,6 @@ module Faraday
|
|
31
34
|
|
32
35
|
attr_reader :env
|
33
36
|
|
34
|
-
def_delegators :env, :to_hash
|
35
|
-
|
36
37
|
def status
|
37
38
|
finished? ? env.status : nil
|
38
39
|
end
|
@@ -54,32 +55,37 @@ module Faraday
|
|
54
55
|
!!env
|
55
56
|
end
|
56
57
|
|
57
|
-
def on_complete
|
58
|
-
if
|
59
|
-
@on_complete_callbacks <<
|
58
|
+
def on_complete(&block)
|
59
|
+
if !finished?
|
60
|
+
@on_complete_callbacks << block
|
60
61
|
else
|
61
62
|
yield(env)
|
62
63
|
end
|
63
|
-
|
64
|
+
self
|
64
65
|
end
|
65
66
|
|
66
67
|
def finish(env)
|
67
|
-
raise
|
68
|
+
raise 'response already finished' if finished?
|
69
|
+
|
68
70
|
@env = env.is_a?(Env) ? env : Env.from(env)
|
69
71
|
@on_complete_callbacks.each { |callback| callback.call(@env) }
|
70
|
-
|
72
|
+
self
|
71
73
|
end
|
72
74
|
|
73
75
|
def success?
|
74
76
|
finished? && env.success?
|
75
77
|
end
|
76
78
|
|
79
|
+
def to_hash
|
80
|
+
{
|
81
|
+
status: env.status, body: env.body,
|
82
|
+
response_headers: env.response_headers
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
77
86
|
# because @on_complete_callbacks cannot be marshalled
|
78
87
|
def marshal_dump
|
79
|
-
|
80
|
-
:status => @env.status, :body => @env.body,
|
81
|
-
:response_headers => @env.response_headers
|
82
|
-
}
|
88
|
+
finished? ? to_hash : nil
|
83
89
|
end
|
84
90
|
|
85
91
|
def marshal_load(env)
|
@@ -90,8 +96,9 @@ module Faraday
|
|
90
96
|
# Useful for applying request params after restoring a marshalled Response.
|
91
97
|
def apply_request(request_env)
|
92
98
|
raise "response didn't finish yet" unless finished?
|
99
|
+
|
93
100
|
@env = Env.from(request_env).update(@env)
|
94
|
-
|
101
|
+
self
|
95
102
|
end
|
96
103
|
end
|
97
104
|
end
|
@@ -1,80 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
4
|
+
require 'faraday/logging/formatter'
|
2
5
|
|
3
6
|
module Faraday
|
4
|
-
class Response
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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]
|
7
|
+
class Response
|
8
|
+
# Logger is a middleware that logs internal events in the HTTP request
|
9
|
+
# lifecycle to a given Logger object. By default, this logs to STDOUT. See
|
10
|
+
# Faraday::Logging::Formatter to see specifically what is logged.
|
11
|
+
class Logger < Middleware
|
12
|
+
def initialize(app, logger = nil, options = {})
|
13
|
+
super(app)
|
14
|
+
logger ||= begin
|
15
|
+
require 'logger'
|
16
|
+
::Logger.new($stdout)
|
17
|
+
end
|
18
|
+
formatter_class = options.delete(:formatter) || Logging::Formatter
|
19
|
+
@formatter = formatter_class.new(logger: logger, options: options)
|
20
|
+
yield @formatter if block_given?
|
62
21
|
end
|
63
|
-
end
|
64
22
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
else @options[:bodies]
|
23
|
+
def call(env)
|
24
|
+
@formatter.request(env)
|
25
|
+
super
|
69
26
|
end
|
70
|
-
end
|
71
27
|
|
72
|
-
|
73
|
-
|
74
|
-
output = output.to_s.gsub(pattern, replacement)
|
28
|
+
def on_complete(env)
|
29
|
+
@formatter.response(env)
|
75
30
|
end
|
76
|
-
output
|
77
31
|
end
|
78
|
-
|
79
32
|
end
|
80
33
|
end
|
@@ -1,21 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
|
-
class Response
|
3
|
-
|
4
|
+
class Response
|
5
|
+
# RaiseError is a Faraday middleware that raises exceptions on common HTTP
|
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
|
4
12
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
def on_complete(env)
|
14
|
+
case env[:status]
|
15
|
+
when 400
|
16
|
+
raise Faraday::BadRequestError, response_values(env)
|
17
|
+
when 401
|
18
|
+
raise Faraday::UnauthorizedError, response_values(env)
|
19
|
+
when 403
|
20
|
+
raise Faraday::ForbiddenError, response_values(env)
|
21
|
+
when 404
|
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
|
14
36
|
end
|
15
|
-
end
|
16
37
|
|
17
|
-
|
18
|
-
|
38
|
+
def response_values(env)
|
39
|
+
{ status: env.status, headers: env.response_headers, body: env.body }
|
40
|
+
end
|
19
41
|
end
|
20
42
|
end
|
21
43
|
end
|
data/lib/faraday/utils.rb
CHANGED
@@ -1,193 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday/utils/headers'
|
4
|
+
require 'faraday/utils/params_hash'
|
2
5
|
|
3
6
|
module Faraday
|
7
|
+
# Utils contains various static helper methods.
|
4
8
|
module Utils
|
5
|
-
|
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
|
9
|
+
module_function
|
191
10
|
|
192
11
|
def build_query(params)
|
193
12
|
FlatParamsEncoder.encode(params)
|
@@ -197,17 +16,19 @@ module Faraday
|
|
197
16
|
NestedParamsEncoder.encode(params)
|
198
17
|
end
|
199
18
|
|
200
|
-
ESCAPE_RE = /[^a-zA-Z0-9 .~_-]
|
19
|
+
ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
|
201
20
|
|
202
|
-
def escape(
|
203
|
-
|
21
|
+
def escape(str)
|
22
|
+
str.to_s.gsub(ESCAPE_RE) do |match|
|
204
23
|
'%' + match.unpack('H2' * match.bytesize).join('%').upcase
|
205
|
-
|
24
|
+
end.tr(' ', '+')
|
206
25
|
end
|
207
26
|
|
208
|
-
def unescape(
|
27
|
+
def unescape(str)
|
28
|
+
CGI.unescape str.to_s
|
29
|
+
end
|
209
30
|
|
210
|
-
DEFAULT_SEP = /[&;] */n
|
31
|
+
DEFAULT_SEP = /[&;] */n.freeze
|
211
32
|
|
212
33
|
# Adapted from Rack
|
213
34
|
def parse_query(query)
|
@@ -226,55 +47,18 @@ module Faraday
|
|
226
47
|
attr_writer :default_params_encoder
|
227
48
|
end
|
228
49
|
|
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
|
-
|
266
50
|
# Normalize URI() behavior across Ruby versions
|
267
51
|
#
|
268
52
|
# url - A String or URI.
|
269
53
|
#
|
270
54
|
# Returns a parsed URI.
|
271
|
-
def URI(url)
|
55
|
+
def URI(url) # rubocop:disable Naming/MethodName
|
272
56
|
if url.respond_to?(:host)
|
273
57
|
url
|
274
58
|
elsif url.respond_to?(:to_str)
|
275
59
|
default_uri_parser.call(url)
|
276
60
|
else
|
277
|
-
raise ArgumentError,
|
61
|
+
raise ArgumentError, 'bad argument (expected URI object or URI string)'
|
278
62
|
end
|
279
63
|
end
|
280
64
|
|
@@ -287,27 +71,28 @@ module Faraday
|
|
287
71
|
|
288
72
|
def default_uri_parser=(parser)
|
289
73
|
@default_uri_parser = if parser.respond_to?(:call) || parser.nil?
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
74
|
+
parser
|
75
|
+
else
|
76
|
+
parser.method(:parse)
|
77
|
+
end
|
294
78
|
end
|
295
79
|
|
296
|
-
# Receives a String or URI and returns just
|
80
|
+
# Receives a String or URI and returns just
|
81
|
+
# the path with the query string sorted.
|
297
82
|
def normalize_path(url)
|
298
83
|
url = URI(url)
|
299
84
|
(url.path.start_with?('/') ? url.path : '/' + url.path) +
|
300
|
-
|
85
|
+
(url.query ? "?#{sort_query_params(url.query)}" : '')
|
301
86
|
end
|
302
87
|
|
303
88
|
# Recursive hash update
|
304
89
|
def deep_merge!(target, hash)
|
305
90
|
hash.each do |key, value|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
91
|
+
target[key] = if value.is_a?(Hash) && target[key].is_a?(Hash)
|
92
|
+
deep_merge(target[key], value)
|
93
|
+
else
|
94
|
+
value
|
95
|
+
end
|
311
96
|
end
|
312
97
|
target
|
313
98
|
end
|
@@ -317,8 +102,6 @@ module Faraday
|
|
317
102
|
deep_merge!(source.dup, hash)
|
318
103
|
end
|
319
104
|
|
320
|
-
protected
|
321
|
-
|
322
105
|
def sort_query_params(query)
|
323
106
|
query.split('&').sort.join('&')
|
324
107
|
end
|