faraday 1.4.1 → 1.10.3

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/examples/client_spec.rb +34 -2
  3. data/examples/client_test.rb +41 -2
  4. data/lib/faraday/adapter/test.rb +59 -43
  5. data/lib/faraday/adapter.rb +1 -6
  6. data/lib/faraday/autoload.rb +1 -6
  7. data/lib/faraday/connection.rb +33 -6
  8. data/lib/faraday/dependency_loader.rb +3 -1
  9. data/lib/faraday/deprecate.rb +110 -0
  10. data/lib/faraday/error.rb +0 -6
  11. data/lib/faraday/options/proxy_options.rb +4 -0
  12. data/lib/faraday/request/authorization.rb +14 -7
  13. data/lib/faraday/request/json.rb +55 -0
  14. data/lib/faraday/request.rb +10 -12
  15. data/lib/faraday/response/json.rb +54 -0
  16. data/lib/faraday/response/logger.rb +2 -4
  17. data/lib/faraday/response.rb +3 -1
  18. data/lib/faraday/version.rb +1 -1
  19. data/lib/faraday.rb +19 -4
  20. data/spec/faraday/adapter/em_http_spec.rb +39 -37
  21. data/spec/faraday/adapter/em_synchrony_spec.rb +11 -9
  22. data/spec/faraday/adapter/test_spec.rb +117 -0
  23. data/spec/faraday/connection_spec.rb +15 -0
  24. data/spec/faraday/deprecate_spec.rb +147 -0
  25. data/spec/faraday/options/proxy_options_spec.rb +7 -0
  26. data/spec/faraday/request/authorization_spec.rb +8 -0
  27. data/spec/faraday/request/json_spec.rb +111 -0
  28. data/spec/faraday/request_spec.rb +1 -1
  29. data/spec/faraday/response/json_spec.rb +119 -0
  30. data/spec/spec_helper.rb +2 -0
  31. metadata +99 -28
  32. data/lib/faraday/adapter/em_http.rb +0 -289
  33. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  34. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  35. data/lib/faraday/adapter/em_synchrony.rb +0 -153
  36. data/lib/faraday/adapter/httpclient.rb +0 -152
  37. data/lib/faraday/adapter/patron.rb +0 -132
  38. data/lib/faraday/adapter/rack.rb +0 -75
  39. data/lib/faraday/file_part.rb +0 -128
  40. data/lib/faraday/param_part.rb +0 -53
  41. data/lib/faraday/request/multipart.rb +0 -106
  42. data/lib/faraday/request/retry.rb +0 -239
  43. data/spec/faraday/request/multipart_spec.rb +0 -302
  44. data/spec/faraday/request/retry_spec.rb +0 -242
