faraday 1.0.0 → 2.0.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +221 -1
  3. data/LICENSE.md +1 -1
  4. data/README.md +19 -14
  5. data/examples/client_spec.rb +36 -4
  6. data/examples/client_test.rb +43 -4
  7. data/lib/faraday/adapter/test.rb +61 -43
  8. data/lib/faraday/adapter.rb +3 -16
  9. data/lib/faraday/adapter_registry.rb +3 -1
  10. data/lib/faraday/connection.rb +25 -78
  11. data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
  12. data/lib/faraday/encoders/nested_params_encoder.rb +9 -4
  13. data/lib/faraday/error.rb +23 -8
  14. data/lib/faraday/logging/formatter.rb +1 -0
  15. data/lib/faraday/methods.rb +6 -0
  16. data/lib/faraday/middleware.rb +14 -5
  17. data/lib/faraday/middleware_registry.rb +15 -79
  18. data/lib/faraday/options/proxy_options.rb +4 -0
  19. data/lib/faraday/options.rb +7 -11
  20. data/lib/faraday/rack_builder.rb +34 -30
  21. data/lib/faraday/request/authorization.rb +32 -36
  22. data/lib/faraday/request/instrumentation.rb +2 -0
  23. data/lib/faraday/request/json.rb +55 -0
  24. data/lib/faraday/request/url_encoded.rb +5 -1
  25. data/lib/faraday/request.rb +13 -23
  26. data/lib/faraday/response/json.rb +54 -0
  27. data/lib/faraday/response/logger.rb +4 -4
  28. data/lib/faraday/response/raise_error.rb +20 -1
  29. data/lib/faraday/response.rb +8 -22
  30. data/lib/faraday/utils/headers.rb +3 -3
  31. data/lib/faraday/utils.rb +21 -8
  32. data/lib/faraday/version.rb +5 -0
  33. data/lib/faraday.rb +44 -59
  34. data/spec/faraday/adapter/test_spec.rb +377 -0
  35. data/spec/faraday/connection_spec.rb +147 -51
  36. data/spec/faraday/error_spec.rb +15 -0
  37. data/spec/faraday/middleware_spec.rb +32 -6
  38. data/spec/faraday/options/env_spec.rb +2 -2
  39. data/spec/faraday/options/proxy_options_spec.rb +7 -0
  40. data/spec/faraday/params_encoders/flat_spec.rb +8 -0
  41. data/spec/faraday/params_encoders/nested_spec.rb +8 -0
  42. data/spec/faraday/rack_builder_spec.rb +144 -38
  43. data/spec/faraday/request/authorization_spec.rb +19 -24
  44. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  45. data/spec/faraday/request/json_spec.rb +111 -0
  46. data/spec/faraday/request/url_encoded_spec.rb +13 -1
  47. data/spec/faraday/request_spec.rb +6 -6
  48. data/spec/faraday/response/json_spec.rb +117 -0
  49. data/spec/faraday/response/raise_error_spec.rb +66 -0
  50. data/spec/faraday/utils_spec.rb +62 -1
  51. data/spec/support/fake_safe_buffer.rb +1 -1
  52. data/spec/support/helper_methods.rb +0 -37
  53. data/spec/support/shared_examples/adapter.rb +2 -2
  54. data/spec/support/shared_examples/request_method.rb +43 -28
  55. metadata +16 -48
  56. data/UPGRADING.md +0 -55
  57. data/lib/faraday/adapter/em_http.rb +0 -285
  58. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  59. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  60. data/lib/faraday/adapter/em_synchrony.rb +0 -150
  61. data/lib/faraday/adapter/excon.rb +0 -124
  62. data/lib/faraday/adapter/httpclient.rb +0 -151
  63. data/lib/faraday/adapter/net_http.rb +0 -209
  64. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  65. data/lib/faraday/adapter/patron.rb +0 -132
  66. data/lib/faraday/adapter/rack.rb +0 -75
  67. data/lib/faraday/adapter/typhoeus.rb +0 -15
  68. data/lib/faraday/autoload.rb +0 -95
  69. data/lib/faraday/dependency_loader.rb +0 -37
  70. data/lib/faraday/file_part.rb +0 -128
  71. data/lib/faraday/param_part.rb +0 -53
  72. data/lib/faraday/request/basic_authentication.rb +0 -20
  73. data/lib/faraday/request/multipart.rb +0 -99
  74. data/lib/faraday/request/retry.rb +0 -239
  75. data/lib/faraday/request/token_authentication.rb +0 -20
  76. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  77. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  78. data/spec/faraday/adapter/excon_spec.rb +0 -49
  79. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  80. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
  81. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  82. data/spec/faraday/adapter/patron_spec.rb +0 -18
  83. data/spec/faraday/adapter/rack_spec.rb +0 -8
  84. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  85. data/spec/faraday/composite_read_io_spec.rb +0 -80
  86. data/spec/faraday/request/multipart_spec.rb +0 -274
  87. data/spec/faraday/request/retry_spec.rb +0 -242
  88. data/spec/faraday/response/middleware_spec.rb +0 -52
  89. data/spec/support/webmock_rack_app.rb +0 -68
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ruby2_keywords'
3
4
  require 'faraday/adapter_registry'
