faraday 1.0.0.pre.rc1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +350 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +6 -7
  5. data/Rakefile +7 -0
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday.rb +51 -41
  9. data/lib/faraday/adapter.rb +47 -1
  10. data/lib/faraday/adapter/em_http.rb +23 -20
  11. data/lib/faraday/adapter/em_http_ssl_patch.rb +1 -1
  12. data/lib/faraday/adapter/em_synchrony.rb +16 -13
  13. data/lib/faraday/adapter/excon.rb +26 -24
  14. data/lib/faraday/adapter/httpclient.rb +42 -40
  15. data/lib/faraday/adapter/net_http_persistent.rb +4 -2
  16. data/lib/faraday/adapter/patron.rb +42 -24
  17. data/lib/faraday/adapter/rack.rb +2 -1
  18. data/lib/faraday/adapter/typhoeus.rb +1 -1
  19. data/lib/faraday/adapter_registry.rb +3 -1
  20. data/lib/faraday/autoload.rb +1 -2
  21. data/lib/faraday/connection.rb +13 -25
  22. data/lib/faraday/encoders/flat_params_encoder.rb +16 -5
  23. data/lib/faraday/encoders/nested_params_encoder.rb +7 -2
  24. data/lib/faraday/error.rb +64 -12
  25. data/lib/faraday/{upload_io.rb → file_part.rb} +53 -3
  26. data/lib/faraday/logging/formatter.rb +28 -15
  27. data/lib/faraday/methods.rb +6 -0
  28. data/lib/faraday/middleware.rb +19 -1
  29. data/lib/faraday/options.rb +5 -9
  30. data/lib/faraday/options/env.rb +1 -1
  31. data/lib/faraday/options/request_options.rb +3 -2
  32. data/lib/faraday/param_part.rb +53 -0
  33. data/lib/faraday/rack_builder.rb +13 -12
  34. data/lib/faraday/request.rb +20 -10
  35. data/lib/faraday/request/authorization.rb +3 -1
  36. data/lib/faraday/request/multipart.rb +19 -4
  37. data/lib/faraday/request/retry.rb +2 -2
  38. data/lib/faraday/request/url_encoded.rb +3 -1
  39. data/lib/faraday/response.rb +6 -9
  40. data/lib/faraday/response/raise_error.rb +14 -1
  41. data/lib/faraday/utils.rb +11 -3
  42. data/lib/faraday/utils/headers.rb +2 -2
  43. data/lib/faraday/version.rb +5 -0
  44. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  45. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  46. data/spec/faraday/adapter/excon_spec.rb +49 -0
  47. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  48. data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
  49. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  50. data/spec/faraday/adapter/patron_spec.rb +18 -0
  51. data/spec/faraday/adapter/rack_spec.rb +8 -0
  52. data/spec/faraday/adapter/test_spec.rb +260 -0
  53. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  54. data/spec/faraday/adapter_registry_spec.rb +28 -0
  55. data/spec/faraday/adapter_spec.rb +55 -0
  56. data/spec/faraday/composite_read_io_spec.rb +80 -0
  57. data/spec/faraday/connection_spec.rb +691 -0
  58. data/spec/faraday/error_spec.rb +60 -0
  59. data/spec/faraday/middleware_spec.rb +52 -0
  60. data/spec/faraday/options/env_spec.rb +70 -0
  61. data/spec/faraday/options/options_spec.rb +297 -0
  62. data/spec/faraday/options/proxy_options_spec.rb +37 -0
  63. data/spec/faraday/options/request_options_spec.rb +19 -0
  64. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  65. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  66. data/spec/faraday/rack_builder_spec.rb +345 -0
  67. data/spec/faraday/request/authorization_spec.rb +88 -0
  68. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  69. data/spec/faraday/request/multipart_spec.rb +302 -0
  70. data/spec/faraday/request/retry_spec.rb +242 -0
  71. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  72. data/spec/faraday/request_spec.rb +120 -0
  73. data/spec/faraday/response/logger_spec.rb +220 -0
  74. data/spec/faraday/response/middleware_spec.rb +68 -0
  75. data/spec/faraday/response/raise_error_spec.rb +169 -0
  76. data/spec/faraday/response_spec.rb +75 -0
  77. data/spec/faraday/utils/headers_spec.rb +82 -0
  78. data/spec/faraday/utils_spec.rb +56 -0
  79. data/spec/faraday_spec.rb +37 -0
  80. data/spec/spec_helper.rb +132 -0
  81. data/spec/support/disabling_stub.rb +14 -0
  82. data/spec/support/fake_safe_buffer.rb +15 -0
  83. data/spec/support/helper_methods.rb +133 -0
  84. data/spec/support/shared_examples/adapter.rb +105 -0
  85. data/spec/support/shared_examples/params_encoder.rb +18 -0
  86. data/spec/support/shared_examples/request_method.rb +262 -0
  87. data/spec/support/streaming_response_checker.rb +35 -0
  88. data/spec/support/webmock_rack_app.rb +68 -0
  89. metadata +96 -12
  90. data/lib/faraday/adapter/net_http.rb +0 -205
