faraday 1.0.0.pre.rc1 → 1.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +276 -0
  3. data/README.md +4 -4
  4. data/Rakefile +7 -0
  5. data/UPGRADING.md +55 -0
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday.rb +4 -4
  9. data/lib/faraday/adapter.rb +46 -0
  10. data/lib/faraday/adapter/em_http.rb +5 -6
  11. data/lib/faraday/adapter/em_http_ssl_patch.rb +1 -1
  12. data/lib/faraday/adapter/excon.rb +24 -22
  13. data/lib/faraday/adapter/httpclient.rb +40 -39
  14. data/lib/faraday/adapter/net_http.rb +42 -38
  15. data/lib/faraday/adapter/net_http_persistent.rb +3 -1
  16. data/lib/faraday/adapter/patron.rb +42 -24
  17. data/lib/faraday/adapter/rack.rb +2 -1
  18. data/lib/faraday/connection.rb +10 -22
  19. data/lib/faraday/encoders/flat_params_encoder.rb +7 -3
  20. data/lib/faraday/error.rb +44 -12
  21. data/lib/faraday/{upload_io.rb → file_part.rb} +53 -3
  22. data/lib/faraday/logging/formatter.rb +28 -15
  23. data/lib/faraday/middleware.rb +8 -0
  24. data/lib/faraday/options.rb +1 -1
  25. data/lib/faraday/options/env.rb +1 -1
  26. data/lib/faraday/options/request_options.rb +3 -2
  27. data/lib/faraday/param_part.rb +53 -0
  28. data/lib/faraday/request/multipart.rb +9 -1
  29. data/lib/faraday/response.rb +2 -2
  30. data/lib/faraday/response/raise_error.rb +2 -0
  31. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  32. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  33. data/spec/faraday/adapter/excon_spec.rb +49 -0
  34. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  35. data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
  36. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  37. data/spec/faraday/adapter/patron_spec.rb +18 -0
  38. data/spec/faraday/adapter/rack_spec.rb +8 -0
  39. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  40. data/spec/faraday/adapter_registry_spec.rb +28 -0
  41. data/spec/faraday/adapter_spec.rb +55 -0
  42. data/spec/faraday/composite_read_io_spec.rb +80 -0
  43. data/spec/faraday/connection_spec.rb +691 -0
  44. data/spec/faraday/error_spec.rb +45 -0
  45. data/spec/faraday/middleware_spec.rb +26 -0
  46. data/spec/faraday/options/env_spec.rb +70 -0
  47. data/spec/faraday/options/options_spec.rb +297 -0
  48. data/spec/faraday/options/proxy_options_spec.rb +37 -0
  49. data/spec/faraday/options/request_options_spec.rb +19 -0
  50. data/spec/faraday/params_encoders/flat_spec.rb +34 -0
  51. data/spec/faraday/params_encoders/nested_spec.rb +134 -0
  52. data/spec/faraday/rack_builder_spec.rb +196 -0
  53. data/spec/faraday/request/authorization_spec.rb +88 -0
  54. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  55. data/spec/faraday/request/multipart_spec.rb +274 -0
  56. data/spec/faraday/request/retry_spec.rb +242 -0
  57. data/spec/faraday/request/url_encoded_spec.rb +70 -0
  58. data/spec/faraday/request_spec.rb +109 -0
  59. data/spec/faraday/response/logger_spec.rb +220 -0
  60. data/spec/faraday/response/middleware_spec.rb +52 -0
  61. data/spec/faraday/response/raise_error_spec.rb +106 -0
  62. data/spec/faraday/response_spec.rb +75 -0
  63. data/spec/faraday/utils/headers_spec.rb +82 -0
  64. data/spec/faraday/utils_spec.rb +56 -0
  65. data/spec/faraday_spec.rb +37 -0
  66. data/spec/spec_helper.rb +132 -0
  67. data/spec/support/disabling_stub.rb +14 -0
  68. data/spec/support/fake_safe_buffer.rb +15 -0
  69. data/spec/support/helper_methods.rb +133 -0
  70. data/spec/support/shared_examples/adapter.rb +104 -0
  71. data/spec/support/shared_examples/params_encoder.rb +18 -0
  72. data/spec/support/shared_examples/request_method.rb +234 -0
  73. data/spec/support/streaming_response_checker.rb +35 -0
  74. data/spec/support/webmock_rack_app.rb +68 -0
  75. metadata +65 -11
