faraday 0.9.1 → 0.17.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 (73) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.md +1 -1
  3. data/README.md +192 -28
  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 +10 -8
  8. data/lib/faraday/adapter/httpclient.rb +27 -5
  9. data/lib/faraday/adapter/net_http.rb +34 -12
  10. data/lib/faraday/adapter/net_http_persistent.rb +35 -15
  11. data/lib/faraday/adapter/patron.rb +39 -16
  12. data/lib/faraday/adapter/test.rb +79 -28
  13. data/lib/faraday/adapter/typhoeus.rb +4 -115
  14. data/lib/faraday/adapter.rb +10 -1
  15. data/lib/faraday/autoload.rb +1 -1
  16. data/lib/faraday/connection.rb +72 -20
  17. data/lib/faraday/error.rb +18 -5
  18. data/lib/faraday/options.rb +42 -19
  19. data/lib/faraday/parameters.rb +56 -39
  20. data/lib/faraday/rack_builder.rb +27 -2
  21. data/lib/faraday/request/authorization.rb +1 -2
  22. data/lib/faraday/request/multipart.rb +7 -2
  23. data/lib/faraday/request/retry.rb +82 -18
  24. data/lib/faraday/request.rb +22 -0
  25. data/lib/faraday/response/logger.rb +29 -8
  26. data/lib/faraday/response.rb +6 -2
  27. data/lib/faraday/utils.rb +32 -3
  28. data/lib/faraday.rb +14 -34
  29. metadata +7 -94
  30. data/.document +0 -6
  31. data/CHANGELOG.md +0 -20
  32. data/CONTRIBUTING.md +0 -36
  33. data/Gemfile +0 -25
  34. data/Rakefile +0 -71
  35. data/faraday.gemspec +0 -34
  36. data/script/cached-bundle +0 -46
  37. data/script/console +0 -7
  38. data/script/generate_certs +0 -42
  39. data/script/package +0 -7
  40. data/script/proxy-server +0 -42
  41. data/script/release +0 -17
  42. data/script/s3-put +0 -71
  43. data/script/server +0 -36
  44. data/script/test +0 -172
  45. data/test/adapters/default_test.rb +0 -14
  46. data/test/adapters/em_http_test.rb +0 -20
  47. data/test/adapters/em_synchrony_test.rb +0 -20
  48. data/test/adapters/excon_test.rb +0 -20
  49. data/test/adapters/httpclient_test.rb +0 -21
  50. data/test/adapters/integration.rb +0 -254
  51. data/test/adapters/logger_test.rb +0 -82
  52. data/test/adapters/net_http_persistent_test.rb +0 -20
  53. data/test/adapters/net_http_test.rb +0 -14
  54. data/test/adapters/patron_test.rb +0 -20
  55. data/test/adapters/rack_test.rb +0 -31
  56. data/test/adapters/test_middleware_test.rb +0 -114
  57. data/test/adapters/typhoeus_test.rb +0 -28
  58. data/test/authentication_middleware_test.rb +0 -65
  59. data/test/composite_read_io_test.rb +0 -111
  60. data/test/connection_test.rb +0 -522
  61. data/test/env_test.rb +0 -218
  62. data/test/helper.rb +0 -81
  63. data/test/live_server.rb +0 -67
  64. data/test/middleware/instrumentation_test.rb +0 -88
  65. data/test/middleware/retry_test.rb +0 -177
  66. data/test/middleware_stack_test.rb +0 -173
  67. data/test/multibyte.txt +0 -1
  68. data/test/options_test.rb +0 -252
  69. data/test/parameters_test.rb +0 -64
  70. data/test/request_middleware_test.rb +0 -142
  71. data/test/response_middleware_test.rb +0 -72
  72. data/test/strawberry.rb +0 -2
  73. data/test/utils_test.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1c31dbb021fc6a43b4f0b102a9a3ccf52a72303a
4
- data.tar.gz: 54da868027777adb5a21145bd6433b0154af2297
2
+ SHA256:
3
+ metadata.gz: 5fec2e4b9c0c8796f1b0dcb24807f456b121f13ae7f8de0f791d59e424ecb547
4
+ data.tar.gz: f2006014355f091959bda79594951e6fc7304e721433d203ee96ebe4c0058d63
5
5
  SHA512:
