faraday 0.17.6 → 1.0.1
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/CHANGELOG.md +52 -8
- data/LICENSE.md +1 -1
- data/README.md +18 -358
- data/Rakefile +1 -7
- data/examples/client_spec.rb +65 -0
- data/examples/client_test.rb +79 -0
- data/lib/faraday/adapter/em_http.rb +142 -99
- data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/em_synchrony.rb +104 -60
- data/lib/faraday/adapter/excon.rb +98 -56
- data/lib/faraday/adapter/httpclient.rb +83 -59
- data/lib/faraday/adapter/net_http.rb +129 -63
- data/lib/faraday/adapter/net_http_persistent.rb +50 -27
- data/lib/faraday/adapter/patron.rb +80 -43
- data/lib/faraday/adapter/rack.rb +30 -13
- data/lib/faraday/adapter/test.rb +86 -53
- data/lib/faraday/adapter/typhoeus.rb +4 -1
- data/lib/faraday/adapter.rb +82 -22
- data/lib/faraday/adapter_registry.rb +30 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +312 -182
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +9 -35
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +105 -0
- data/lib/faraday/middleware.rb +12 -28
- data/lib/faraday/middleware_registry.rb +129 -0
- 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 +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +32 -183
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -197
- data/lib/faraday/rack_builder.rb +66 -55
- data/lib/faraday/request/authorization.rb +44 -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 +197 -171
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +43 -23
- data/lib/faraday/request.rb +68 -38
- data/lib/faraday/response/logger.rb +22 -69
- data/lib/faraday/response/raise_error.rb +38 -18
- data/lib/faraday/response.rb +24 -14
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +36 -245
- data/lib/faraday.rb +94 -175
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/em_http_spec.rb +47 -0
- data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
- data/spec/faraday/adapter/excon_spec.rb +49 -0
- data/spec/faraday/adapter/httpclient_spec.rb +73 -0
- data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
- data/spec/faraday/adapter/net_http_spec.rb +64 -0
- data/spec/faraday/adapter/patron_spec.rb +18 -0
- data/spec/faraday/adapter/rack_spec.rb +8 -0
- data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/composite_read_io_spec.rb +80 -0
- data/spec/faraday/connection_spec.rb +691 -0
- data/spec/faraday/error_spec.rb +0 -57
- data/spec/faraday/middleware_spec.rb +26 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +37 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +34 -0
- data/spec/faraday/params_encoders/nested_spec.rb +134 -0
- data/spec/faraday/rack_builder_spec.rb +196 -0
- data/spec/faraday/request/authorization_spec.rb +88 -0
- data/spec/faraday/request/instrumentation_spec.rb +76 -0
- data/spec/faraday/request/multipart_spec.rb +274 -0
- data/spec/faraday/request/retry_spec.rb +242 -0
- data/spec/faraday/request/url_encoded_spec.rb +83 -0
- data/spec/faraday/request_spec.rb +109 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/middleware_spec.rb +68 -0
- data/spec/faraday/response/raise_error_spec.rb +15 -15
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +56 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +63 -36
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +133 -0
- data/spec/support/shared_examples/adapter.rb +104 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +234 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- data/spec/support/webmock_rack_app.rb +68 -0
- metadata +66 -38
- data/lib/faraday/deprecate.rb +0 -109
- data/lib/faraday/upload_io.rb +0 -77
- data/spec/faraday/deprecate_spec.rb +0 -147
- data/test/adapters/default_test.rb +0 -14
- data/test/adapters/em_http_test.rb +0 -30
- data/test/adapters/em_synchrony_test.rb +0 -32
- data/test/adapters/excon_test.rb +0 -30
- data/test/adapters/httpclient_test.rb +0 -34
- data/test/adapters/integration.rb +0 -263
- data/test/adapters/logger_test.rb +0 -136
- data/test/adapters/net_http_persistent_test.rb +0 -114
- data/test/adapters/net_http_test.rb +0 -79
- data/test/adapters/patron_test.rb +0 -40
- data/test/adapters/rack_test.rb +0 -38
- data/test/adapters/test_middleware_test.rb +0 -157
- data/test/adapters/typhoeus_test.rb +0 -38
- data/test/authentication_middleware_test.rb +0 -65
- data/test/composite_read_io_test.rb +0 -109
- data/test/connection_test.rb +0 -738
- data/test/env_test.rb +0 -268
- data/test/helper.rb +0 -75
- data/test/live_server.rb +0 -67
- data/test/middleware/instrumentation_test.rb +0 -88
- data/test/middleware/retry_test.rb +0 -282
- data/test/middleware_stack_test.rb +0 -260
- data/test/multibyte.txt +0 -1
- data/test/options_test.rb +0 -333
- data/test/parameters_test.rb +0 -157
- data/test/request_middleware_test.rb +0 -126
- data/test/response_middleware_test.rb +0 -72
- data/test/strawberry.rb +0 -2
- data/test/utils_test.rb +0 -98
data/lib/faraday/request.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
|
-
# Used to setup
|
4
|
+
# Used to setup URLs, params, headers, and the request body in a sane manner.
|
3
5
|
#
|
6
|
+
# @example
|
4
7
|
# @connection.post do |req|
|
5
8
|
# req.url 'http://localhost', 'a' => '1' # 'http://localhost?a=1'
|
6
9
|
# req.headers['b'] = '2' # Header
|
@@ -9,27 +12,53 @@ module Faraday
|
|
9
12
|
# req.body = 'abc'
|
10
13
|
# end
|
11
14
|
#
|
15
|
+
# @!attribute method
|
16
|
+
# @return [Symbol] the HTTP method of the Request
|
17
|
+
# @!attribute path
|
18
|
+
# @return [URI, String] the path
|
19
|
+
# @!attribute params
|
20
|
+
# @return [Hash] query parameters
|
21
|
+
# @!attribute headers
|
22
|
+
# @return [Faraday::Utils::Headers] headers
|
23
|
+
# @!attribute body
|
24
|
+
# @return [Hash] body
|
25
|
+
# @!attribute options
|
26
|
+
# @return [RequestOptions] options
|
27
|
+
#
|
28
|
+
# rubocop:disable Style/StructInheritance
|
12
29
|
class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
|
13
|
-
|
30
|
+
# rubocop:enable Style/StructInheritance
|
14
31
|
|
15
|
-
|
32
|
+
extend MiddlewareRegistry
|
16
33
|
|
17
|
-
register_middleware File.expand_path('
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
34
|
+
register_middleware File.expand_path('request', __dir__),
|
35
|
+
url_encoded: [:UrlEncoded, 'url_encoded'],
|
36
|
+
multipart: [:Multipart, 'multipart'],
|
37
|
+
retry: [:Retry, 'retry'],
|
38
|
+
authorization: [:Authorization, 'authorization'],
|
39
|
+
basic_auth: [
|
40
|
+
:BasicAuthentication,
|
41
|
+
'basic_authentication'
|
42
|
+
],
|
43
|
+
token_auth: [
|
44
|
+
:TokenAuthentication,
|
45
|
+
'token_authentication'
|
46
|
+
],
|
47
|
+
instrumentation: [:Instrumentation, 'instrumentation']
|
25
48
|
|
49
|
+
# @param request_method [String]
|
50
|
+
# @yield [request] for block customization, if block given
|
51
|
+
# @yieldparam request [Request]
|
52
|
+
# @return [Request]
|
26
53
|
def self.create(request_method)
|
27
54
|
new(request_method).tap do |request|
|
28
55
|
yield(request) if block_given?
|
29
56
|
end
|
30
57
|
end
|
31
58
|
|
32
|
-
#
|
59
|
+
# Replace params, preserving the existing hash type.
|
60
|
+
#
|
61
|
+
# @param hash [Hash] new params
|
33
62
|
def params=(hash)
|
34
63
|
if params
|
35
64
|
params.replace hash
|
@@ -38,7 +67,9 @@ module Faraday
|
|
38
67
|
end
|
39
68
|
end
|
40
69
|
|
41
|
-
#
|
70
|
+
# Replace request headers, preserving the existing hash type.
|
71
|
+
#
|
72
|
+
# @param hash [Hash] new headers
|
42
73
|
def headers=(hash)
|
43
74
|
if headers
|
44
75
|
headers.replace hash
|
@@ -47,9 +78,14 @@ module Faraday
|
|
47
78
|
end
|
48
79
|
end
|
49
80
|
|
81
|
+
# Update path and params.
|
82
|
+
#
|
83
|
+
# @param path [URI, String]
|
84
|
+
# @param params [Hash, nil]
|
85
|
+
# @return [void]
|
50
86
|
def url(path, params = nil)
|
51
87
|
if path.respond_to? :query
|
52
|
-
if query = path.query
|
88
|
+
if (query = path.query)
|
53
89
|
path = path.dup
|
54
90
|
path.query = nil
|
55
91
|
end
|
@@ -63,25 +99,35 @@ module Faraday
|
|
63
99
|
self.params.update(params) if params
|
64
100
|
end
|
65
101
|
|
102
|
+
# @param key [Object] key to look up in headers
|
103
|
+
# @return [Object] value of the given header name
|
66
104
|
def [](key)
|
67
105
|
headers[key]
|
68
106
|
end
|
69
107
|
|
108
|
+
# @param key [Object] key of header to write
|
109
|
+
# @param value [Object] value of header
|
70
110
|
def []=(key, value)
|
71
111
|
headers[key] = value
|
72
112
|
end
|
73
113
|
|
114
|
+
# Marshal serialization support.
|
115
|
+
#
|
116
|
+
# @return [Hash] the hash ready to be serialized in Marshal.
|
74
117
|
def marshal_dump
|
75
118
|
{
|
76
|
-
:
|
77
|
-
:
|
78
|
-
:
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:
|
119
|
+
method: method,
|
120
|
+
body: body,
|
121
|
+
headers: headers,
|
122
|
+
path: path,
|
123
|
+
params: params,
|
124
|
+
options: options
|
82
125
|
}
|
83
126
|
end
|
84
127
|
|
128
|
+
# Marshal serialization support.
|
129
|
+
# Restores the instance variables according to the +serialised+.
|
130
|
+
# @param serialised [Hash] the serialised object.
|
85
131
|
def marshal_load(serialised)
|
86
132
|
self.method = serialised[:method]
|
87
133
|
self.body = serialised[:body]
|
@@ -91,26 +137,10 @@ module Faraday
|
|
91
137
|
self.options = serialised[:options]
|
92
138
|
end
|
93
139
|
|
94
|
-
#
|
95
|
-
# :method - a symbolized request method (:get, :post)
|
96
|
-
# :body - the request body that will eventually be converted to a string.
|
97
|
-
# :url - URI instance for the current request.
|
98
|
-
# :status - HTTP response status code
|
99
|
-
# :request_headers - hash of HTTP Headers to be sent to the server
|
100
|
-
# :response_headers - Hash of HTTP headers from the server
|
101
|
-
# :parallel_manager - sent if the connection is in parallel mode
|
102
|
-
# :request - Hash of options for configuring the request.
|
103
|
-
# :timeout - open/read timeout Integer in seconds
|
104
|
-
# :open_timeout - read timeout Integer in seconds
|
105
|
-
# :proxy - Hash of proxy options
|
106
|
-
# :uri - Proxy Server URI
|
107
|
-
# :user - Proxy server username
|
108
|
-
# :password - Proxy server password
|
109
|
-
# :ssl - Hash of options for configuring SSL requests.
|
140
|
+
# @return [Env] the Env for this Request
|
110
141
|
def to_env(connection)
|
111
142
|
Env.new(method, body, connection.build_exclusive_url(path, params),
|
112
|
-
|
143
|
+
options, headers, connection.ssl, connection.parallel_manager)
|
113
144
|
end
|
114
145
|
end
|
115
146
|
end
|
116
|
-
|
@@ -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,25 +1,45 @@
|
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
+
when nil
|
36
|
+
raise Faraday::NilStatusError, response_values(env)
|
37
|
+
end
|
18
38
|
end
|
19
|
-
end
|
20
39
|
|
21
|
-
|
22
|
-
|
40
|
+
def response_values(env)
|
41
|
+
{ status: env.status, headers: env.response_headers, body: env.body }
|
42
|
+
end
|
23
43
|
end
|
24
44
|
end
|
25
45
|
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
|
@@ -12,17 +15,20 @@ module Faraday
|
|
12
15
|
|
13
16
|
# Override this to modify the environment after the response has finished.
|
14
17
|
# Calls the `parse` method if defined
|
18
|
+
# `parse` method can be defined as private, public and protected
|
15
19
|
def on_complete(env)
|
16
|
-
|
20
|
+
return unless respond_to?(:parse, true) && env.parse_body?
|
21
|
+
|
22
|
+
env.body = parse(env.body)
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
20
26
|
extend Forwardable
|
21
27
|
extend MiddlewareRegistry
|
22
28
|
|
23
|
-
register_middleware File.expand_path('
|
24
|
-
|
25
|
-
|
29
|
+
register_middleware File.expand_path('response', __dir__),
|
30
|
+
raise_error: [:RaiseError, 'raise_error'],
|
31
|
+
logger: [:Logger, 'logger']
|
26
32
|
|
27
33
|
def initialize(env = nil)
|
28
34
|
@env = Env.from(env) if env
|
@@ -31,8 +37,6 @@ module Faraday
|
|
31
37
|
|
32
38
|
attr_reader :env
|
33
39
|
|
34
|
-
def_delegators :env, :to_hash
|
35
|
-
|
36
40
|
def status
|
37
41
|
finished? ? env.status : nil
|
38
42
|
end
|
@@ -60,26 +64,31 @@ module Faraday
|
|
60
64
|
else
|
61
65
|
yield(env)
|
62
66
|
end
|
63
|
-
|
67
|
+
self
|
64
68
|
end
|
65
69
|
|
66
70
|
def finish(env)
|
67
|
-
raise
|
71
|
+
raise 'response already finished' if finished?
|
72
|
+
|
68
73
|
@env = env.is_a?(Env) ? env : Env.from(env)
|
69
74
|
@on_complete_callbacks.each { |callback| callback.call(@env) }
|
70
|
-
|
75
|
+
self
|
71
76
|
end
|
72
77
|
|
73
78
|
def success?
|
74
79
|
finished? && env.success?
|
75
80
|
end
|
76
81
|
|
82
|
+
def to_hash
|
83
|
+
{
|
84
|
+
status: env.status, body: env.body,
|
85
|
+
response_headers: env.response_headers
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
77
89
|
# because @on_complete_callbacks cannot be marshalled
|
78
90
|
def marshal_dump
|
79
|
-
|
80
|
-
:status => @env.status, :body => @env.body,
|
81
|
-
:response_headers => @env.response_headers
|
82
|
-
}
|
91
|
+
finished? ? to_hash : nil
|
83
92
|
end
|
84
93
|
|
85
94
|
def marshal_load(env)
|
@@ -90,8 +99,9 @@ module Faraday
|
|
90
99
|
# Useful for applying request params after restoring a marshalled Response.
|
91
100
|
def apply_request(request_env)
|
92
101
|
raise "response didn't finish yet" unless finished?
|
102
|
+
|
93
103
|
@env = Env.from(request_env).update(@env)
|
94
|
-
|
104
|
+
self
|
95
105
|
end
|
96
106
|
end
|
97
107
|
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
module Utils
|
5
|
+
# A case-insensitive Hash that preserves the original case of a header
|
6
|
+
# when set.
|
7
|
+
#
|
8
|
+
# Adapted from Rack::Utils::HeaderHash
|
9
|
+
class Headers < ::Hash
|
10
|
+
def self.from(value)
|
11
|
+
new(value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.allocate
|
15
|
+
new_self = super
|
16
|
+
new_self.initialize_names
|
17
|
+
new_self
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(hash = nil)
|
21
|
+
super()
|
22
|
+
@names = {}
|
23
|
+
update(hash || {})
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize_names
|
27
|
+
@names = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
# on dup/clone, we need to duplicate @names hash
|
31
|
+
def initialize_copy(other)
|
32
|
+
super
|
33
|
+
@names = other.names.dup
|
34
|
+
end
|
35
|
+
|
36
|
+
# need to synchronize concurrent writes to the shared KeyMap
|
37
|
+
keymap_mutex = Mutex.new
|
38
|
+
|
39
|
+
# symbol -> string mapper + cache
|
40
|
+
KeyMap = Hash.new do |map, key|
|
41
|
+
value = if key.respond_to?(:to_str)
|
42
|
+
key
|
43
|
+
else
|
44
|
+
key.to_s.split('_') # user_agent: %w(user agent)
|
45
|
+
.each(&:capitalize!) # => %w(User Agent)
|
46
|
+
.join('-') # => "User-Agent"
|
47
|
+
end
|
48
|
+
keymap_mutex.synchronize { map[key] = value }
|
49
|
+
end
|
50
|
+
KeyMap[:etag] = 'ETag'
|
51
|
+
|
52
|
+
def [](key)
|
53
|
+
key = KeyMap[key]
|
54
|
+
super(key) || super(@names[key.downcase])
|
55
|
+
end
|
56
|
+
|
57
|
+
def []=(key, val)
|
58
|
+
key = KeyMap[key]
|
59
|
+
key = (@names[key.downcase] ||= key)
|
60
|
+
# join multiple values with a comma
|
61
|
+
val = val.to_ary.join(', ') if val.respond_to?(:to_ary)
|
62
|
+
super(key, val)
|
63
|
+
end
|
64
|
+
|
65
|
+
def fetch(key, *args, &block)
|
66
|
+
key = KeyMap[key]
|
67
|
+
key = @names.fetch(key.downcase, key)
|
68
|
+
super(key, *args, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def delete(key)
|
72
|
+
key = KeyMap[key]
|
73
|
+
key = @names[key.downcase]
|
74
|
+
return unless key
|
75
|
+
|
76
|
+
@names.delete key.downcase
|
77
|
+
super(key)
|
78
|
+
end
|
79
|
+
|
80
|
+
def include?(key)
|
81
|
+
@names.include? key.downcase
|
82
|
+
end
|
83
|
+
|
84
|
+
alias has_key? include?
|
85
|
+
alias member? include?
|
86
|
+
alias key? include?
|
87
|
+
|
88
|
+
def merge!(other)
|
89
|
+
other.each { |k, v| self[k] = v }
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
alias update merge!
|
94
|
+
|
95
|
+
def merge(other)
|
96
|
+
hash = dup
|
97
|
+
hash.merge! other
|
98
|
+
end
|
99
|
+
|
100
|
+
def replace(other)
|
101
|
+
clear
|
102
|
+
@names.clear
|
103
|
+
update other
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_hash
|
108
|
+
::Hash.new.update(self)
|
109
|
+
end
|
110
|
+
|
111
|
+
def parse(header_string)
|
112
|
+
return unless header_string && !header_string.empty?
|
113
|
+
|
114
|
+
headers = header_string.split(/\r\n/)
|
115
|
+
|
116
|
+
# Find the last set of response headers.
|
117
|
+
start_index = headers.rindex { |x| x.match(%r{^HTTP/}) } || 0
|
118
|
+
last_response = headers.slice(start_index, headers.size)
|
119
|
+
|
120
|
+
last_response
|
121
|
+
.tap { |a| a.shift if a.first.start_with?('HTTP/') }
|
122
|
+
.map { |h| h.split(/:\s*/, 2) } # split key and value
|
123
|
+
.reject { |p| p[0].nil? } # ignore blank lines
|
124
|
+
.each { |key, value| add_parsed(key, value) }
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
|
129
|
+
attr_reader :names
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
# Join multiple values with a comma.
|
134
|
+
def add_parsed(key, value)
|
135
|
+
self[key] ? self[key] << ', ' << value : self[key] = value
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
module Utils
|
5
|
+
# A hash with stringified keys.
|
6
|
+
class ParamsHash < Hash
|
7
|
+
def [](key)
|
8
|
+
super(convert_key(key))
|
9
|
+
end
|
10
|
+
|
11
|
+
def []=(key, value)
|
12
|
+
super(convert_key(key), value)
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete(key)
|
16
|
+
super(convert_key(key))
|
17
|
+
end
|
18
|
+
|
19
|
+
def include?(key)
|
20
|
+
super(convert_key(key))
|
21
|
+
end
|
22
|
+
|
23
|
+
alias has_key? include?
|
24
|
+
alias member? include?
|
25
|
+
alias key? include?
|
26
|
+
|
27
|
+
def update(params)
|
28
|
+
params.each do |key, value|
|
29
|
+
self[key] = value
|
30
|
+
end
|
31
|
+
self
|
32
|
+
end
|
33
|
+
alias merge! update
|
34
|
+
|
35
|
+
def merge(params)
|
36
|
+
dup.update(params)
|
37
|
+
end
|
38
|
+
|
39
|
+
def replace(other)
|
40
|
+
clear
|
41
|
+
update(other)
|
42
|
+
end
|
43
|
+
|
44
|
+
def merge_query(query, encoder = nil)
|
45
|
+
return self unless query && !query.empty?
|
46
|
+
|
47
|
+
update((encoder || Utils.default_params_encoder).decode(query))
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_query(encoder = nil)
|
51
|
+
(encoder || Utils.default_params_encoder).encode(self)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def convert_key(key)
|
57
|
+
key.to_s
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|