4
5
 
5
6
  module Faraday
@@ -27,7 +28,7 @@ module Faraday
27
28
 
28
29
  attr_reader :name
29
30
 
30
- def initialize(klass, *args, &block)
31
+ ruby2_keywords def initialize(klass, *args, &block)
31
32
  @name = klass.to_s
32
33
  REGISTRY.set(klass) if klass.respond_to?(:name)
33
34
  @args = args
@@ -57,22 +58,21 @@ module Faraday
57
58
  end
58
59
  end
59
60
 
60
- def initialize(handlers = [], adapter = nil, &block)
61
- @adapter = adapter
62
- @handlers = handlers
63
- if block_given?
64
- build(&block)
65
- elsif @handlers.empty?
66
- # default stack, if nothing else is configured
67
- request :url_encoded
68
- self.adapter Faraday.default_adapter
69
- end
61
+ def initialize(&block)
62
+ @adapter = nil
63
+ @handlers = []
64
+ build(&block)
65
+ end
66
+
67
+ def initialize_dup(original)
68
+ super
69
+ @adapter = original.adapter
70
+ @handlers = original.handlers.dup
70
71
  end
71
72
 
72
- def build(options = {})
73
+ def build
73
74
  raise_if_locked
74
- @handlers.clear unless options[:keep]
75
- yield(self) if block_given?
75
+ block_given? ? yield(self) : request(:url_encoded)
76
76
  adapter(Faraday.default_adapter) unless @adapter
77
77
  end
78
78
 
@@ -89,7 +89,7 @@ module Faraday
89
89
  @handlers.frozen?
90
90
  end
91
91
 
92
- def use(klass, *args, &block)
92
+ ruby2_keywords def use(klass, *args, &block)
93
93
  if klass.is_a? Symbol
94
94
  use_symbol(Faraday::Middleware, klass, *args, &block)
95
95
  else
@@ -99,16 +99,16 @@ module Faraday
99
99
  end
100
100
  end
101
101
 
102
- def request(key, *args, &block)
102
+ ruby2_keywords def request(key, *args, &block)
103
103
  use_symbol(Faraday::Request, key, *args, &block)
104
104
  end
105
105
 
106
- def response(key, *args, &block)
106
+ ruby2_keywords def response(key, *args, &block)
107
107
  use_symbol(Faraday::Response, key, *args, &block)
108
108
  end
109
109
 
110
- def adapter(klass = NO_ARGUMENT, *args, &block)
111
- return @adapter if klass == NO_ARGUMENT
110
+ ruby2_keywords def adapter(klass = NO_ARGUMENT, *args, &block)
111
+ return @adapter if klass == NO_ARGUMENT || klass.nil?
112
112
 
113
113
  klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
114
114
  @adapter = self.class::Handler.new(klass, *args, &block)
