faraday 0.9.1 → 0.11.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/README.md +53 -16
  4. data/lib/faraday/adapter/em_http.rb +8 -2
  5. data/lib/faraday/adapter/em_http_ssl_patch.rb +1 -1
  6. data/lib/faraday/adapter/em_synchrony.rb +16 -2
  7. data/lib/faraday/adapter/excon.rb +7 -7
  8. data/lib/faraday/adapter/httpclient.rb +27 -5
  9. data/lib/faraday/adapter/net_http.rb +13 -8
  10. data/lib/faraday/adapter/net_http_persistent.rb +6 -4
  11. data/lib/faraday/adapter/patron.rb +13 -9
  12. data/lib/faraday/adapter/test.rb +64 -21
  13. data/lib/faraday/adapter.rb +8 -1
  14. data/lib/faraday/connection.rb +14 -9
  15. data/lib/faraday/error.rb +11 -1
  16. data/lib/faraday/options.rb +18 -1
  17. data/lib/faraday/parameters.rb +54 -38
  18. data/lib/faraday/rack_builder.rb +3 -2
  19. data/lib/faraday/request/authorization.rb +1 -2
  20. data/lib/faraday/request/retry.rb +10 -4
  21. data/lib/faraday/request.rb +2 -0
  22. data/lib/faraday/response/logger.rb +27 -6
  23. data/lib/faraday/response.rb +6 -2
  24. data/lib/faraday/utils.rb +22 -2
  25. data/lib/faraday.rb +8 -33
  26. metadata +7 -93
  27. data/.document +0 -6
  28. data/CHANGELOG.md +0 -20
  29. data/CONTRIBUTING.md +0 -36
  30. data/Gemfile +0 -25
  31. data/Rakefile +0 -71
  32. data/faraday.gemspec +0 -34
  33. data/script/cached-bundle +0 -46
  34. data/script/console +0 -7
  35. data/script/generate_certs +0 -42
  36. data/script/package +0 -7
  37. data/script/proxy-server +0 -42
  38. data/script/release +0 -17
  39. data/script/s3-put +0 -71
  40. data/script/server +0 -36
  41. data/script/test +0 -172
  42. data/test/adapters/default_test.rb +0 -14
  43. data/test/adapters/em_http_test.rb +0 -20
  44. data/test/adapters/em_synchrony_test.rb +0 -20
  45. data/test/adapters/excon_test.rb +0 -20
  46. data/test/adapters/httpclient_test.rb +0 -21
  47. data/test/adapters/integration.rb +0 -254
  48. data/test/adapters/logger_test.rb +0 -82
  49. data/test/adapters/net_http_persistent_test.rb +0 -20
  50. data/test/adapters/net_http_test.rb +0 -14
  51. data/test/adapters/patron_test.rb +0 -20
  52. data/test/adapters/rack_test.rb +0 -31
  53. data/test/adapters/test_middleware_test.rb +0 -114
  54. data/test/adapters/typhoeus_test.rb +0 -28
  55. data/test/authentication_middleware_test.rb +0 -65
  56. data/test/composite_read_io_test.rb +0 -111
  57. data/test/connection_test.rb +0 -522
  58. data/test/env_test.rb +0 -218
  59. data/test/helper.rb +0 -81
  60. data/test/live_server.rb +0 -67
  61. data/test/middleware/instrumentation_test.rb +0 -88
  62. data/test/middleware/retry_test.rb +0 -177
  63. data/test/middleware_stack_test.rb +0 -173
  64. data/test/multibyte.txt +0 -1
  65. data/test/options_test.rb +0 -252
  66. data/test/parameters_test.rb +0 -64
  67. data/test/request_middleware_test.rb +0 -142
  68. data/test/response_middleware_test.rb +0 -72
  69. data/test/strawberry.rb +0 -2
  70. data/test/utils_test.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c31dbb021fc6a43b4f0b102a9a3ccf52a72303a
4
- data.tar.gz: 54da868027777adb5a21145bd6433b0154af2297
3
+ metadata.gz: 88d17f843f96e641d4cb8b87b360b99adfee6c53
4
+ data.tar.gz: 3c0031b2fa042939cc5e7f27aefa00f8ebe6a97f
5
5
  SHA512:
6
- metadata.gz: 22c1c286687ca596bd1d6b7d9a6a3749731f6d8962a5bbbe7e1e39cf22e364b92010ae44446cf1804ba10567a2e6409cc2be537375d9f47ace9bca909196dcd3
7
- data.tar.gz: 7e8116cdeea918b8e7de661ec6d49d839960e26f136903e53db62e8cc353f89b3ac053d5efe6401995129418ae4dfce8fda9c8a471093223dca08002615d10e1
6
+ metadata.gz: 03fa51e8008930909fb2e5f40afe8f3d59d176574a084e364569d256b0c073bd06796bb0fe96f79c42cfacda2ee8417fecb1b3fc13e5b46bbb76f960136d116c
7
+ data.tar.gz: 16432e693c7c666ac40de8a03ca890f08ee1cba705477afd31d64346282f018abf9ee617e1996330bbe2b2c3352021683e386522d700c49d08246b77d36fb65a
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2013 Rick Olson, Zack Hobson
1
+ Copyright (c) 2009-2015 Rick Olson, Zack Hobson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -6,7 +6,8 @@ processing the request/response cycle.
6
6
 
7
7
  Faraday supports these adapters:
8
8
 
9
- * Net::HTTP
9
+ * [Net::HTTP][net_http] _(default)_
10
+ * [Net::HTTP::Persistent][persistent]
10
11
  * [Excon][]
11
12
  * [Typhoeus][]
12
13
  * [Patron][]
@@ -16,6 +17,10 @@ Faraday supports these adapters:
16
17
  It also includes a Rack adapter for hitting loaded Rack applications through
17
18
  Rack::Test, and a Test adapter for stubbing requests by hand.
18
19
 