@@ -1,152 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # HTTPClient adapter.
6
- class HTTPClient < Faraday::Adapter
7
- dependency 'httpclient'
8
-
9
- def build_connection(env)
10
- @client ||= ::HTTPClient.new.tap do |cli|
11
- # enable compression
12
- cli.transparent_gzip_decompression = true
13
- end
14
-
15
- if (req = env[:request])
16
- if (proxy = req[:proxy])
17
- configure_proxy @client, proxy
18
- end
19
-
20
- if (bind = req[:bind])
21
- configure_socket @client, bind
22
- end
23
-
24
- configure_timeouts @client, req
25
- end
26
-
27
- if env[:url].scheme == 'https' && (ssl = env[:ssl])
28
- configure_ssl @client, ssl
29
- end
30
-
31
- configure_client @client
32
-
33
- @client
34
- end
35
-
36
- def call(env)
37
- super
38
-
39
- # TODO: Don't stream yet.
40
- # https://github.com/nahi/httpclient/pull/90
41
- env[:body] = env[:body].read if env[:body].respond_to? :read
42
-
43
- connection(env) do |http|
44
- resp = http.request env[:method], env[:url],
45
- body: env[:body],
46
- header: env[:request_headers]
47
-
48
- if (req = env[:request]).stream_response?
49
- warn "Streaming downloads for #{self.class.name} " \
50
- 'are not yet implemented.'
51
- req.on_data.call(resp.body, resp.body.bytesize)
52
- end
53
- save_response env, resp.status, resp.body, resp.headers, resp.reason
54
-
55
- @app.call env
56
- end
57
- rescue ::HTTPClient::TimeoutError, Errno::ETIMEDOUT
58
- raise Faraday::TimeoutError, $ERROR_INFO
59
- rescue ::HTTPClient::BadResponseError => e
60
- if e.message.include?('status 407')
61
- raise Faraday::ConnectionFailed,
62
- %(407 "Proxy Authentication Required ")
63
- end
64
-
65
- raise Faraday::ClientError, $ERROR_INFO
66
- rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED, IOError, SocketError
67
- raise Faraday::ConnectionFailed, $ERROR_INFO
68
- rescue StandardError => e
69
- if defined?(::OpenSSL::SSL::SSLError) && \
70
- e.is_a?(::OpenSSL::SSL::SSLError)
71
- raise Faraday::SSLError, e
72
- end
73
-
74
- raise
75
- end
76
-
77
- # @param bind [Hash]
78
- def configure_socket(client, bind)
79
- client.socket_local.host = bind[:host]
80
- client.socket_local.port = bind[:port]
81
- end
82
-
83
- # Configure proxy URI and any user credentials.
84
- #
85
- # @param proxy [Hash]
86
- def configure_proxy(client, proxy)
87
- client.proxy = proxy[:uri]
88
- return unless proxy[:user] && proxy[:password]
89
-
90
- client.set_proxy_auth(proxy[:user], proxy[:password])
91
- end
92
-
93
- # @param ssl [Hash]
94
- def configure_ssl(client, ssl)
95
- ssl_config = client.ssl_config
96
- ssl_config.verify_mode = ssl_verify_mode(ssl)
97
- ssl_config.cert_store = ssl_cert_store(ssl)
98
-
99
- ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file]
100
- ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path]
101
- ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert]
102
- ssl_config.client_key = ssl[:client_key] if ssl[:client_key]
103
- ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
104
- end
105
-
106
- # @param req [Hash]
107
- def configure_timeouts(client, req)
108
- if (sec = request_timeout(:open, req))
109
- client.connect_timeout = sec
110
- end
111
-
112
- if (sec = request_timeout(:write, req))
113
- client.send_timeout = sec
114
- end
115
-
116
- return unless (sec = request_timeout(:read, req))
117
-
118
- client.receive_timeout = sec
119
- end
120
-
121
- def configure_client(client)
122
- @config_block&.call(client)
123
- end
124
-
125
- # @param ssl [Hash]
126
- # @return [OpenSSL::X509::Store]
127
- def ssl_cert_store(ssl)
128
- return ssl[:cert_store] if ssl[:cert_store]
129
-
130
- # Memoize the cert store so that the same one is passed to
131
- # HTTPClient each time, to avoid resyncing SSL sessions when
132
- # it's changed
133
- @ssl_cert_store ||= begin
134
- # Use the default cert store by default, i.e. system ca certs
135
- OpenSSL::X509::Store.new.tap(&:set_default_paths)
136
- end
137
- end
138
-
139
- # @param ssl [Hash]
140
- def ssl_verify_mode(ssl)
141
- ssl[:verify_mode] || begin
142
- if ssl.fetch(:verify, true)
143
- OpenSSL::SSL::VERIFY_PEER |
144
- OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
145
- else
146
- OpenSSL::SSL::VERIFY_NONE
147
- end
148
- end
149
- end
150
- end
151
- end
152
- end
@@ -1,132 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # Patron adapter.
6
- class Patron < Faraday::Adapter
7
- dependency 'patron'
8
-
9
- def build_connection(env)
10
- session = ::Patron::Session.new
11
- @config_block&.call(session)
12
- if (env[:url].scheme == 'https') && env[:ssl]
13
- configure_ssl(session, env[:ssl])
14
- end
15
-
16
- if (req = env[:request])
17
- configure_timeouts(session, req)
18
- configure_proxy(session, req[:proxy])
19
- end
20
-
21
- session
22
- end
23
-
24
- def call(env)
25
- super
26
- # TODO: support streaming requests
27
- env[:body] = env[:body].read if env[:body].respond_to? :read
28
-
29
- response = connection(env) do |session|
30
- begin
31
- data = env[:body] ? env[:body].to_s : nil
32
- session.request(env[:method], env[:url].to_s,
33
- env[:request_headers], data: data)
34
- rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
35
- raise Faraday::ConnectionFailed, $ERROR_INFO
36
- end
37
- end
38
-
39
- if (req = env[:request]).stream_response?
40
- warn "Streaming downloads for #{self.class.name} " \
41
- 'are not yet implemented.'
42
- req.on_data.call(response.body, response.body.bytesize)
43
- end
44
- # Remove the "HTTP/1.1 200", leaving just the reason phrase
45
- reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
46
-
47
- save_response(env, response.status, response.body,
48
- response.headers, reason_phrase)
49
-
50
- @app.call env
51
- rescue ::Patron::TimeoutError => e
52
- if connection_timed_out_message?(e.message)
53
- raise Faraday::ConnectionFailed, e
54
- end
55
-
56
- raise Faraday::TimeoutError, e
57
- rescue ::Patron::Error => e
58
- if e.message.include?('code 407')
59
- raise Faraday::ConnectionFailed,
60
- %(407 "Proxy Authentication Required ")
61
- end
62
-
63
- raise Faraday::ConnectionFailed, e
64
- end
65
-
66
- if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
67
- # HAX: helps but doesn't work completely
68
- # https://github.com/toland/patron/issues/34
69
- ::Patron::Request::VALID_ACTIONS.tap do |actions|
70
- if actions[0].is_a?(Symbol)
71
- actions << :patch unless actions.include? :patch
72
- actions << :options unless actions.include? :options
73
- else
74
- # Patron 0.4.20 and up
75
- actions << 'PATCH' unless actions.include? 'PATCH'
76
- actions << 'OPTIONS' unless actions.include? 'OPTIONS'
77
- end
78
- end
79
- end
80
-
81
- def configure_ssl(session, ssl)
82
- if ssl.fetch(:verify, true)
83
- session.cacert = ssl[:ca_file]
84
- else
85
- session.insecure = true
86
- end
87
- end
88
-
89
- def configure_timeouts(session, req)
90
- return unless req
91
-
92
- if (sec = request_timeout(:read, req))
93
- session.timeout = sec
94
- end
95
-
96
- return unless (sec = request_timeout(:open, req))
97
-
98
- session.connect_timeout = sec
99
- end
100
-
101
- def configure_proxy(session, proxy)
102
- return unless proxy
103
-
104
- proxy_uri = proxy[:uri].dup
105
- proxy_uri.user = proxy[:user] &&
106
- Utils.escape(proxy[:user]).gsub('+', '%20')
107
- proxy_uri.password = proxy[:password] &&
108
- Utils.escape(proxy[:password]).gsub('+', '%20')
109
- session.proxy = proxy_uri.to_s
110
- end
111
-
112
- private
113
-
114
- CURL_TIMEOUT_MESSAGES = [
115
- 'Connection time-out',
116
- 'Connection timed out',
117
- 'Timed out before name resolve',
118
- 'server connect has timed out',
119
- 'Resolving timed out',
120
- 'name lookup timed out',
121
- 'timed out before SSL',
122
- 'connect() timed out'
123
- ].freeze
124
-
125
- def connection_timed_out_message?(message)
126
- CURL_TIMEOUT_MESSAGES.any? do |curl_message|
127
- message.include?(curl_message)
128
- end
129
- end
130
- end
131
- end
132
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # Sends requests to a Rack app.
6
- #
7
- # @example
8
- #
9
- # class MyRackApp
10
- # def call(env)
11
- # [200, {'Content-Type' => 'text/html'}, ["hello world"]]
12
- # end
13
- # end
14
- #
15
- # Faraday.new do |conn|
16
- # conn.adapter :rack, MyRackApp.new
17
- # end
18
- class Rack < Faraday::Adapter
19
- dependency 'rack/test'
20
-
21
- # not prefixed with "HTTP_"
22
- SPECIAL_HEADERS = %w[CONTENT_LENGTH CONTENT_TYPE].freeze
23
-
24
- def initialize(faraday_app, rack_app)
25
- super(faraday_app)
26
- mock_session = ::Rack::MockSession.new(rack_app)
27
- @session = ::Rack::Test::Session.new(mock_session)
28
- end
29
-
30
- def call(env)
31
- super
32
- rack_env = build_rack_env(env)
33
-
34
- env[:request_headers]&.each do |name, value|
35
- name = name.upcase.tr('-', '_')
36
- name = "HTTP_#{name}" unless SPECIAL_HEADERS.include? name
37
- rack_env[name] = value
38
- end
39
-
40
- timeout = request_timeout(:open, env[:request])
41
- timeout ||= request_timeout(:read, env[:request])
42
- response = if timeout
43
- Timer.timeout(timeout, Faraday::TimeoutError) do
44
- execute_request(env, rack_env)
45
- end
46
- else
47
- execute_request(env, rack_env)
48
- end
49
-
50
- if (req = env[:request]).stream_response?
51
- warn "Streaming downloads for #{self.class.name} " \
52
- 'are not yet implemented.'
53
- req.on_data.call(response.body, response.body.bytesize)
54
- end
55
-
56
- save_response(env, response.status, response.body, response.headers)
57
- @app.call env
58
- end
59
-
60
- private
61
-
62
- def execute_request(env, rack_env)
63
- @session.request(env[:url].to_s, rack_env)
64
- end
65
-
66
- def build_rack_env(env)
67
- {
68
- method: env[:method],
69
- input: env[:body].respond_to?(:read) ? env[:body].read : env[:body],
70
- 'rack.url_scheme' => env[:url].scheme
71
- }
72
- end
73
- end
74
- end
75
- end
@@ -1,128 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'stringio'
4
-
5
- # multipart-post gem
6
- require 'composite_io'
7
- require 'parts'
8
-
9
- module Faraday
10
- # Multipart value used to POST a binary data from a file or
11
- #
12
- # @example
13
- # payload = { file: Faraday::FilePart.new("file_name.ext", "content/type") }
14
- # http.post("/upload", payload)
15
- #
16
-
17
- # @!method initialize(filename_or_io, content_type, filename = nil, opts = {})
18
- #
19
- # @param filename_or_io [String, IO] Either a String filename to a local
20
- # file or an open IO object.
21
- # @param content_type [String] String content type of the file data.
22
- # @param filename [String] Optional String filename, usually to add context
23
- # to a given IO object.
24
- # @param opts [Hash] Optional Hash of String key/value pairs to describethis
25
- # this uploaded file. Expected Header keys include:
26
- # * Content-Transfer-Encoding - Defaults to "binary"
27
- # * Content-Disposition - Defaults to "form-data"
28
- # * Content-Type - Defaults to the content_type argument.
29
- # * Content-ID - Optional.
30
- #
31
- # @return [Faraday::FilePart]
32
- #
33
- # @!attribute [r] content_type
34
- # The uploaded binary data's content type.
35
- #
36
- # @return [String]
37
- #
38
- # @!attribute [r] original_filename
39
- # The base filename, taken either from the filename_or_io or filename
40
- # arguments in #initialize.
41
- #
42
- # @return [String]
43
- #
44
- # @!attribute [r] opts
45
- # Extra String key/value pairs to make up the header for this uploaded file.
46
- #
47
- # @return [Hash]
48
- #
49
- # @!attribute [r] io
50
- # The open IO object for the uploaded file.
51
- #
52
- # @return [IO]
53
- FilePart = ::UploadIO
54
-
55
- # Multipart value used to POST a file.
56
- #
57
- # @deprecated Use FilePart instead of this class. It behaves identically, with
58
- # a matching name to ParamPart.
59
- UploadIO = ::UploadIO
60
-
61
- Parts = ::Parts
62
-
63
- # Similar to, but not compatible with CompositeReadIO provided by the
64
- # multipart-post gem.
65
- # https://github.com/nicksieger/multipart-post/blob/master/lib/composite_io.rb
66
- class CompositeReadIO
67
- def initialize(*parts)
68
- @parts = parts.flatten
69
- @ios = @parts.map(&:to_io)
70
- @index = 0
71
- end
72
-
73
- # @return [Integer] sum of the lengths of all the parts
74
- def length
75
- @parts.inject(0) { |sum, part| sum + part.length }
76
- end
77
-
78
- # Rewind each of the IOs and reset the index to 0.
79
- #
80
- # @return [void]
81
- def rewind
82
- @ios.each(&:rewind)
83
- @index = 0
84
- end
85
-
86
- # Read from IOs in order until `length` bytes have been received.
87
- #
88
- # @param length [Integer, nil]
89
- # @param outbuf [String, nil]
90
- def read(length = nil, outbuf = nil)
91
- got_result = false
92
- outbuf = outbuf ? (+outbuf).replace('') : +''
93
-
94
- while (io = current_io)
95
- if (result = io.read(length))
96
- got_result ||= !result.nil?
97
- result.force_encoding('BINARY') if result.respond_to?(:force_encoding)
98
- outbuf << result
99
- length -= result.length if length
100
- break if length&.zero?
101
- end
102
- advance_io
103
- end
104
- !got_result && length ? nil : outbuf
105
- end
106
-
107
- # Close each of the IOs.
108
- #
109
- # @return [void]
110
- def close
111
- @ios.each(&:close)
112
- end
113
-
114
- def ensure_open_and_readable
115
- # Rubinius compatibility
116
- end
117
-
118
- private
119
-
120
- def current_io
121
- @ios[@index]
122
- end
123
-
124
- def advance_io
125
- @index += 1
126
- end
127
- end
128
- end
@@ -1,53 +0,0 @@
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
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require File.expand_path('url_encoded', __dir__)
4
- require 'securerandom'
5
-
6
- module Faraday
7
- class Request
8
- # Middleware for supporting multi-part requests.
9
- class Multipart < UrlEncoded
10
- self.mime_type = 'multipart/form-data'
11
- unless defined?(::Faraday::Request::Multipart::DEFAULT_BOUNDARY_PREFIX)
12
- DEFAULT_BOUNDARY_PREFIX = '-----------RubyMultipartPost'
13
- end
14
-
15
- def initialize(app = nil, options = {})
16
- super(app)
17
- @options = options
18
- end
19
-
20
- # Checks for files in the payload, otherwise leaves everything untouched.
21
- #
22
- # @param env [Faraday::Env]
23
- def call(env)
24
- match_content_type(env) do |params|
25
- env.request.boundary ||= unique_boundary
26
- env.request_headers[CONTENT_TYPE] +=
27
- "; boundary=#{env.request.boundary}"
28
- env.body = create_multipart(env, params)
29
- end
30
- @app.call env
31
- end
32
-
33
- # @param env [Faraday::Env]
34
- def process_request?(env)
35
- type = request_type(env)
36
- env.body.respond_to?(:each_key) && !env.body.empty? && (
37
- (type.empty? && has_multipart?(env.body)) ||
38
- (type == self.class.mime_type)
39
- )
40
- end
41
-
42
- # Returns true if obj is an enumerable with values that are multipart.
43
- #
44
- # @param obj [Object]
45
- # @return [Boolean]
46
- def has_multipart?(obj) # rubocop:disable Naming/PredicateName
47
- if obj.respond_to?(:each)
48
- (obj.respond_to?(:values) ? obj.values : obj).each do |val|
49
- return true if val.respond_to?(:content_type) || has_multipart?(val)
50
- end
51
- end
52
- false
53
- end
54
-
55
- # @param env [Faraday::Env]
56
- # @param params [Hash]
57
- def create_multipart(env, params)
58
- boundary = env.request.boundary
59
- parts = process_params(params) do |key, value|
60
- part(boundary, key, value)
61
- end
62
- parts << Faraday::Parts::EpiloguePart.new(boundary)
63
-
64
- body = Faraday::CompositeReadIO.new(parts)
65
- env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
66
- body
67
- end
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
-
77
- # @return [String]
78
- def unique_boundary
79
- "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
80
- end
81
-
82
- # @param params [Hash]
83
- # @param prefix [String]
84
- # @param pieces [Array]
85
- def process_params(params, prefix = nil, pieces = nil, &block)
86
- params.inject(pieces || []) do |all, (key, value)|
87
- if prefix
88
- key = @options[:flat_encode] ? prefix.to_s : "#{prefix}[#{key}]"
89
- end
90
-
91
- case value
92
- when Array
93
- values = value.inject([]) { |a, v| a << [nil, v] }
94
- process_params(values, key, all, &block)
95
- when Hash
96
- process_params(value, key, all, &block)
97
- else
98
- # rubocop:disable Performance/RedundantBlockCall
99
- all << block.call(key, value)
100
- # rubocop:enable Performance/RedundantBlockCall
101
- end
102
- end
103
- end
104
- end
105
- end
106
- end