@@ -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,7 +26,9 @@ 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(
30
+ :http_method, :path, :params, :headers, :body, :options
31
+ )
30
32
  # rubocop:enable Style/StructInheritance
31
33
 
32
34
  extend MiddlewareRegistry
@@ -56,6 +58,14 @@ module Faraday
56
58
  end
57
59
  end
58
60
 
61
+ def method
62
+ warn <<~TEXT
63
+ WARNING: `Faraday::Request##{__method__}` is deprecated; use `#http_method` instead. It will be removed in or after version 2.0.
64
+ `Faraday::Request##{__method__}` called from #{caller_locations(1..1).first}
65
+ TEXT
66
+ http_method
67
+ end
68
+
59
69
  # Replace params, preserving the existing hash type.
60
70
  #
61
71
  # @param hash [Hash] new params
@@ -116,7 +126,7 @@ module Faraday
116
126
  # @return [Hash] the hash ready to be serialized in Marshal.
117
127
  def marshal_dump
118
128
  {
119
- method: method,
129
+ http_method: http_method,
120
130
  body: body,
121
131
  headers: headers,
122
132
  path: path,
@@ -129,17 +139,17 @@ module Faraday
129
139
  # Restores the instance variables according to the +serialised+.
130
140
  # @param serialised [Hash] the serialised object.
131
141
  def marshal_load(serialised)
132
- self.method = serialised[:method]
133
- self.body = serialised[:body]
134
- self.headers = serialised[:headers]
135
- self.path = serialised[:path]
136
- self.params = serialised[:params]
137
- self.options = serialised[:options]
142
+ self.http_method = serialised[:http_method]
143
+ self.body = serialised[:body]
144
+ self.headers = serialised[:headers]
145
+ self.path = serialised[:path]
146
+ self.params = serialised[:params]
147
+ self.options = serialised[:options]
138
148
  end
139
149
 
140
150
  # @return [Env] the Env for this Request
141
151
  def to_env(connection)
142
- Env.new(method, body, connection.build_exclusive_url(path, params),
152
+ Env.new(http_method, body, connection.build_exclusive_url(path, params),
143
153
  options, headers, connection.ssl, connection.parallel_manager)
144
154
  end
145
155
  end
@@ -4,7 +4,9 @@ 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
7
+ unless defined?(::Faraday::Request::Authorization::KEY)
8
+ KEY = 'Authorization'
9
+ end
8
10
 
9
11
  # @param type [String, Symbol]
10
12
  # @param token [String, Symbol, Hash]
@@ -8,10 +8,15 @@ module Faraday
8
8
  # Middleware for supporting multi-part requests.
9
9
  class Multipart < UrlEncoded
10
10
  self.mime_type = 'multipart/form-data'
11
- unless defined? DEFAULT_BOUNDARY_PREFIX
11
+ unless defined?(::Faraday::Request::Multipart::DEFAULT_BOUNDARY_PREFIX)
12
12
  DEFAULT_BOUNDARY_PREFIX = '-----------RubyMultipartPost'
13
13
  end
14
14
 
15
+ def initialize(app = nil, options = {})
16
+ super(app)
17
+ @options = options
18
+ end
19
+
15
20
  # Checks for files in the payload, otherwise leaves everything untouched.
16
21
  #
17
22
  # @param env [Faraday::Env]
@@ -30,7 +35,7 @@ module Faraday
30
35
  type = request_type(env)
31
36
  env.body.respond_to?(:each_key) && !env.body.empty? && (
32
37
  (type.empty? && has_multipart?(env.body)) ||
33
- (type == self.class.mime_type)
38
+ (type == self.class.mime_type)
34
39
  )
35
40
  end
36
41
 
@@ -52,7 +57,7 @@ module Faraday
52
57
  def create_multipart(env, params)
53
58
  boundary = env.request.boundary
54
59
  parts = process_params(params) do |key, value|
55
- Faraday::Parts::Part.new(boundary, key, value)
60
+ part(boundary, key, value)
56
61
  end
57
62
  parts << Faraday::Parts::EpiloguePart.new(boundary)
58
63
 
@@ -61,6 +66,14 @@ module Faraday
61
66
  body
62
67
  end
63
68
 
69
+ def part(boundary, key, value)
70
+ if value.respond_to?(:to_part)
71
+ value.to_part(boundary, key)
72
+ else
73
+ Faraday::Parts::Part.new(boundary, key, value)
74
+ end
75
+ end
76
+
64
77
  # @return [String]
65
78
  def unique_boundary
66
79
  "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
@@ -71,7 +84,9 @@ module Faraday
71
84
  # @param pieces [Array]
72
85
  def process_params(params, prefix = nil, pieces = nil, &block)
73
86
  params.inject(pieces || []) do |all, (key, value)|
74
- key = "#{prefix}[#{key}]" if prefix
87
+ if prefix
88
+ key = @options[:flat_encode] ? prefix.to_s : "#{prefix}[#{key}]"
89
+ end
75
90
 
76
91
  case value
77
92
  when Array
@@ -21,7 +21,7 @@ module Faraday
21
21
  # end
22
22
  #
23
23
  # This example will result in a first interval that is random between 0.05
24
- # and 0.075 and a second interval that is random between 0.1 and 0.15.
24
+ # and 0.075 and a second interval that is random between 0.1 and 0.125.
25
25
  class Retry < Faraday::Middleware
26
26
  DEFAULT_EXCEPTIONS = [
27
27
  Errno::ETIMEDOUT, 'Timeout::Error',
@@ -112,7 +112,7 @@ module Faraday
112
112
  # not independent of the retry count. This would be useful
113
113
  # if the exception produced is non-recoverable or if the
114
114
  # the HTTP method called is not idempotent.
115
- # @option options [Block] :retry_block block that is executed after
115
+ # @option options [Block] :retry_block block that is executed before
116
116
  # every retry. Request environment, middleware options, current number
117
117
  # of retries and the exception is passed to the block as parameters.
118
118
  # @option options [Array] :retry_statuses Array of Integer HTTP status
@@ -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
@@ -7,16 +7,13 @@ module Faraday
7
7
  class Response
8
8
  # Used for simple response middleware.
9
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
10
  # Override this to modify the environment after the response has finished.
17
11
  # Calls the `parse` method if defined
12
+ # `parse` method can be defined as private, public and protected
18
13
  def on_complete(env)
19
- env.body = parse(env.body) if respond_to?(:parse) && env.parse_body?
14
+ return unless respond_to?(:parse, true) && env.parse_body?
15
+
16
+ env.body = parse(env.body)
20
17
  end
21
18
  end
22
19
 
@@ -55,9 +52,9 @@ module Faraday
55
52
  !!env
56
53
  end
57
54
 
58
- def on_complete
55
+ def on_complete(&block)
59
56
  if !finished?
60
- @on_complete_callbacks << Proc.new
57
+ @on_complete_callbacks << block
61
58
  else
62
59
  yield(env)
63
60
  end
@@ -32,11 +32,24 @@ module Faraday
32
32
  raise Faraday::ClientError, response_values(env)
33
33
  when ServerErrorStatuses
34
34
  raise Faraday::ServerError, response_values(env)
35
+ when nil
36
+ raise Faraday::NilStatusError, response_values(env)
35
37
  end
36
38
  end
37
39
 
38
40
  def response_values(env)
39
- { 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_path: env.url.path,
48
+ params: env.params,
49
+ headers: env.request_headers,
50
+ body: env.request_body
51
+ }
52
+ }
40
53
  end
41
54
  end
42
55
  end
@@ -16,12 +16,20 @@ module Faraday
16
16
  NestedParamsEncoder.encode(params)
17
17
  end
18
18
 
19
+ def default_space_encoding
20
+ @default_space_encoding ||= '+'
21
+ end
22
+
23
+ class << self
24
+ attr_writer :default_space_encoding
25
+ end
26
+
19
27
  ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
20
28
 
21
29
  def escape(str)
22
30
  str.to_s.gsub(ESCAPE_RE) do |match|
23
- '%' + match.unpack('H2' * match.bytesize).join('%').upcase
24
- end.tr(' ', '+')
31
+ "%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
32
+ end.gsub(' ', default_space_encoding)
25
33
  end
26
34
 
27
35
  def unescape(str)
@@ -81,7 +89,7 @@ module Faraday
81
89
  # the path with the query string sorted.
82
90
  def normalize_path(url)
83
91
  url = URI(url)
84
- (url.path.start_with?('/') ? url.path : '/' + url.path) +
92
+ (url.path.start_with?('/') ? url.path : "/#{url.path}") +
85
93
  (url.query ? "?#{sort_query_params(url.query)}" : '')
86
94
  end
87
95
 
@@ -105,7 +105,7 @@ 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)
@@ -114,7 +114,7 @@ module Faraday
114
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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ VERSION = '1.3.0'
5
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::EMHttp, unless: defined?(JRUBY_VERSION) do
4
+ features :request_body_on_query_methods, :reason_phrase_parse, :trace_method,
5
+ :skip_response_body_on_head, :parallel, :local_socket_binding
6
+
7
+ it_behaves_like 'an adapter'
8
+
9
+ it 'allows to provide adapter specific configs' do
10
+ url = URI('https://example.com:1234')
11
+ adapter = described_class.new nil, inactivity_timeout: 20
12
+ req = adapter.create_request(url: url, request: {})
13
+
14
+ expect(req.connopts.inactivity_timeout).to eq(20)
15
+ end
16
+
17
+ context 'Options' do
18
+ let(:request) { Faraday::RequestOptions.new }
19
+ let(:env) { { request: request } }
20
+ let(:options) { {} }
21
+ let(:adapter) { Faraday::Adapter::EMHttp.new }
22
+
23
+ it 'configures timeout' do
24
+ request.timeout = 5
25
+ adapter.configure_timeout(options, env)
26
+ expect(options[:inactivity_timeout]).to eq(5)
27
+ expect(options[:connect_timeout]).to eq(5)
28
+ end
29
+
30
+ it 'configures timeout and open_timeout' do
31
+ request.timeout = 5
32
+ request.open_timeout = 1
33
+ adapter.configure_timeout(options, env)
34
+ expect(options[:inactivity_timeout]).to eq(5)
35
+ expect(options[:connect_timeout]).to eq(1)
36
+ end
37
+
38
+ it 'configures all timeout settings' do
39
+ request.timeout = 5
40
+ request.read_timeout = 3
41
+ request.open_timeout = 1
42
+ adapter.configure_timeout(options, env)
43
+ expect(options[:inactivity_timeout]).to eq(3)
44
+ expect(options[:connect_timeout]).to eq(1)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::EMSynchrony, unless: defined?(JRUBY_VERSION) do
4
+ features :request_body_on_query_methods, :reason_phrase_parse,
5
+ :skip_response_body_on_head, :parallel, :local_socket_binding
6
+
7
+ it_behaves_like 'an adapter'
8
+
9
+ it 'allows to provide adapter specific configs' do
10
+ url = URI('https://example.com:1234')
11
+ adapter = described_class.new nil, inactivity_timeout: 20
12
+ req = adapter.create_request(url: url, request: {})
13
+
14
+ expect(req.connopts.inactivity_timeout).to eq(20)
15
+ end
16
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::Excon do
4
+ features :request_body_on_query_methods, :reason_phrase_parse, :trace_method
5
+
6
+ it_behaves_like 'an adapter'
7
+
8
+ it 'allows to provide adapter specific configs' do
9
+ url = URI('https://example.com:1234')
10
+
11
+ adapter = described_class.new(nil, debug_request: true)
12
+
13
+ conn = adapter.build_connection(url: url)
14
+
15
+ expect(conn.data[:debug_request]).to be_truthy
16
+ end
17
+
18
+ context 'config' do
19
+ let(:adapter) { Faraday::Adapter::Excon.new }
20
+ let(:request) { Faraday::RequestOptions.new }
21
+ let(:uri) { URI.parse('https://example.com') }
22
+ let(:env) { { request: request, url: uri } }
23
+
24
+ it 'sets timeout' do
25
+ request.timeout = 5
26
+ options = adapter.send(:opts_from_env, env)
27
+ expect(options[:read_timeout]).to eq(5)
28
+ expect(options[:write_timeout]).to eq(5)
29
+ expect(options[:connect_timeout]).to eq(5)
30
+ end
31
+
32
+ it 'sets timeout and open_timeout' do
33
+ request.timeout = 5
34
+ request.open_timeout = 3
35
+ options = adapter.send(:opts_from_env, env)
36
+ expect(options[:read_timeout]).to eq(5)
37
+ expect(options[:write_timeout]).to eq(5)
38
+ expect(options[:connect_timeout]).to eq(3)
39
+ end
40
+
41
+ it 'sets open_timeout' do
42
+ request.open_timeout = 3
43
+ options = adapter.send(:opts_from_env, env)
44
+ expect(options[:read_timeout]).to eq(nil)
45
+ expect(options[:write_timeout]).to eq(nil)
46
+ expect(options[:connect_timeout]).to eq(3)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::HTTPClient do
4
+ # ruby gem defaults for testing purposes
5
+ HTTPCLIENT_OPEN = 60
6
+ HTTPCLIENT_READ = 60
7
+ HTTPCLIENT_WRITE = 120
8
+
9
+ features :request_body_on_query_methods, :reason_phrase_parse, :compression,
10
+ :trace_method, :local_socket_binding
11
+
12
+ it_behaves_like 'an adapter'
13
+
14
+ it 'allows to provide adapter specific configs' do
15
+ adapter = described_class.new do |client|
16
+ client.keep_alive_timeout = 20
17
+ client.ssl_config.timeout = 25
18
+ end
19
+
20
+ client = adapter.build_connection(url: URI.parse('https://example.com'))
21
+ expect(client.keep_alive_timeout).to eq(20)
22
+ expect(client.ssl_config.timeout).to eq(25)
23
+ end
24
+
25
+ context 'Options' do
26
+ let(:request) { Faraday::RequestOptions.new }
27
+ let(:env) { { request: request } }
28
+ let(:options) { {} }
29
+ let(:adapter) { Faraday::Adapter::HTTPClient.new }
30
+ let(:client) { adapter.connection(url: URI.parse('https://example.com')) }
31
+
32
+ it 'configures timeout' do
33
+ assert_default_timeouts!
34
+
35
+ request.timeout = 5
36
+ adapter.configure_timeouts(client, request)
37
+
38
+ expect(client.connect_timeout).to eq(5)
39
+ expect(client.send_timeout).to eq(5)
40
+ expect(client.receive_timeout).to eq(5)
41
+ end
42
+
43
+ it 'configures open timeout' do
44
+ assert_default_timeouts!
45
+
46
+ request.open_timeout = 1
47
+ adapter.configure_timeouts(client, request)
48
+
49
+ expect(client.connect_timeout).to eq(1)
50
+ expect(client.send_timeout).to eq(HTTPCLIENT_WRITE)
51
+ expect(client.receive_timeout).to eq(HTTPCLIENT_READ)
52
+ end
53
+
54
+ it 'configures multiple timeouts' do
55
+ assert_default_timeouts!
56
+
57
+ request.open_timeout = 1
58
+ request.write_timeout = 10
59
+ request.read_timeout = 5
60
+ adapter.configure_timeouts(client, request)
61
+
62
+ expect(client.connect_timeout).to eq(1)
63
+ expect(client.send_timeout).to eq(10)
64
+ expect(client.receive_timeout).to eq(5)
65
+ end
66
+
67
+ def assert_default_timeouts!
68
+ expect(client.connect_timeout).to eq(HTTPCLIENT_OPEN)
69
+ expect(client.send_timeout).to eq(HTTPCLIENT_WRITE)
70
+ expect(client.receive_timeout).to eq(HTTPCLIENT_READ)
71
+ end
72
+ end
73
+ end