20
+ ## API documentation
21
+
22
+ Available at [rubydoc.info](http://www.rubydoc.info/gems/faraday).
23
+
19
24
  ## Usage
20
25
 
21
26
  ```ruby
@@ -25,6 +30,14 @@ conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
25
30
  faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
26
31
  end
27
32
 
33
+ # Filter sensitive information from logs with a regex matcher
34
+
35
+ conn = Faraday.new(:url => 'http://sushi.com/api_key=s3cr3t') do |faraday|
36
+ faraday.response :logger do | logger |
37
+ logger.filter(/(api_key=)(\w+)/,'\1[REMOVED]')
38
+ end
39
+ end
40
+
28
41
  ## GET ##
29
42
 
30
43
  response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json
@@ -64,6 +77,32 @@ stack and default adapter (see [Faraday::RackBuilder#initialize](https://github.
64
77
  response = Faraday.get 'http://sushi.com/nigiri/sake.json'
65
78
  ```
66
79
 
80
+ ### Changing how parameters are serialized
81
+
82
+ Sometimes you need to send the same URL parameter multiple times with different
83
+ values. This requires manually setting the parameter encoder and can be done on
84
+ either per-connection or per-request basis.
85
+
86
+ ```ruby
87
+ # per-connection setting
88
+ conn = Faraday.new :request => { :params_encoder => Faraday::FlatParamsEncoder }
89
+
90
+ conn.get do |req|
91
+ # per-request setting:
92
+ # req.options.params_encoder = my_encoder
93
+ req.params['roll'] = ['california', 'philadelphia']
94
+ end
95
+ # GET 'http://sushi.com?roll=california&roll=philadelphia'
96
+ ```
97
+
98
+ The value of Faraday `params_encoder` can be any object that responds to:
99
+
100
+ * `encode(hash) #=> String`
101
+ * `decode(string) #=> Hash`
102
+
103
+ The encoder will affect both how query strings are processed and how POST bodies
104
+ get serialized. The default encoder is Faraday::NestedParamsEncoder.
105
+
67
106
  ## Advanced middleware usage
68
107
 
69
108
  The order in which middleware is stacked is important. Like with Rack, the
@@ -183,13 +222,9 @@ stubs.verify_stubbed_calls
183
222
  This library aims to support and is [tested against][travis] the following Ruby
184
223
  implementations:
185
224
 
186
- * MRI 1.8.7
187
- * MRI 1.9.2
188
- * MRI 1.9.3
189
- * MRI 2.0.0
190
- * MRI 2.1.0
191
- * [JRuby][]
192
- * [Rubinius][]
225
+ * Ruby 1.9.3+
226
+ * [JRuby][] 1.7+
227
+ * [Rubinius][] 2+
193
228
 
194
229
  If something doesn't work on one of these Ruby versions, it's a bug.
195
230
 
@@ -209,12 +244,14 @@ of a major release, support for that Ruby version may be dropped.
209
244
  Copyright (c) 2009-2013 [Rick Olson](mailto:technoweenie@gmail.com), Zack Hobson.
210
245
  See [LICENSE][] for details.
211
246
 
212
- [travis]: http://travis-ci.org/lostisland/faraday
213
- [excon]: https://github.com/geemus/excon#readme
214
- [typhoeus]: https://github.com/typhoeus/typhoeus#readme
215
- [patron]: http://toland.github.com/patron/
247
+ [net_http]: http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html
248
+ [persistent]: https://github.com/drbrain/net-http-persistent
249
+ [travis]: https://travis-ci.org/lostisland/faraday
250
+ [excon]: https://github.com/excon/excon#readme
251
+ [typhoeus]: https://github.com/typhoeus/typhoeus#readme
252
+ [patron]: http://toland.github.io/patron/
216
253
  [eventmachine]: https://github.com/igrigorik/em-http-request#readme
217
- [httpclient]: https://github.com/nahi/httpclient
218
- [jruby]: http://jruby.org/
219
- [rubinius]: http://rubini.us/
220
- [license]: LICENSE.md
254
+ [httpclient]: https://github.com/nahi/httpclient
255
+ [jruby]: http://jruby.org/
256
+ [rubinius]: http://rubini.us/
257
+ [license]: LICENSE.md
@@ -138,9 +138,11 @@ module Faraday
138
138
 
139
139
  # TODO: reuse the connection to support pipelining
140
140
  def perform_single_request(env)
141
- req = EventMachine::HttpRequest.new(env[:url], connection_config(env))
141
+ req = create_request(env)
142
142
  req.setup_request(env[:method], request_config(env)).callback { |client|
143
- save_response(env, client.response_header.status, client.response) do |resp_headers|
143
+ status = client.response_header.status
144
+ reason = client.response_header.http_reason
145
+ save_response(env, status, client.response, nil, reason) do |resp_headers|
144
146
  client.response_header.each do |name, value|
145
147
  resp_headers[name.to_sym] = value
146
148
  end
@@ -148,6 +150,10 @@ module Faraday
148
150
  }
149
151
  end
150
152
 
153
+ def create_request(env)
154
+ EventMachine::HttpRequest.new(env[:url], connection_config(env).merge(@connection_options))
155
+ end
156
+
151
157
  def error_message(client)
152
158
  client.error or "request failed"
153
159
  end
@@ -39,7 +39,7 @@ module EmHttpSslPatch
39
39
  end
40
40
 
41
41
  def host
42
- parent.connopts.host
42
+ parent.uri.host
43
43
  end
44
44
 
45
45
  def certificate_store
@@ -19,7 +19,7 @@ module Faraday
19
19
 
20
20
  def call(env)
21
21
  super
22
- request = EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env))
22
+ request = create_request(env)
23
23
 
24
24
  http_method = env[:method].to_s.downcase.to_sym
25
25
 
@@ -54,7 +54,9 @@ module Faraday
54
54
 
55
55
  raise client.error if client.error
56
56
 
57
- save_response(env, client.response_header.status, client.response) do |resp_headers|
57
+ status = client.response_header.status
58
+ reason = client.response_header.http_reason
59
+ save_response(env, status, client.response, nil, reason) do |resp_headers|
58
60
  client.response_header.each do |name, value|
59
61
  resp_headers[name.to_sym] = value
60
62
  end
@@ -70,6 +72,14 @@ module Faraday
70
72
  else
71
73
  raise Error::ConnectionFailed, err
72
74
  end
75
+ rescue Errno::ETIMEDOUT => err
76
+ raise Error::TimeoutError, err
77
+ rescue RuntimeError => err
78
+ if err.message == "connection closed by server"
79
+ raise Error::ConnectionFailed, err
80
+ else
81
+ raise
82
+ end
73
83
  rescue => err
74
84
  if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
75
85
  raise Faraday::SSLError, err
@@ -77,6 +87,10 @@ module Faraday
77
87
  raise
78
88
  end
79
89
  end
90
+
91
+ def create_request(env)
92
+ EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env).merge(@connection_options))
93
+ end
80
94
  end
81
95
  end
82
96
  end
@@ -3,11 +3,6 @@ module Faraday
3
3
  class Excon < Faraday::Adapter