@@ -116,7 +116,7 @@ module Faraday
116
116
 
117
117
  ## methods to push onto the various positions in the stack:
118
118
 
119
- def insert(index, *args, &block)
119
+ ruby2_keywords def insert(index, *args, &block)
120
120
  raise_if_locked
121
121
  index = assert_index(index)
122
122
  handler = self.class::Handler.new(*args, &block)
@@ -125,12 +125,12 @@ module Faraday
125
125
 
126
126
  alias insert_before insert
127
127
 
128
- def insert_after(index, *args, &block)
128
+ ruby2_keywords def insert_after(index, *args, &block)
129
129
  index = assert_index(index)
130
130
  insert(index + 1, *args, &block)
131
131
  end
132
132
 
133
- def swap(index, *args, &block)
133
+ ruby2_keywords def swap(index, *args, &block)
134
134
  raise_if_locked
135
135
  index = assert_index(index)
136
136
  @handlers.delete_at(index)
@@ -163,6 +163,7 @@ module Faraday
163
163
  def app
164
164
  @app ||= begin
165
165
  lock!
166
+ ensure_adapter!
166
167
  to_app
167
168
  end
168
169
  end
@@ -181,12 +182,8 @@ module Faraday
181
182
  @adapter == other.adapter
182
183
  end
183
184
 
184
- def dup
185
- self.class.new(@handlers.dup, @adapter.dup)
186
- end
187
-
188
185
  # ENV Keys
189
- # :method - a symbolized request method (:get, :post)
186
+ # :http_method - a symbolized request HTTP method (:get, :post)
190
187
  # :body - the request body that will eventually be converted to a string.
191
188
  # :url - URI instance for the current request.
192
189
  # :status - HTTP response status code
@@ -207,7 +204,7 @@ module Faraday
207
204
  request.options.params_encoder
208
205
  )
209
206
 