@@ -132,7 +132,7 @@ module Faraday
132
132
  # Sets content length to zero and the body to the empty string.
133
133
  def clear_body
134
134
  request_headers[ContentLength] = '0'
135
- self.body = ''
135
+ self.body = +''
136
136
  end
137
137
 
138
138
  # @return [Boolean] true if the status isn't in the set of
@@ -3,8 +3,9 @@
3
3
  module Faraday
4
4
  # RequestOptions contains the configurable properties for a Faraday request.
5
5
  class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
6
- :timeout, :open_timeout, :write_timeout,
7
- :boundary, :oauth, :context, :on_data)
6
+ :timeout, :open_timeout, :read_timeout,
7
+ :write_timeout, :boundary, :oauth,
8
+ :context, :on_data)
8
9
 
9
10
  def []=(key, value)
10
11
  if key && key.to_sym == :proxy
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # Multipart value used to POST data with a content type.
5
+ class ParamPart
6
+ # @param value [String] Uploaded content as a String.
7
+ # @param content_type [String] String content type of the value.
8
+ # @param content_id [String] Optional String of this value's Content-ID.
9
+ #
10
+ # @return [Faraday::ParamPart]
11
+ def initialize(value, content_type, content_id = nil)
12
+ @value = value
13
+ @content_type = content_type
14
+ @content_id = content_id
15
+ end
16
+
17
+ # Converts this value to a form part.
18
+ #
19
+ # @param boundary [String] String multipart boundary that must not exist in
20
+ # the content exactly.
21
+ # @param key [String] String key name for this value.
22
+ #
23
+ # @return [Faraday::Parts::Part]
24
+ def to_part(boundary, key)
25
+ Faraday::Parts::Part.new(boundary, key, value, headers)
26
+ end
27
+
28
+ # Returns a Hash of String key/value pairs.
29
+ #
30
+ # @return [Hash]
31
+ def headers
32
+ {
33
+ 'Content-Type' => content_type,
34
+ 'Content-ID' => content_id
35
+ }
36
+ end
37
+
38
+ # The content to upload.
39
+ #
40
+ # @return [String]
41
+ attr_reader :value
42
+
43
+ # The value's content type.
44
+ #
45
+ # @return [String]
46
+ attr_reader :content_type
47
+
48
+ # The value's content ID, if given.
49
+ #
50
+ # @return [String, nil]
51
+ attr_reader :content_id
52
+ end
53
+ end
@@ -52,7 +52,7 @@ module Faraday
52
52
  def create_multipart(env, params)
53
53
  boundary = env.request.boundary
54
54
  parts = process_params(params) do |key, value|
55
- Faraday::Parts::Part.new(boundary, key, value)
55
+ part(boundary, key, value)
56
56
  end
57
57
  parts << Faraday::Parts::EpiloguePart.new(boundary)
58
58
 
@@ -61,6 +61,14 @@ module Faraday
61
61
  body
62
62
  end
63
63
 
64
+ def part(boundary, key, value)
65
+ if value.respond_to?(:to_part)
66
+ value.to_part(boundary, key)
67
+ else
68
+ Faraday::Parts::Part.new(boundary, key, value)
69
+ end
70
+ end
71
+
64
72
  # @return [String]
65
73
  def unique_boundary
66
74
  "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
@@ -55,9 +55,9 @@ module Faraday
55
55
  !!env
56
56
  end
57
57
 
58
- def on_complete
58
+ def on_complete(&block)
59
59
  if !finished?
60
- @on_complete_callbacks << Proc.new
60
+ @on_complete_callbacks << block
61
61
  else
62
62
  yield(env)
63
63
  end