4
4
  dependency 'excon'
5
5
 
6
- def initialize(app, connection_options = {})
7
- @connection_options = connection_options
8
- super(app)
9
- end
10
-
11
6
  def call(env)
12
7
  super
13
8
 
@@ -41,6 +36,7 @@ module Faraday
41
36
  if req[:proxy]
42
37
  opts[:proxy] = {
43
38
  :host => req[:proxy][:uri].host,
39
+ :hostname => req[:proxy][:uri].hostname,
44
40
  :port => req[:proxy][:uri].port,
45
41
  :scheme => req[:proxy][:uri].scheme,
46
42
  :user => req[:proxy][:user],
@@ -49,14 +45,14 @@ module Faraday
49
45
  end
50
46
  end
51
47
 
52
- conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
48
+ conn = create_connection(env, opts)
53
49
 
54
50
  resp = conn.request \
55
51
  :method => env[:method].to_s.upcase,
56
52
  :headers => env[:request_headers],
57
53
  :body => read_body(env)
58
54
 
59
- save_response(env, resp.status.to_i, resp.body, resp.headers)
55
+ save_response(env, resp.status.to_i, resp.body, resp.headers, resp.reason_phrase)
60
56
 
61
57
  @app.call env
62
58
  rescue ::Excon::Errors::SocketError => err
@@ -71,6 +67,10 @@ module Faraday
71
67
  raise Error::TimeoutError, err
72
68
  end
73
69
 
70
+ def create_connection(env, opts)
71
+ ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
72
+ end
73
+
74
74
  # TODO: support streaming requests
75
75
  def read_body(env)
76
76
  env[:body].respond_to?(:read) ? env[:body].read : env[:body]
@@ -10,6 +10,9 @@ module Faraday
10
10
  def call(env)
11
11
  super
12
12
 
13
+ # enable compression
14
+ client.transparent_gzip_decompression = true
15
+
13
16
  if req = env[:request]
14
17
  if proxy = req[:proxy]
15
18
  configure_proxy proxy
@@ -26,6 +29,8 @@ module Faraday
26
29
  configure_ssl ssl
27
30
  end
28
31
 
32
+ configure_client
33
+
29
34
  # TODO Don't stream yet.
30
35
  # https://github.com/nahi/httpclient/pull/90
31
36
  env[:body] = env[:body].read if env[:body].respond_to? :read
@@ -34,10 +39,10 @@ module Faraday
34
39
  :body => env[:body],
35
40
  :header => env[:request_headers]
36
41
 
37
- save_response env, resp.status, resp.body, resp.headers
42
+ save_response env, resp.status, resp.body, resp.headers, resp.reason
38
43
 
39
44
  @app.call env
40
- rescue ::HTTPClient::TimeoutError
45
+ rescue ::HTTPClient::TimeoutError, Errno::ETIMEDOUT
41
46
  raise Faraday::Error::TimeoutError, $!
42
47
  rescue ::HTTPClient::BadResponseError => err
43
48
  if err.message.include?('status 407')
@@ -45,7 +50,7 @@ module Faraday
45
50
  else
46
51
  raise Faraday::Error::ClientError, $!
47
52
  end
48
- rescue Errno::ECONNREFUSED, EOFError
53
+ rescue Errno::ECONNREFUSED, IOError
49
54
  raise Faraday::Error::ConnectionFailed, $!
50
55
  rescue => err
51
56
  if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
@@ -69,14 +74,14 @@ module Faraday
69
74
 
70
75
  def configure_ssl(ssl)
71
76
  ssl_config = client.ssl_config
77
+ ssl_config.verify_mode = ssl_verify_mode(ssl)
78
+ ssl_config.cert_store = ssl_cert_store(ssl)
72
79
 
73
80
  ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file]
74
81
  ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path]
75
- ssl_config.cert_store = ssl[:cert_store] if ssl[:cert_store]
76
82
  ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert]
77
83
  ssl_config.client_key = ssl[:client_key] if ssl[:client_key]
78
84
  ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
79
- ssl_config.verify_mode = ssl_verify_mode(ssl)
80
85
  end
81
86
 
82
87
  def configure_timeouts(req)
@@ -92,6 +97,23 @@ module Faraday
92
97
  end
93
98
  end
94
99
 