210
- Env.new(request.method, request.body, exclusive_url,
207
+ Env.new(request.http_method, request.body, exclusive_url,
211
208
  request.options, request.headers, connection.ssl,
212
209
  connection.parallel_manager)
213
210
  end
@@ -215,6 +212,9 @@ module Faraday
215
212
  private
216
213
 
217
214
  LOCK_ERR = "can't modify middleware stack after making a request"
215
+ MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
216
+ "Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
217
+ 'For more info, check https://lostisland.github.io/faraday/usage/.'
218
218
 
219
219
  def raise_if_locked
220
220
  raise StackLocked, LOCK_ERR if locked?
@@ -226,15 +226,19 @@ module Faraday
226
226
  raise 'Adapter should be set using the `adapter` method, not `use`'
227
227
  end
228
228
 
229
+ def ensure_adapter!
230
+ raise MISSING_ADAPTER_ERROR unless @adapter
231
+ end
232
+
229
233
  def adapter_set?
230
234
  !@adapter.nil?
231
235
  end
232
236
 
233
237
  def is_adapter?(klass) # rubocop:disable Naming/PredicateName
234
- klass.ancestors.include?(Faraday::Adapter)
238
+ klass <= Faraday::Adapter
235
239
  end
236
240
 
237
- def use_symbol(mod, key, *args, &block)
241
+ ruby2_keywords def use_symbol(mod, key, *args, &block)
238
242
  use(mod.lookup_middleware(key), *args, &block)
239
243
  end
240
244
 
@@ -4,50 +4,46 @@ module Faraday
4
4
  class Request
5
5
  # Request middleware for the Authorization HTTP header
6
6
  class Authorization < Faraday::Middleware
7
- KEY = 'Authorization' unless defined? KEY
8
-
9
- # @param type [String, Symbol]
10
- # @param token [String, Symbol, Hash]
11
- # @return [String] a header value
12
- def self.header(type, token)
13
- case token
14
- when String, Symbol
15
- "#{type} #{token}"
16
- when Hash
17
- build_hash(type.to_s, token)
18
- else
19
- raise ArgumentError,
20
- "Can't build an Authorization #{type}" \
21
- "header from #{token.inspect}"
22
- end
23
- end
24
-
25
- # @param type [String]
26
- # @param hash [Hash]
27
- # @return [String] type followed by comma-separated key=value pairs
28
- # @api private
29
- def self.build_hash(type, hash)
30
- comma = ', '
31
- values = []
32
- hash.each do |key, value|
33
- values << "#{key}=#{value.to_s.inspect}"
34
- end
35
- "#{type} #{values * comma}"
36
- end
7
+ KEY = 'Authorization'
37
8
 
38
9
  # @param app [#call]
39
10
  # @param type [String, Symbol] Type of Authorization
40
- # @param token [String, Symbol, Hash] Token value for the Authorization
41
- def initialize(app, type, token)
42
- @header_value = self.class.header(type, token)
11
+ # @param params [Array<String, Proc, #call>] parameters to build the Authorization header.
12
+ # If the type is `:basic`, then these can be a login and password pair.
13
+ # Otherwise, a single value is expected that will be appended after the type.
14
+ # This value can be a proc or an object responding to `.call`, in which case
15
+ # it will be invoked on each request.
16
+ def initialize(app, type, *params)
17
+ @type = type
18
+ @params = params
43
19
  super(app)
44
20
  end
45
21
 
46
22
  # @param env [Faraday::Env]
47
- def call(env)
48
- env.request_headers[KEY] = @header_value unless env.request_headers[KEY]
49
- @app.call(env)
23
+ def on_request(env)
24
+ return if env.request_headers[KEY]
25
+
26
+ env.request_headers[KEY] = header_from(@type, *@params)
27
+ end
28
+
29
+ private
30
+
31
+ # @param type [String, Symbol]
32
+ # @param params [Array]
33
+ # @return [String] a header value
34
+ def header_from(type, *params)
35
+ if type.to_s.casecmp('basic').zero? && params.size == 2
36
+ Utils.basic_header_from(*params)
37
+ elsif params.size != 1
38
+ raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)"
39
+ else
40
+ value = params.first
41
+ value = value.call if value.is_a?(Proc) || value.respond_to?(:call)
42
+ "#{type} #{value}"
43
+ end
50
44
  end
51
45
  end
52
46
  end
53
47
  end
48
+
49
+ Faraday::Request.register_middleware(authorization: Faraday::Request::Authorization)
@@ -52,3 +52,5 @@ module Faraday
52
52
  end
53
53
  end
54
54
  end
55
+
56
+ Faraday::Request.register_middleware(instrumentation: Faraday::Request::Instrumentation)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Faraday
6
+ class Request
7
+ # Request middleware that encodes the body as JSON.
8
+ #
9
+ # Processes only requests with matching Content-type or those without a type.
10
+ # If a request doesn't have a type but has a body, it sets the Content-type
11
+ # to JSON MIME-type.
12
+ #
13
+ # Doesn't try to encode bodies that already are in string form.
14
+ class Json < Middleware
15
+ MIME_TYPE = 'application/json'
16
+ MIME_TYPE_REGEX = %r{^application/(vnd\..+\+)?json$}.freeze
17
+
18
+ def on_request(env)
19
+ match_content_type(env) do |data|
20
+ env[:body] = encode(data)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def encode(data)
27
+ ::JSON.generate(data)
28
+ end
29
+
30
+ def match_content_type(env)
31
+ return unless process_request?(env)
32
+
33
+ env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
34
+ yield env[:body] unless env[:body].respond_to?(:to_str)
35
+ end
36
+
37
+ def process_request?(env)
38
+ type = request_type(env)
39
+ body?(env) && (type.empty? || type.match?(MIME_TYPE_REGEX))
40
+ end
41
+
42
+ def body?(env)
43
+ (body = env[:body]) && !(body.respond_to?(:to_str) && body.empty?)
44
+ end
45
+
46
+ def request_type(env)
47
+ type = env[:request_headers][CONTENT_TYPE].to_s
48
+ type = type.split(';', 2).first if type.index(';')
49
+ type
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ Faraday::Request.register_middleware(json: Faraday::Request::Json)
@@ -4,7 +4,9 @@ module Faraday
4
4
  class Request