6
- metadata.gz: 22c1c286687ca596bd1d6b7d9a6a3749731f6d8962a5bbbe7e1e39cf22e364b92010ae44446cf1804ba10567a2e6409cc2be537375d9f47ace9bca909196dcd3
7
- data.tar.gz: 7e8116cdeea918b8e7de661ec6d49d839960e26f136903e53db62e8cc353f89b3ac053d5efe6401995129418ae4dfce8fda9c8a471093223dca08002615d10e1
6
+ metadata.gz: 53b8e3270ae2cb39b9608ca8fd860379210c87e1c3d9674db5b23b7fa123c44fe2a24e9c70618396525552875ac35f5372be0abd0aeffed7977151573e3cb833
7
+ data.tar.gz: 1de826ef4f4c6d448b64b808a5e93e9e0e92cd6f1799a14d9cdba0ef77c16114632fefd2c4bc80dcfb6015495610165035685f56454b9d4d3acb5fcd9b3f0d79
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2013 Rick Olson, Zack Hobson
1
+ Copyright (c) 2009-2017 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
@@ -1,30 +1,77 @@
1
1
  # Faraday
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/faraday.svg)](https://rubygems.org/gems/faraday)
4
+ [![Build Status](https://travis-ci.org/lostisland/faraday.svg?branch=master)](https://travis-ci.org/lostisland/faraday)
5
+ [![Coverage Status](https://coveralls.io/repos/github/lostisland/faraday/badge.svg?branch=master)](https://coveralls.io/github/lostisland/faraday?branch=master)
6
+ [![Code Climate](https://codeclimate.com/github/lostisland/faraday/badges/gpa.svg)](https://codeclimate.com/github/lostisland/faraday)
7
+ [![Gitter](https://badges.gitter.im/lostisland/faraday.svg)](https://gitter.im/lostisland/faraday?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
8
+
9
+
3
10
  Faraday is an HTTP client lib that provides a common interface over many
4
11
  adapters (such as Net::HTTP) and embraces the concept of Rack middleware when
5
12
  processing the request/response cycle.
6
13
 
7
- Faraday supports these adapters:
14
+ Faraday supports these adapters out of the box:
8
15
 
9
- * Net::HTTP
16
+ * [Net::HTTP][net_http] _(default)_
17
+ * [Net::HTTP::Persistent][persistent]
10
18
  * [Excon][]
11
- * [Typhoeus][]
12
19
  * [Patron][]
13
20
  * [EventMachine][]
14
21
  * [HTTPClient][]
15
22
 
23
+ Adapters are slowly being moved into their own gems, or bundled with HTTP clients:
24
+
25
+ * [Typhoeus][]
26
+
16
27
  It also includes a Rack adapter for hitting loaded Rack applications through
17
28
  Rack::Test, and a Test adapter for stubbing requests by hand.
18
29
 
30
+ ## API documentation
31
+
32
+ Available at [rubydoc.info](http://www.rubydoc.info/gems/faraday).
33
+
19
34
  ## Usage
20
35
 
36
+ ### Basic Use
37
+
38
+ ```ruby
39
+ response = Faraday.get 'http://sushi.com/nigiri/sake.json'
40
+ ```
41
+ A simple `get` request can be performed by using the syntax described above. This works if you don't need to set up anything; you can roll with just the default middleware
42
+ stack and default adapter (see [Faraday::RackBuilder#initialize](https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb)).
43
+
44
+ A more flexible way to use Faraday is to start with a Connection object. If you want to keep the same defaults, you can use this syntax:
45
+
46
+ ```ruby
47
+ conn = Faraday.new(:url => 'http://www.example.com')
48
+ response = conn.get '/users' # GET http://www.example.com/users'
49
+ ```
50
+
51
+ Connections can also take an options hash as a parameter or be configured by using a block. Checkout the section called [Advanced middleware usage](#advanced-middleware-usage) for more details about how to use this block for configurations.
52
+ Since the default middleware stack uses url\_encoded middleware and default adapter, use them on building your own middleware stack.
53
+
21
54
  ```ruby
22
55
  conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
23
56
  faraday.request :url_encoded # form-encode POST params
24
- faraday.response :logger # log requests to STDOUT
57
+ faraday.response :logger # log requests to $stdout
58
+ faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
59
+ end
60
+
61
+ # Filter sensitive information from logs with a regex matcher
62
+
63
+ conn = Faraday.new(:url => 'http://sushi.com/api_key=s3cr3t') do |faraday|
64
+ faraday.request :url_encoded # form-encode POST params
65
+ faraday.response :logger do | logger |
66
+ logger.filter(/(api_key=)(\w+)/,'\1[REMOVED]')
67
+ end
25
68
  faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
26
69
  end
70
+ ```
71
+
72
+ Once you have the connection object, use it to make HTTP requests. You can pass parameters to it in a few different ways:
27
73
 
74
+ ```ruby
28
75
  ## GET ##
29
76
 
30
77
  response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json
@@ -40,7 +87,11 @@ end
40
87
  ## POST ##
41
88
 
42
89
  conn.post '/nigiri', { :name => 'Maguro' } # POST "name=maguro" to http://sushi.com/nigiri
90
+ ```
91
+
92
+ Some configuration options can be adjusted per request:
43
93
 
94
+ ```ruby
44
95
  # post payload as JSON instead of "www-form-urlencoded" encoding:
45
96
  conn.post do |req|
46
97
  req.url '/nigiri'
@@ -57,11 +108,74 @@ conn.get do |req|
57
108
  end
58
109
  ```
59
110
 
60
- If you don't need to set up anything, you can roll with just the default middleware
61
- stack and default adapter (see [Faraday::RackBuilder#initialize](https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb)):
111
+ And you can inject arbitrary data into the request using the `context` option:
62
112
 
63
113
  ```ruby
64
- response = Faraday.get 'http://sushi.com/nigiri/sake.json'
114
+ # Anything you inject using context option will be available in the env on all middlewares
115
+
116
+ conn.get do |req|
117
+ req.url '/search'
118
+ req.options.context = {
119
+ foo: 'foo',
120
+ bar: 'bar'
121
+ }
122
+ end
123
+ ```
124
+
125
+ ### Changing how parameters are serialized
126
+
127
+ Sometimes you need to send the same URL parameter multiple times with different
128
+ values. This requires manually setting the parameter encoder and can be done on
129
+ either per-connection or per-request basis.
130
+
131
+ ```ruby
132
+ # per-connection setting
133
+ conn = Faraday.new :request => { :params_encoder => Faraday::FlatParamsEncoder }
134
+
135
+ conn.get do |req|
136
+ # per-request setting:
137
+ # req.options.params_encoder = my_encoder
138
+ req.params['roll'] = ['california', 'philadelphia']
139
+ end
140
+ # GET 'http://sushi.com?roll=california&roll=philadelphia'
141
+ ```
142
+
143
+ The value of Faraday `params_encoder` can be any object that responds to:
144
+
145
+ * `encode(hash) #=> String`
146
+ * `decode(string) #=> Hash`
147
+
148
+ The encoder will affect both how query strings are processed and how POST bodies
149
+ get serialized. The default encoder is Faraday::NestedParamsEncoder.
150
+
151
+ ## Authentication
152
+
153
+ Basic and Token authentication are handled by Faraday::Request::BasicAuthentication and Faraday::Request::TokenAuthentication respectively. These can be added as middleware manually or through the helper methods.
154
+
155
+ ```ruby
156
+ Faraday.new(...) do |conn|
157
+ conn.basic_auth('username', 'password')
158
+ end
159
+
160
+ Faraday.new(...) do |conn|
161
+ conn.token_auth('authentication-token')
162
+ end
163
+ ```
164
+
165
+ ## Proxy
166
+
167
+ Faraday will try to automatically infer the proxy settings from your system using `URI#find_proxy`.
168
+ This will retrieve them from environment variables such as http_proxy, ftp_proxy, no_proxy, etc.
169
+ If for any reason you want to disable this behaviour, you can do so by setting the global varibale `ignore_env_proxy`:
170
+
171
+ ```ruby
172
+ Faraday.ignore_env_proxy = true
173
+ ```
174
+
175
+ You can also specify a custom proxy when initializing the connection
176
+
177
+ ```ruby
178
+ Faraday.new('http://www.example.com', :proxy => 'http://proxy.com')
65
179
  ```
66
180
 
67
181
  ## Advanced middleware usage
@@ -75,7 +189,11 @@ Faraday.new(...) do |conn|
75
189
  # POST/PUT params encoders:
76
190
  conn.request :multipart
77
191
  conn.request :url_encoded
192
+
193
+ # add custom middleware
194
+ conn.use MyMiddleware
78
195
 
196
+ # Last middleware must be the adapter:
79
197
  conn.adapter :net_http
80
198
  end
81
199
  ```
@@ -138,6 +256,53 @@ later, response. Some keys are:
138
256
  :response_headers
139
257
  ```
140
258
 
259
+ ## Ad-hoc adapters customization
260
+
261
+ Faraday is intended to be a generic interface between your code and the adapter. However, sometimes you need to access a feature specific to one of the adapters that is not covered in Faraday's interface.
262
+
263
+ When that happens, you can pass a block when specifying the adapter to customize it. The block parameter will change based on the adapter you're using. See below for some examples.
264
+
265
+ ### NetHttp
266
+ ```ruby
267
+ conn = Faraday.new(...) do |f|
268
+ f.adapter :net_http do |http| # yields Net::HTTP
269
+ http.idle_timeout = 100
270
+ http.verify_callback = lambda do | preverify_ok, cert_store |
271
+ # do something here...
272
+ end
273
+ end
274
+ end
275
+ ```
276
+
277
+ ### NetHttpPersistent
278
+ ```ruby
279
+ conn = Faraday.new(...) do |f|
280
+ f.adapter :net_http_persistent, pool_size: 5 do |http| # yields Net::HTTP::Persistent
281
+ http.idle_timeout = 100
282
+ http.retry_change_requests = true
283
+ end
284
+ end
285
+ ```
286
+
287
+ ### Patron
288
+ ```ruby
289
+ conn = Faraday.new(...) do |f|
290
+ f.adapter :patron do |session| # yields Patron::Session
291
+ session.max_redirects = 10
292
+ end
293
+ end
294
+ ```
295
+
296
+ ### HTTPClient
297
+ ```ruby
298
+ conn = Faraday.new(...) do |f|
299
+ f.adapter :httpclient do |client| # yields HTTPClient
300
+ client.keep_alive_timeout = 20
301
+ client.ssl_config.timeout = 25
302
+ end
303
+ end
304
+ ```
305
+
141
306
  ## Using Faraday for testing
142
307
 
143
308
  ```ruby
@@ -173,23 +338,14 @@ resp = test.get '/else' #=> raises "no such stub" error
173
338
  stubs.verify_stubbed_calls
174
339
  ```
175
340
 
176
- ## TODO
177
-
178
- * support streaming requests/responses
179
- * better stubbing API
180
-
181
341
  ## Supported Ruby versions
182
342
 
183
343
  This library aims to support and is [tested against][travis] the following Ruby
184
344
  implementations:
185
345
 
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][]
346
+ * Ruby 1.9.3+
347
+ * [JRuby][] 1.7+
348
+ * [Rubinius][] 2+
193
349
 
194
350
  If something doesn't work on one of these Ruby versions, it's a bug.
195
351
 
@@ -204,17 +360,25 @@ implementation, you will be responsible for providing patches in a timely
204
360
  fashion. If critical issues for a particular implementation exist at the time
205
361
  of a major release, support for that Ruby version may be dropped.
206
362
 
363
+ ## Contribute
364
+
365
+ Do you want to contribute to Faraday?
366
+ Open the issues page and check for the `help wanted` label!
367
+ But before you start coding, please read our [Contributing Guide](https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md)
368
+
207
369
  ## Copyright
208
370
 
209
- Copyright (c) 2009-2013 [Rick Olson](mailto:technoweenie@gmail.com), Zack Hobson.
371
+ Copyright (c) 2009-2017 [Rick Olson](mailto:technoweenie@gmail.com), Zack Hobson.
210
372
  See [LICENSE][] for details.
211
373
 
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/
374
+ [net_http]: http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html
375
+ [persistent]: https://github.com/drbrain/net-http-persistent
376
+ [travis]: https://travis-ci.org/lostisland/faraday
377
+ [excon]: https://github.com/excon/excon#readme
378
+ [patron]: http://toland.github.io/patron/
216
379
  [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
380
+ [httpclient]: https://github.com/nahi/httpclient
381
+ [typhoeus]: https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
382
+ [jruby]: http://jruby.org/
383
+ [rubinius]: http://rubini.us/
384
+ [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
 
@@ -20,6 +15,9 @@ module Faraday
20
15
  opts[:client_key] = ssl[:client_key] if ssl[:client_key]
21
16
  opts[:certificate] = ssl[:certificate] if ssl[:certificate]
22
17
  opts[:private_key] = ssl[:private_key] if ssl[:private_key]
18
+ opts[:ssl_version] = ssl[:version] if ssl[:version]
19
+ opts[:ssl_min_version] = ssl[:min_version] if ssl[:min_version]
20
+ opts[:ssl_max_version] = ssl[:max_version] if ssl[:max_version]
23
21
 
24
22
  # https://github.com/geemus/excon/issues/106
25
23
  # https://github.com/jruby/jruby-ossl/issues/19
@@ -35,12 +33,12 @@ module Faraday
35
33
 
36
34
  if req[:open_timeout]
37
35
  opts[:connect_timeout] = req[:open_timeout]
38
- opts[:write_timeout] = req[:open_timeout]
39
36
  end
40
37
 
41
38
  if req[:proxy]
42
39
  opts[:proxy] = {
43
40
  :host => req[:proxy][:uri].host,
41
+ :hostname => req[:proxy][:uri].hostname,
44
42
  :port => req[:proxy][:uri].port,
45
43
  :scheme => req[:proxy][:uri].scheme,
46
44
  :user => req[:proxy][:user],
@@ -49,14 +47,14 @@ module Faraday
49
47
  end
50
48
  end
51
49
 
52
- conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
50
+ conn = create_connection(env, opts)
53
51
 
54
52
  resp = conn.request \
55
53
  :method => env[:method].to_s.upcase,
56
54
  :headers => env[:request_headers],
57
55
  :body => read_body(env)
58
56
 
59
- save_response(env, resp.status.to_i, resp.body, resp.headers)
57
+ save_response(env, resp.status.to_i, resp.body, resp.headers, resp.reason_phrase)
60
58
 
61
59
  @app.call env
62
60
  rescue ::Excon::Errors::SocketError => err
@@ -71,6 +69,10 @@ module Faraday
71
69
  raise Error::TimeoutError, err
72
70
  end
73
71
 
72
+ def create_connection(env, opts)
73
+ ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
74
+ end
75
+
74
76
  # TODO: support streaming requests
75
77
  def read_body(env)
76
78
  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, SocketError
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,
@@ -27,14 +28,16 @@ module Faraday
27
28
  NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
28
29
  NET_HTTP_EXCEPTIONS << Net::OpenTimeout if defined?(Net::OpenTimeout)
29
30
 
31
+ def initialize(app = nil, opts = {}, &block)
32
+ @cert_store = nil
33
+ super(app, opts, &block)
34
+ end
35
+
30
36
  def call(env)
31
37
  super
32
38
  with_net_http_connection(env) do |http|
33
39
  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]
40
+ configure_request(http, env[:request])
38
41
 
39
42
  begin
40
43
  http_response = perform_request(http, env)
@@ -46,7 +49,7 @@ module Faraday
46
49
  end
47
50
  end
48
51
 
49
- save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers|
52
+ save_response(env, http_response.code.to_i, http_response.body || '', nil, http_response.message) do |response_headers|
50
53
  http_response.each_header do |key, value|
51
54
  response_headers[key] = value
52
55
  end
@@ -54,10 +57,12 @@ module Faraday
54
57
  end
55
58
 
56
59
  @app.call env
57
- rescue Timeout::Error => err
60
+ rescue Timeout::Error, Errno::ETIMEDOUT => err
58
61
  raise Faraday::Error::TimeoutError, err
59
62
  end
60
63
 
64
+ private
65
+
61
66
  def create_request(env)
62
67
  request = Net::HTTPGenericRequest.new \
63
68
  env[:method].to_s.upcase, # request method
@@ -89,10 +94,10 @@ module Faraday
89
94
 
90
95
  def net_http_connection(env)
91
96
  if proxy = env[:request][:proxy]
92
- Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
97
+ Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
93
98
  else
94
99
  Net::HTTP
95
- end.new(env[:url].host, env[:url].port)
100
+ end.new(env[:url].hostname, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
96
101
  end
97
102
 
98
103
  def configure_ssl(http, ssl)
@@ -106,14 +111,31 @@ module Faraday
106
111
  http.ca_path = ssl[:ca_path] if ssl[:ca_path]
107
112
  http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
108
113
  http.ssl_version = ssl[:version] if ssl[:version]
114
+ http.min_version = ssl[:min_version] if ssl[:min_version]
115
+ http.max_version = ssl[:max_version] if ssl[:max_version]
116
+ end
117
+
118
+ def configure_request(http, req)
119
+ if req[:timeout]
120
+ http.read_timeout = req[:timeout]
121
+ http.open_timeout = req[:timeout]
122
+ http.write_timeout = req[:timeout] if http.respond_to?(:write_timeout=)
123
+ end
124
+ http.open_timeout = req[:open_timeout] if req[:open_timeout]
125
+ http.write_timeout = req[:write_timeout] if req[:write_timeout] && http.respond_to?(:write_timeout=)
126
+ # Only set if Net::Http supports it, since Ruby 2.5.
127
+ http.max_retries = 0 if http.respond_to?(:max_retries=)
128
+
129
+ @config_block.call(http) if @config_block
109
130
  end
110
131
 
111
132
  def ssl_cert_store(ssl)
112
133
  return ssl[:cert_store] if ssl[:cert_store]
134
+ return @cert_store if @cert_store
113
135
  # Use the default cert store by default, i.e. system ca certs
114
- cert_store = OpenSSL::X509::Store.new
115
- cert_store.set_default_paths
116
- cert_store
136
+ @cert_store = OpenSSL::X509::Store.new
137
+ @cert_store.set_default_paths
138
+ @cert_store
117
139
  end
118
140
 
119
141
  def ssl_verify_mode(ssl)