100
+ def configure_client
101
+ @config_block.call(client) if @config_block
102
+ end
103
+
104
+ def ssl_cert_store(ssl)
105
+ return ssl[:cert_store] if ssl[:cert_store]
106
+ # Memoize the cert store so that the same one is passed to
107
+ # HTTPClient each time, to avoid resyncing SSL sesions when
108
+ # it's changed
109
+ @cert_store ||= begin
110
+ # Use the default cert store by default, i.e. system ca certs
111
+ cert_store = OpenSSL::X509::Store.new
112
+ cert_store.set_default_paths
113
+ cert_store
114
+ end
115
+ end
116
+
95
117
  def ssl_verify_mode(ssl)
96
118
  ssl[:verify_mode] || begin
97
119
  if ssl.fetch(:verify, true)
@@ -10,13 +10,14 @@ module Faraday
10
10
  class Adapter
11
11
  class NetHttp < Faraday::Adapter
12
12
  NET_HTTP_EXCEPTIONS = [
13
- EOFError,
13
+ IOError,
14
14
  Errno::ECONNABORTED,
15
15
  Errno::ECONNREFUSED,
16
16
  Errno::ECONNRESET,
17
17
  Errno::EHOSTUNREACH,
18
18
  Errno::EINVAL,
19
19
  Errno::ENETUNREACH,
20
+ Errno::EPIPE,
20
21
  Net::HTTPBadResponse,
21
22
  Net::HTTPHeaderSyntaxError,
22
23
  Net::ProtocolError,
@@ -31,10 +32,7 @@ module Faraday
31
32
  super
32
33
  with_net_http_connection(env) do |http|
33
34
  configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
34
-
35
- req = env[:request]
36
- http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
37
- http.open_timeout = req[:open_timeout] if req[:open_timeout]
35
+ configure_request(http, env[:request])
38
36
 
39
37
  begin
40
38
  http_response = perform_request(http, env)
@@ -46,7 +44,7 @@ module Faraday
46
44
  end
47
45
  end
48
46
 
49
- save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers|
47
+ save_response(env, http_response.code.to_i, http_response.body || '', nil, http_response.message) do |response_headers|
50
48
  http_response.each_header do |key, value|
51
49
  response_headers[key] = value
52
50
  end
@@ -54,7 +52,7 @@ module Faraday
54
52
  end
55
53
 
56
54
  @app.call env
57
- rescue Timeout::Error => err
55
+ rescue Timeout::Error, Errno::ETIMEDOUT => err
58
56
  raise Faraday::Error::TimeoutError, err
59
57
  end
60
58
 
@@ -92,7 +90,7 @@ module Faraday
92
90
  Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
93
91
  else
94
92
  Net::HTTP
95
- end.new(env[:url].host, env[:url].port)
93
+ end.new(env[:url].host, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
96
94
  end
97
95
 
98
96
  def configure_ssl(http, ssl)
@@ -108,6 +106,13 @@ module Faraday
108
106
  http.ssl_version = ssl[:version] if ssl[:version]
109
107
  end
110
108
 
109
+ def configure_request(http, req)
110
+ http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
111
+ http.open_timeout = req[:open_timeout] if req[:open_timeout]
112
+
113
+ @config_block.call(http) if @config_block
114
+ end
115
+
111
116
  def ssl_cert_store(ssl)
112
117
  return ssl[:cert_store] if ssl[:cert_store]
113
118
  # Use the default cert store by default, i.e. system ca certs
@@ -4,12 +4,11 @@
4
4
 
5
5
  module Faraday
6
6
  class Adapter
7
- # Experimental adapter for net-http-persistent
8
7
  class NetHttpPersistent < NetHttp
9
8
  dependency 'net/http/persistent'
10
9
 
11
- def with_net_http_connection(env)
12
- if proxy = env[:request][:proxy]
10
+ def net_http_connection(env)
11
+ if (proxy = env[:request][:proxy])
13
12
  proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
14
13
  proxy_uri.user = proxy_uri.password = nil
15
14
  # awful patch for net-http-persistent 2.8 not unescaping user/password
@@ -17,13 +16,16 @@ module Faraday
17
16
  define_method(:user) { proxy[:user] }
18
17
  define_method(:password) { proxy[:password] }
19
18
  end if proxy[:user]
19
+ return Net::HTTP::Persistent.new 'Faraday', proxy_uri
20
20
  end
21
21
 
22
- yield Net::HTTP::Persistent.new 'Faraday', proxy_uri
22
+ Net::HTTP::Persistent.new 'Faraday'
23
23
  end
24
24
 
25
25
  def perform_request(http, env)
26
26
  http.request env[:url], create_request(env)
27
+ rescue Errno::ETIMEDOUT => error
28
+ raise Faraday::Error::TimeoutError, error
27
29
  rescue Net::HTTP::Persistent::Error => error
28
30
  if error.message.include? 'Timeout'
29
31
  raise Faraday::Error::TimeoutError, error
@@ -3,11 +3,6 @@ module Faraday
3
3
  class Patron < Faraday::Adapter
4
4
  dependency 'patron'
5
5
 
6
- def initialize(app, &block)
7
- super(app)
8
- @block = block
9
- end
10
-
11
6
  def call(env)
12
7
  super
13
8
 
@@ -35,7 +30,10 @@ module Faraday
35
30
  raise Error::ConnectionFailed, $!
36
31
  end
37
32
 
38
- save_response(env, response.status, response.body, response.headers)
33
+ # Remove the "HTTP/1.1 200", leaving just the reason phrase
34
+ reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
35
+
36
+ save_response(env, response.status, response.body, response.headers, reason_phrase)
39
37
 
40
38
  @app.call env
41
39
  rescue ::Patron::TimeoutError => err
@@ -56,15 +54,21 @@ module Faraday
56
54
  # HAX: helps but doesn't work completely
57
55
  # https://github.com/toland/patron/issues/34
58
56
  ::Patron::Request::VALID_ACTIONS.tap do |actions|
59
- actions << :patch unless actions.include? :patch
60
- actions << :options unless actions.include? :options
57
+ if actions[0].is_a?(Symbol)
58
+ actions << :patch unless actions.include? :patch
59
+ actions << :options unless actions.include? :options
60
+ else
61
+ # Patron 0.4.20 and up
62
+ actions << "PATCH" unless actions.include? "PATCH"
63
+ actions << "OPTIONS" unless actions.include? "OPTIONS"
64
+ end
61
65
  end
62
66
  end
63
67
 
64
68
  def create_session
65
69
  session = ::Patron::Session.new
66
70
  session.insecure = true
67
- @block.call(session) if @block
71
+ @config_block.call(session) if @config_block
68
72
  session
69
73
  end
70
74
  end
@@ -1,16 +1,41 @@
1
1
  module Faraday
2
2
  class Adapter
3
- # test = Faraday::Connection.new do
4
- # use Faraday::Adapter::Test do |stub|
5
- # stub.get '/nigiri/sake.json' do
6
- # [200, {}, 'hi world']
3
+ # Examples
4
+ #
5
+ # test = Faraday::Connection.new do
6
+ # use Faraday::Adapter::Test do |stub|
7
+ # # simply define matcher to match the request
8
+ # stub.get '/resource.json' do
9
+ # # return static content
10
+ # [200, {'Content-Type' => 'application/json'}, 'hi world']
11
+ # end
12
+ #
13
+ # # response with content generated based on request
14
+ # stub.get '/showget' do |env|
15
+ # [200, {'Content-Type' => 'text/plain'}, env[:method].to_s]
16
+ # end
17
+ #
18
+ # # regular expression can be used as matching filter
19
+ # stub.get /\A\/items\/(\d+)\z/ do |env, meta|
20
+ # # in case regular expression is used an instance of MatchData can be received
21
+ # [200, {'Content-Type' => 'text/plain'}, "showing item: #{meta[:match_data][1]}"]
22
+ # end
7
23
  # end
8
24
  # end
9
- # end
10
- #
11
- # resp = test.get '/nigiri/sake.json'
12
- # resp.body # => 'hi world'
25
+ #
26
+ # resp = test.get '/resource.json'
27
+ # resp.body # => 'hi world'
28
+ #
29
+ # resp = test.get '/showget'
30
+ # resp.body # => 'get'
31
+ #
32
+ # resp = test.get '/items/1'
33
+ # resp.body # => 'showing item: 1'
34
+ #
35
+ # resp = test.get '/items/2'
36
+ # resp.body # => 'showing item: 2'
13
37
  #
38
+
14
39
  class Test < Faraday::Adapter
15
40
  attr_accessor :stubs
16
41
 
@@ -33,12 +58,12 @@ module Faraday
33
58
  stack = @stack[request_method]
34
59
  consumed = (@consumed[request_method] ||= [])
35
60
 
36
- if stub = matches?(stack, path, headers, body)
61
+ stub, meta = matches?(stack, path, headers, body)
62
+ if stub
37
63
  consumed << stack.delete(stub)
38
- stub
39
- else
40
- matches?(consumed, path, headers, body)
64
+ return stub, meta
41
65
  end
66
+ matches?(consumed, path, headers, body)
42
67
  end
43
68
 
44
69
  def get(path, headers = {}, &block)
@@ -85,18 +110,22 @@ module Faraday
85
110
  protected
86
111
 
87
112
  def new_stub(request_method, path, headers = {}, body=nil, &block)
88
- normalized_path = Faraday::Utils.normalize_path(path)
113
+ normalized_path = path.is_a?(Regexp) ? path : Faraday::Utils.normalize_path(path)
89
114
  (@stack[request_method] ||= []) << Stub.new(normalized_path, headers, body, block)
90
115
  end
91
116
 
92
117
  def matches?(stack, path, headers, body)
93
- stack.detect { |stub| stub.matches?(path, headers, body) }
118
+ stack.each do |stub|
119
+ match_result, meta = stub.matches?(path, headers, body)
120
+ return stub, meta if match_result
121
+ end
122
+ nil
94
123
  end
95
124
  end
96
125
 
97
126
  class Stub < Struct.new(:path, :params, :headers, :body, :block)
98
127
  def initialize(full, headers, body, block)
99
- path, query = full.split('?')
128
+ path, query = full.respond_to?(:split) ? full.split("?") : full
100
129
  params = query ?
101
130
  Faraday::Utils.parse_nested_query(query) :
102
131
  {}
@@ -108,10 +137,21 @@ module Faraday
108
137
  request_params = request_query ?
109
138
  Faraday::Utils.parse_nested_query(request_query) :
110
139
  {}
111
- request_path == path &&
140
+ # meta is a hash use as carrier
141
+ # that will be yielded to consumer block
142
+ meta = {}
143
+ return path_match?(request_path, meta) &&
112
144
  params_match?(request_params) &&
113
145
  (body.to_s.size.zero? || request_body == body) &&
114
- headers_match?(request_headers)
146
+ headers_match?(request_headers), meta
147
+ end
148
+
149
+ def path_match?(request_path, meta)
150
+ if path.is_a? Regexp
151
+ !!(meta[:match_data] = path.match(request_path))
152
+ else
153
+ path == request_path
154
+ end
115
155
  end
116
156
 
117
157
  def params_match?(request_params)
@@ -146,11 +186,14 @@ module Faraday
146
186
  normalized_path = Faraday::Utils.normalize_path(env[:url])
147
187
  params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder
148
188
 
149
- if stub = stubs.match(env[:method], normalized_path, env.request_headers, env[:body])
189
+ stub, meta = stubs.match(env[:method], normalized_path, env.request_headers, env[:body])
190
+ if stub
150
191
  env[:params] = (query = env[:url].query) ?
151
- params_encoder.decode(query) :
152
- {}
153
- status, headers, body = stub.block.call(env)
192
+ params_encoder.decode(query) : {}
193
+ block_arity = stub.block.arity
194
+ status, headers, body = (block_arity >= 0) ?
195
+ stub.block.call(*[env, meta].take(block_arity)) :
196
+ stub.block.call(env, meta)
154
197
  save_response(env, status, body, headers)
155
198
  else
156
199
  raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
@@ -30,13 +30,20 @@ module Faraday
30
30
  extend Parallelism
31
31
  self.supports_parallel = false
32
32
 
33
+ def initialize(app = nil, opts = {}, &block)
34
+ super(app)
35
+ @connection_options = opts
36
+ @config_block = block
37
+ end
38
+
33
39
  def call(env)
34
40
  env.clear_body if env.needs_body?
35
41
  end
36
42
 
37
- def save_response(env, status, body, headers = nil)
43
+ def save_response(env, status, body, headers = nil, reason_phrase = nil)
38
44
  env.status = status
39
45
  env.body = body
46
+ env.reason_phrase = reason_phrase && reason_phrase.to_s.strip
40
47
  env.response_headers = Utils::Headers.new.tap do |response_headers|
41
48
  response_headers.update headers unless headers.nil?
42
49
  yield(response_headers) if block_given?