@@ -32,6 +32,8 @@ 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
 
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::EMHttp 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 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
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::NetHttpPersistent do
4
+ features :request_body_on_query_methods, :reason_phrase_parse, :compression, :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')
10
+
11
+ adapter = described_class.new do |http|
12
+ http.idle_timeout = 123
13
+ end
14
+
15
+ http = adapter.send(:connection, url: url, request: {})
16
+ adapter.send(:configure_request, http, {})
17
+
18
+ expect(http.idle_timeout).to eq(123)
19
+ end
20
+
21
+ it 'sets max_retries to 0' do
22
+ url = URI('http://example.com')
23
+
24
+ adapter = described_class.new
25
+
26
+ http = adapter.send(:connection, url: url, request: {})
27
+ adapter.send(:configure_request, http, {})
28
+
29
+ # `max_retries=` is only present in Ruby 2.5
30
+ expect(http.max_retries).to eq(0) if http.respond_to?(:max_retries=)
31
+ end
32
+
33
+ it 'allows to set pool_size on initialize' do
34
+ url = URI('https://example.com')
35
+
36
+ adapter = described_class.new(nil, pool_size: 5)
37
+
38
+ http = adapter.send(:connection, url: url, request: {})
39
+
40
+ # `pool` is only present in net_http_persistent >= 3.0
41
+ expect(http.pool.size).to eq(5) if http.respond_to?(:pool)
42
+ end
43
+
44
+ context 'min_version' do
45
+ it 'allows to set min_version in SSL settings' do
46
+ url = URI('https://example.com')
47
+
48
+ adapter = described_class.new(nil)
49
+
50
+ http = adapter.send(:connection, url: url, request: {})
51
+ adapter.send(:configure_ssl, http, min_version: :TLS1_2)
52
+
53
+ # `min_version` is only present in net_http_persistent >= 3.1 (UNRELEASED)
54
+ expect(http.min_version).to eq(:TLS1_2) if http.respond_to?(:min_version)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::NetHttp do
4
+ features :request_body_on_query_methods, :reason_phrase_parse, :compression, :streaming, :trace_method
5
+
6
+ it_behaves_like 'an adapter'
7
+
8
+ context 'checking http' do
9
+ let(:url) { URI('http://example.com') }
10
+ let(:adapter) { described_class.new }
11
+ let(:http) { adapter.send(:connection, url: url, request: {}) }
12
+
13
+ it { expect(http.port).to eq(80) }
14
+
15
+ it 'sets max_retries to 0' do
16
+ adapter.send(:configure_request, http, {})
17
+
18
+ expect(http.max_retries).to eq(0) if http.respond_to?(:max_retries=)
19
+ end
20
+
21
+ it 'supports write_timeout' do
22
+ adapter.send(:configure_request, http, write_timeout: 10)
23
+
24
+ expect(http.write_timeout).to eq(10) if http.respond_to?(:write_timeout=)
25
+ end
26
+
27
+ it 'supports open_timeout' do
28
+ adapter.send(:configure_request, http, open_timeout: 10)
29
+
30
+ expect(http.open_timeout).to eq(10)
31
+ end
32
+
33
+ it 'supports read_timeout' do
34
+ adapter.send(:configure_request, http, read_timeout: 10)
35
+
36
+ expect(http.read_timeout).to eq(10)
37
+ end
38
+
39
+ context 'with https url' do
40
+ let(:url) { URI('https://example.com') }
41
+
42
+ it { expect(http.port).to eq(443) }
43
+ end
44
+
45
+ context 'with http url including port' do
46
+ let(:url) { URI('https://example.com:1234') }
47
+
48
+ it { expect(http.port).to eq(1234) }
49
+ end
50
+
51
+ context 'with custom adapter config' do
52
+ let(:adapter) do
53
+ described_class.new do |http|
54
+ http.continue_timeout = 123
55
+ end
56
+ end
57
+
58
+ it do
59
+ adapter.send(:configure_request, http, {})
60
+ expect(http.continue_timeout).to eq(123)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::Patron do
4
+ features :reason_phrase_parse
5
+
6
+ it_behaves_like 'an adapter'
7
+
8
+ it 'allows to provide adapter specific configs' do
9
+ conn = Faraday.new do |f|
10
+ f.adapter :patron do |session|
11
+ session.max_redirects = 10
12
+ raise 'Configuration block called'
13
+ end
14
+ end
15
+
16
+ expect { conn.get('/') }.to raise_error(RuntimeError, 'Configuration block called')
17
+ end
18
+ end