5
5
  # Middleware for supporting urlencoded requests.
6
6
  class UrlEncoded < Faraday::Middleware
7
- CONTENT_TYPE = 'Content-Type' unless defined? CONTENT_TYPE
7
+ unless defined?(::Faraday::Request::UrlEncoded::CONTENT_TYPE)
8
+ CONTENT_TYPE = 'Content-Type'
9
+ end
8
10
 
9
11
  class << self
10
12
  attr_accessor :mime_type
@@ -52,3 +54,5 @@ module Faraday
52
54
  end
53
55
  end
54
56
  end
57
+
58
+ Faraday::Request.register_middleware(url_encoded: Faraday::Request::UrlEncoded)
@@ -12,7 +12,7 @@ module Faraday
12
12
  # req.body = 'abc'
13
13
  # end
14
14
  #
15
- # @!attribute method
15
+ # @!attribute http_method
16
16
  # @return [Symbol] the HTTP method of the Request
17
17
  # @!attribute path
18
18
  # @return [URI, String] the path
@@ -26,26 +26,11 @@ module Faraday
26
26
  # @return [RequestOptions] options
27
27
  #
28
28
  # rubocop:disable Style/StructInheritance
29
- class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
29
+ class Request < Struct.new(:http_method, :path, :params, :headers, :body, :options)
30
30
  # rubocop:enable Style/StructInheritance
31
31
 
32
32
  extend MiddlewareRegistry
33
33
 
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']
48
-
49
34
  # @param request_method [String]
50
35
  # @yield [request] for block customization, if block given
51
36
  # @yieldparam request [Request]
@@ -116,7 +101,7 @@ module Faraday
116
101
  # @return [Hash] the hash ready to be serialized in Marshal.
117
102
  def marshal_dump
118
103
  {
119
- method: method,
104
+ http_method: http_method,
120
105
  body: body,
121
106
  headers: headers,
122
107
  path: path,
@@ -129,18 +114,23 @@ module Faraday
129
114
  # Restores the instance variables according to the +serialised+.
130
115
  # @param serialised [Hash] the serialised object.
131
116
  def marshal_load(serialised)
132
- self.method = serialised[:method]
133
- self.body = serialised[:body]
117
+ self.http_method = serialised[:http_method]
118
+ self.body = serialised[:body]
134
119
  self.headers = serialised[:headers]
135
- self.path = serialised[:path]
136
- self.params = serialised[:params]
120
+ self.path = serialised[:path]
121
+ self.params = serialised[:params]
137
122
  self.options = serialised[:options]
138
123
  end
139
124
 
140
125
  # @return [Env] the Env for this Request
141
126
  def to_env(connection)
142
- Env.new(method, body, connection.build_exclusive_url(path, params),
127
+ Env.new(http_method, body, connection.build_exclusive_url(path, params),
143
128
  options, headers, connection.ssl, connection.parallel_manager)
144
129
  end
145
130
  end
146
131
  end
132
+
133
+ require 'faraday/request/authorization'
134
+ require 'faraday/request/instrumentation'
135
+ require 'faraday/request/json'
136
+ require 'faraday/request/url_encoded'
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Faraday
6
+ class Response
7
+ # Parse response bodies as JSON.
8
+ class Json < Middleware
9
+ def initialize(app = nil, parser_options: nil, content_type: /\bjson$/, preserve_raw: false)
10
+ super(app)
11
+ @parser_options = parser_options
12
+ @content_types = Array(content_type)
13
+ @preserve_raw = preserve_raw
14
+ end
15
+
16
+ def on_complete(env)
17
+ process_response(env) if parse_response?(env)
18
+ end
19
+
20
+ private
21
+
22
+ def process_response(env)
23
+ env[:raw_body] = env[:body] if @preserve_raw
24
+ env[:body] = parse(env[:body])
25
+ rescue StandardError, SyntaxError => e
26
+ raise Faraday::ParsingError.new(e, env[:response])
27
+ end
28
+
29
+ def parse(body)
30
+ ::JSON.parse(body, @parser_options || {}) unless body.strip.empty?
31
+ end
32
+
33
+ def parse_response?(env)
34
+ process_response_type?(env) &&
35
+ env[:body].respond_to?(:to_str)
36
+ end
37
+
38
+ def process_response_type?(env)
39
+ type = response_type(env)
40
+ @content_types.empty? || @content_types.any? do |pattern|
41
+ pattern.is_a?(Regexp) ? type.match?(pattern) : type == pattern
42
+ end
43
+ end
44
+
45
+ def response_type(env)
46
+ type = env[:response_headers][CONTENT_TYPE].to_s
47
+ type = type.split(';', 2).first if type.index(';')
48
+ type
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ Faraday::Response.register_middleware(json: Faraday::Response::Json)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
+ require 'logger'
4
5
  require 'faraday/logging/formatter'
5
6
 
6
7
  module Faraday
@@ -11,10 +12,7 @@ module Faraday
11
12
  class Logger < Middleware
12
13
  def initialize(app, logger = nil, options = {})
13
14
  super(app)
14
- logger ||= begin
15
- require 'logger'
16
- ::Logger.new($stdout)
17
- end
15
+ logger ||= ::Logger.new($stdout)
18
16
  formatter_class = options.delete(:formatter) || Logging::Formatter
19
17
  @formatter = formatter_class.new(logger: logger, options: options)
20
18
  yield @formatter if block_given?
@@ -31,3 +29,5 @@ module Faraday
31
29
  end
32
30
  end
33
31
  end
32
+
33
+ Faraday::Response.register_middleware(logger: Faraday::Response::Logger)
@@ -38,8 +38,27 @@ module Faraday
38
38
  end
39
39
 
40
40
  def response_values(env)
41
- { status: env.status, headers: env.response_headers, body: env.body }
41
+ {
42
+ status: env.status,
43
+ headers: env.response_headers,
44
+ body: env.body,
45
+ request: {
46
+ method: env.method,
47
+ url: env.url,
48
+ url_path: env.url.path,
49
+ params: query_params(env),
50
+ headers: env.request_headers,
51
+ body: env.request_body
52
+ }
53
+ }
54
+ end
55
+
56
+ def query_params(env)
57
+ env.request.params_encoder ||= Faraday::Utils.default_params_encoder
58
+ env.params_encoder.decode(env.url.query)
42
59
  end
43
60
  end
44
61
  end
45
62
  end
63
+
64
+ Faraday::Response.register_middleware(raise_error: Faraday::Response::RaiseError)
@@ -5,28 +5,9 @@ require 'forwardable'
5
5
  module Faraday
6
6
  # Response represents an HTTP response from making an HTTP request.
7
7
  class Response
8
- # Used for simple response middleware.
9
- class Middleware < Faraday::Middleware
10
- def call(env)
11
- @app.call(env).on_complete do |environment|
12
- on_complete(environment)
13
- end
14
- end
15
-
16
- # Override this to modify the environment after the response has finished.
17
- # Calls the `parse` method if defined
18
- def on_complete(env)
19
- env.body = parse(env.body) if respond_to?(:parse) && env.parse_body?
20
- end
21
- end
22
-
23
8
  extend Forwardable
24
9
  extend MiddlewareRegistry
25
10
 
26
- register_middleware File.expand_path('response', __dir__),
27
- raise_error: [:RaiseError, 'raise_error'],
28
- logger: [:Logger, 'logger']
29
-
30
11
  def initialize(env = nil)
31
12
  @env = Env.from(env) if env
32
13
  @on_complete_callbacks = []
@@ -45,6 +26,7 @@ module Faraday
45
26
  def headers
46
27
  finished? ? env.response_headers : {}
47
28
  end
29
+
48
30
  def_delegator :headers, :[]
49
31
 
50
32
  def body
@@ -56,10 +38,10 @@ module Faraday
56
38
  end
57
39
 
58
40
  def on_complete(&block)
59
- if !finished?
60
- @on_complete_callbacks << block
61
- else
41
+ if finished?
62
42
  yield(env)
43
+ else
44
+ @on_complete_callbacks << block
63
45
  end
64
46
  self
65
47
  end
@@ -102,3 +84,7 @@ module Faraday
102
84
  end
103
85
  end
104
86
  end
87
+
88
+ require 'faraday/response/json'
89
+ require 'faraday/response/logger'
90
+ require 'faraday/response/raise_error'
@@ -105,16 +105,16 @@ module Faraday
105
105
  end
106
106
 
107
107
  def to_hash
108
- ::Hash.new.update(self)
108
+ {}.update(self)
109
109
  end
110
110
 
111
111
  def parse(header_string)
112
112
  return unless header_string && !header_string.empty?
113
113
 
114
- headers = header_string.split(/\r\n/)
114
+ headers = header_string.split("\r\n")
115
115
 
116
116
  # Find the last set of response headers.
117
- start_index = headers.rindex { |x| x.match(%r{^HTTP/}) } || 0
117
+ start_index = headers.rindex { |x| x.start_with?('HTTP/') } || 0
118
118
  last_response = headers.slice(start_index, headers.size)
119
119
 
120
120
  last_response
data/lib/faraday/utils.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
4
+ require 'uri'
3
5
  require 'faraday/utils/headers'
4
6
  require 'faraday/utils/params_hash'
5
7
 
@@ -16,12 +18,20 @@ module Faraday
16
18
  NestedParamsEncoder.encode(params)
17
19
  end
18
20
 
21
+ def default_space_encoding
22
+ @default_space_encoding ||= '+'
23
+ end
24
+
25
+ class << self
26
+ attr_writer :default_space_encoding
27
+ end
28
+
19
29
  ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
20
30
 
21
31
  def escape(str)
22
32
  str.to_s.gsub(ESCAPE_RE) do |match|
23
- '%' + match.unpack('H2' * match.bytesize).join('%').upcase
24
- end.tr(' ', '+')
33
+ "%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
34
+ end.gsub(' ', default_space_encoding)
25
35
  end
26
36
 
27
37
  def unescape(str)
@@ -43,6 +53,12 @@ module Faraday
43
53
  @default_params_encoder ||= NestedParamsEncoder
44
54
  end
45
55
 
56
+ def basic_header_from(login, pass)
57
+ value = Base64.encode64("#{login}:#{pass}")
58
+ value.delete!("\n")
59
+ "Basic #{value}"
60
+ end
61
+
46
62
  class << self
47
63
  attr_writer :default_params_encoder
48
64
  end
@@ -63,10 +79,7 @@ module Faraday
63
79
  end
64
80
 
65
81
  def default_uri_parser
66
- @default_uri_parser ||= begin
67
- require 'uri'
68
- Kernel.method(:URI)
69
- end
82
+ @default_uri_parser ||= Kernel.method(:URI)
70
83
  end
71
84
 
72
85
  def default_uri_parser=(parser)
@@ -81,14 +94,14 @@ module Faraday
81
94
  # the path with the query string sorted.
82
95
  def normalize_path(url)
83
96
  url = URI(url)
84
- (url.path.start_with?('/') ? url.path : '/' + url.path) +
97
+ (url.path.start_with?('/') ? url.path : "/#{url.path}") +
85
98
  (url.query ? "?#{sort_query_params(url.query)}" : '')
86
99
  end
87
100
 
88
101
  # Recursive hash update
89
102
  def deep_merge!(target, hash)
90
103
  hash.each do |key, value|
91
- target[key] = if value.is_a?(Hash) && target[key].is_a?(Hash)
104
+ target[key] = if value.is_a?(Hash) && (target[key].is_a?(Hash) || target[key].is_a?(Options))
92
105
  deep_merge(target[key], value)
93
106
  else
94
107
  value
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ VERSION = '2.0.0'
5
+ end