faraday 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,6 +26,9 @@ This mess is gonna get raw, like sushi. So, haters to the left.
26
26
  req.body = {:name => 'Unagi'}
27
27
  end
28
28
 
29
+ # If you're ready to roll with just the bare minimum (net/http):
30
+ resp1 = Faraday.get 'http://sushi.com/nigiri/sake.json'
31
+
29
32
  == Testing
30
33
 
31
34
  # It's possible to define stubbed request outside a test adapter block.
@@ -63,7 +66,7 @@ This mess is gonna get raw, like sushi. So, haters to the left.
63
66
 
64
67
  * Add curb/em-http support
65
68
  * Add xml parsing
66
- * Support timeouts, proxy servers, ssl options
69
+ * Support timeouts, proxy servers, ssl options on Typhoeus/Patron
67
70
  * Add streaming requests and responses
68
71
  * Add default middleware load out for common cases
69
72
  * Add symbol => string index for mime types (:json => 'application/json')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{faraday}
8
- s.version = "0.3.1"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["rick"]
12
- s.date = %q{2010-04-22}
12
+ s.date = %q{2010-04-27}
13
13
  s.description = %q{HTTP/REST API client library with pluggable components}
14
14
  s.email = %q{technoweenie@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -1,6 +1,62 @@
1
1
  require 'rack/utils'
2
2
 
3
3
  module Faraday
4
+ class << self
5
+ attr_accessor :default_adapter
6
+ attr_writer :default_connection
7
+ end
8
+
9
+ self.default_adapter = :net_http
10
+
11
+ def self.default_connection
12
+ @default_connection ||= Connection.new
13
+ end
14
+
15
+ # use the method signature from Faraday::Connection
16
+ def self.build(options = {}, &block)
17
+ default_connection.build(options, &block)
18
+ end
19
+
20
+ def self.get(url = nil, headers = nil, &block)
21
+ default_connection.get(url, headers, &block)
22
+ end
23
+
24
+ def self.post(url = nil, body = nil, headers = nil, &block)
25
+ default_connection.post(url, body, headers, &block)
26
+ end
27
+
28
+ def self.put(url = nil, body = nil, headers = nil, &block)
29
+ default_connection.put(url, body, headers, &block)
30
+ end
31
+
32
+ def self.head(url = nil, headers = nil, &block)
33
+ default_connection.head(url, headers, &block)
34
+ end
35
+
36
+ def self.delete(url = nil, headers = nil, &block)
37
+ default_connection.delete(url, headers, &block)
38
+ end
39
+
40
+ def self.in_parallel?
41
+ default_connection.in_parallel?
42
+ end
43
+
44
+ def self.in_parallel(manager)
45
+ default_connection.in_parallel(manager)
46
+ end
47
+
48
+ def self.proxy(arg = nil)
49
+ default_connection.proxy(arg)
50
+ end
51
+
52
+ def self.url_prefix=(url)
53
+ default_connection.url_prefix = url
54
+ end
55
+
56
+ def self.path_prefix=(value)
57
+ default_connection.path_prefix = value
58
+ end
59
+
4
60
  module AutoloadHelper
5
61
  def register_lookup_modules(mods)
6
62
  (@lookup_module_index ||= {}).update(mods)
@@ -1,11 +1,34 @@
1
- require 'net/http'
1
+ begin
2
+ require 'net/https'
3
+ rescue LoadError
4
+ puts "no such file to load -- net/https. Make sure openssl is installed if you want ssl support"
5
+ require 'net/http'
6
+ end
7
+
2
8
  module Faraday
3
9
  module Adapter
4
10
  class NetHttp < Middleware
5
11
  def call(env)
6
12
  process_body_for_request(env)
7
13
 
8
- http = Net::HTTP.new(env[:url].host, env[:url].port)
14
+ is_ssl = env[:url].scheme == 'https'
15
+
16
+ http = net_http_class(env).new(env[:url].host, env[:url].port || (is_ssl ? 443 : 80))
17
+ if http.use_ssl = is_ssl
18
+ ssl = env[:ssl]
19
+ if ssl[:verify] == false
20
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
21
+ else
22
+ http.verify_mode = ssl[:verify]
23
+ end
24
+ http.cert = ssl[:client_cert] if ssl[:client_cert]
25
+ http.key = ssl[:client_key] if ssl[:client_key]
26
+ http.ca_file = ssl[:ca_file] if ssl[:ca_file]
27
+ end
28
+ req = env[:request]
29
+ http.read_timeout = net.open_timeout = req[:timeout] if req[:timeout]
30
+ http.open_timeout = req[:open_timeout] if req[:open_timeout]
31
+
9
32
  full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
10
33
  http_resp = http.send_request(env[:method].to_s.upcase, full_path, env[:body], env[:request_headers])
11
34
 
@@ -23,6 +46,14 @@ module Faraday
23
46
  rescue Errno::ECONNREFUSED
24
47
  raise Error::ConnectionFailed, "connection refused"
25
48
  end
49
+
50
+ def net_http_class(env)
51
+ if proxy = env[:request][:proxy]
52
+ Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password])
53
+ else
54
+ Net::HTTP
55
+ end
56
+ end
26
57
  end
27
58
  end
28
59
  end
@@ -20,7 +20,8 @@ module Faraday
20
20
  req = ::Typhoeus::Request.new env[:url].to_s,
21
21
  :method => env[:method],
22
22
  :body => env[:body],
23
- :headers => env[:request_headers]
23
+ :headers => env[:request_headers],
24
+ :disable_ssl_peer_verification => (env[:ssl][:verify] == false)
24
25
 
25
26
  req.on_complete do |resp|
26
27
  env.update \
@@ -24,9 +24,13 @@ module Faraday
24
24
  build(&block) if block_given?
25
25
  end
26
26
 
27
- def build(&block)
27
+ def build(options = {}, &block)
28
+ inner = @handlers.shift
29
+ if !options[:keep]
30
+ @handlers.clear
31
+ end
28
32
  block.call(self)
29
- run(self.class.inner_app)
33
+ run(inner || self.class.inner_app)
30
34
  end
31
35
 
32
36
  def [](index)
@@ -39,6 +43,10 @@ module Faraday
39
43
  end
40
44
 
41
45
  def to_app
46
+ if @handlers.empty?
47
+ build { |b| b.adapter Faraday.default_adapter }
48
+ end
49
+
42
50
  inner_app = @handlers.first
43
51
  @handlers[1..-1].inject(inner_app) { |app, middleware| middleware.call(app) }
44
52
  end
@@ -16,11 +16,13 @@ module Faraday
16
16
  METHODS_WITH_BODIES = Set.new [:post, :put]
17
17
 
18
18
  attr_accessor :host, :port, :scheme, :params, :headers, :parallel_manager
19
- attr_reader :path_prefix, :builder
19
+ attr_reader :path_prefix, :builder, :options, :ssl
20
20
 
21
21
  # :url
22
22
  # :params
23
23
  # :headers
24
+ # :request
25
+ # :ssl
24
26
  def initialize(url = nil, options = {}, &block)
25
27
  if url.is_a?(Hash)
26
28
  options = url
@@ -28,8 +30,11 @@ module Faraday
28
30
  end
29
31
  @headers = HeaderHash.new
30
32
  @params = {}
33
+ @options = options[:request] || {}
34
+ @ssl = options[:ssl] || {}
31
35
  @parallel_manager = options[:parallel]
32
36
  self.url_prefix = url if url
37
+ proxy(options[:proxy])
33
38
  merge_params @params, options[:params] if options[:params]
34
39
  merge_headers @headers, options[:headers] if options[:headers]
35
40
  if block
@@ -39,8 +44,8 @@ module Faraday
39
44
  end
40
45
  end
41
46
 
42
- def build(&block)
43
- @builder.build(&block)
47
+ def build(options = {}, &block)
48
+ @builder.build(options, &block)
44
49
  end
45
50
 
46
51
  def get(url = nil, headers = nil, &block)
@@ -63,19 +68,6 @@ module Faraday
63
68
  run_request :delete, url, nil, headers, &block
64
69
  end
65
70
 
66
- def run_request(method, url, body, headers)
67
- if !METHODS.include?(method)
68
- raise ArgumentError, "unknown http method: #{method}"
69
- end
70
-
71
- Request.run(self, method) do |req|
72
- req.url(url) if url
73
- req.headers.update(headers) if headers
74
- req.body = body if body
75
- yield req if block_given?
76
- end
77
- end
78
-
79
71
  def in_parallel?
80
72
  !!@parallel_manager
81
73
  end
@@ -88,9 +80,20 @@ module Faraday
88
80
  @parallel_manager = nil
89
81
  end
90
82
 
91
- # return the assembled Rack application for this instance.
92
- def to_app
93
- @builder.to_app
83
+ def proxy(arg = nil)
84
+ return @proxy if arg.nil?
85
+
86
+ @proxy =
87
+ case arg
88
+ when String then {:uri => proxy_arg_to_uri(arg)}
89
+ when URI then {:uri => arg}
90
+ when Hash then arg
91
+ if arg[:uri] = proxy_arg_to_uri(arg[:uri])
92
+ arg
93
+ else
94
+ raise ArgumentError, "no :uri option."
95
+ end
96
+ end
94
97
  end
95
98
 
96
99
  # Parses the giving url with Addressable::URI and stores the individual
@@ -124,6 +127,24 @@ module Faraday
124
127
  @path_prefix = value
125
128
  end
126
129
 
130
+ # return the assembled Rack application for this instance.
131
+ def to_app
132
+ @builder.to_app
133
+ end
134
+
135
+ def run_request(method, url, body, headers)
136
+ if !METHODS.include?(method)
137
+ raise ArgumentError, "unknown http method: #{method}"
138
+ end
139
+
140
+ Request.run(self, method) do |req|
141
+ req.url(url) if url
142
+ req.headers.update(headers) if headers
143
+ req.body = body if body
144
+ yield req if block_given?
145
+ end
146
+ end
147
+
127
148
  # Takes a relative url for a request and combines it with the defaults
128
149
  # set on the connection instance.
129
150
  #
@@ -137,9 +158,9 @@ module Faraday
137
158
  #
138
159
  def build_url(url, params = nil)
139
160
  uri = URI.parse(url.to_s)
140
- uri.scheme ||= @scheme
141
161
  uri.host ||= @host
142
162
  uri.port ||= @port
163
+ uri.scheme ||= @scheme
143
164
  if @path_prefix && uri.path !~ /^\//
144
165
  uri.path = "#{@path_prefix.size > 1 ? @path_prefix : nil}/#{uri.path}"
145
166
  end
@@ -189,5 +210,12 @@ module Faraday
189
210
  '%' << $1.unpack('H2'*bytesize($1)).join('%').tap { |c| c.upcase! }
190
211
  end
191
212
  end
213
+
214
+ def proxy_arg_to_uri(arg)
215
+ case arg
216
+ when String then URI.parse(arg)
217
+ when URI then arg
218
+ end
219
+ end
192
220
  end
193
221
  end
@@ -54,6 +54,14 @@ module Faraday
54
54
  # :response_headers - Hash of HTTP headers from the server
55
55
  # :parallel_manager - sent if the connection is in parallel mode
56
56
  # :response - the actual response object that stores the rack response
57
+ # :request - Hash of options for configuring the request.
58
+ # :timeout - open/read timeout Integer in seconds
59
+ # :open_timeout - read timeout Integer in seconds
60
+ # :proxy - Hash of proxy options
61
+ # :uri - Proxy Server URI
62
+ # :user - Proxy server username
63
+ # :password - Proxy server password
64
+ # :ssl - Hash of options for configuring SSL requests.
57
65
  def to_env_hash(connection, request_method)
58
66
  env_headers = connection.headers.dup
59
67
  env_params = connection.params.dup
@@ -65,7 +73,9 @@ module Faraday
65
73
  :url => connection.build_url(path, env_params),
66
74
  :request_headers => env_headers.update(headers),
67
75
  :parallel_manager => connection.parallel_manager,
68
- :response => Response.new}
76
+ :response => Response.new,
77
+ :request => connection.options.merge(:proxy => connection.proxy),
78
+ :ssl => connection.ssl}
69
79
  end
70
80
 
71
81
  def run(connection, request_method)
@@ -3,7 +3,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
3
3
  if Faraday::TestCase::LIVE_SERVER
4
4
  module Adapters
5
5
  class LiveTest < Faraday::TestCase
6
- Faraday::Adapter.all_loaded_constants.each do |adapter|
6
+ (Faraday::Adapter.all_loaded_constants + [:default]).each do |adapter|
7
7
  define_method "test_#{adapter}_GET_retrieves_the_response_body" do
8
8
  assert_equal 'hello world', create_connection(adapter).get('hello_world').body
9
9
  end
@@ -100,6 +100,7 @@ if Faraday::TestCase::LIVE_SERVER
100
100
  resp1, resp2 = nil, nil
101
101
 
102
102
  connection = create_connection(adapter)
103
+ adapter = real_adapter_for(adapter)
103
104
 
104
105
  connection.in_parallel(adapter.setup_parallel_manager) do
105
106
  resp1 = connection.get('json')
@@ -117,8 +118,22 @@ if Faraday::TestCase::LIVE_SERVER
117
118
  end
118
119
 
119
120
  def create_connection(adapter)
120
- Faraday::Connection.new LIVE_SERVER do |b|
121
- b.use adapter
121
+ if adapter == :default
122
+ conn = Faraday.default_connection
123
+ conn.url_prefix = LIVE_SERVER
124
+ conn
125
+ else
126
+ Faraday::Connection.new LIVE_SERVER do |b|
127
+ b.use adapter
128
+ end
129
+ end
130
+ end
131
+
132
+ def real_adapter_for(adapter)
133
+ if adapter == :default
134
+ Faraday::Adapter.lookup_module(Faraday.default_adapter)
135
+ else
136
+ adapter
122
137
  end
123
138
  end
124
139
  end
@@ -139,16 +139,61 @@ class TestConnection < Faraday::TestCase
139
139
  assert_no_match /token=abc/, url.query
140
140
  end
141
141
 
142
- def test_build_url_parses_url_into_host
142
+ def test_build_url_parses_url
143
143
  conn = Faraday::Connection.new
144
144
  uri = conn.build_url("http://sushi.com/sake.html")
145
- assert_equal "sushi.com", uri.host
145
+ assert_equal "http", uri.scheme
146
+ assert_equal "sushi.com", uri.host
147
+ assert_equal '/sake.html', uri.path
148
+ assert_nil uri.port
149
+ end
150
+
151
+ def test_build_url_parses_url_and_changes_scheme
152
+ conn = Faraday::Connection.new :url => "http://sushi.com/sushi"
153
+ conn.scheme = 'https'
154
+ uri = conn.build_url("sake.html")
155
+ assert_equal 'https://sushi.com/sushi/sake.html', uri.to_s
146
156
  end
147
157
 
148
- def test_build_url_parses_url_into_port
158
+ def test_proxy_accepts_string
149
159
  conn = Faraday::Connection.new
150
- uri = conn.build_url("http://sushi.com/sake.html")
151
- assert_nil uri.port
160
+ conn.proxy 'http://proxy.com'
161
+ assert_equal 'proxy.com', conn.proxy.host
162
+ end
163
+
164
+ def test_proxy_accepts_string
165
+ conn = Faraday::Connection.new
166
+ conn.proxy 'http://proxy.com'
167
+ assert_equal 'proxy.com', conn.proxy[:uri].host
168
+ assert_equal [:uri], conn.proxy.keys
169
+ end
170
+
171
+ def test_proxy_accepts_uri
172
+ conn = Faraday::Connection.new
173
+ conn.proxy Addressable::URI.parse('http://proxy.com')
174
+ assert_equal 'proxy.com', conn.proxy[:uri].host
175
+ assert_equal [:uri], conn.proxy.keys
176
+ end
177
+
178
+ def test_proxy_accepts_hash_with_string_uri
179
+ conn = Faraday::Connection.new
180
+ conn.proxy :uri => 'http://proxy.com', :user => 'rick'
181
+ assert_equal 'proxy.com', conn.proxy[:uri].host
182
+ assert_equal 'rick', conn.proxy[:user]
183
+ end
184
+
185
+ def test_proxy_accepts_hash
186
+ conn = Faraday::Connection.new
187
+ conn.proxy :uri => Addressable::URI.parse('http://proxy.com'), :user => 'rick'
188
+ assert_equal 'proxy.com', conn.proxy[:uri].host
189
+ assert_equal 'rick', conn.proxy[:user]
190
+ end
191
+
192
+ def test_proxy_requires_uri
193
+ conn = Faraday::Connection.new
194
+ assert_raises ArgumentError do
195
+ conn.proxy :uri => :bad_uri, :user => 'rick'
196
+ end
152
197
  end
153
198
 
154
199
  def test_params_to_query_converts_hash_of_params_to_uri_escaped_query_string
@@ -173,4 +218,43 @@ class TestConnection < Faraday::TestCase
173
218
  assert_not_equal conn.send(attr).object_id, duped.send(attr).object_id
174
219
  end
175
220
  end
176
- end
221
+
222
+ def test_allows_rebuilding_of_connection_handlers
223
+ conn = Faraday::Connection.new
224
+ conn.to_app
225
+ inner = conn.builder.handlers[0]
226
+ mware = conn.builder.handlers[1].call({})
227
+ assert_kind_of Faraday::Adapter::NetHttp, mware
228
+
229
+ conn.build do |b|
230
+ b.adapter :test
231
+ end
232
+ mware = conn.builder.handlers[1].call({})
233
+ assert_kind_of Faraday::Adapter::Test, mware
234
+ assert_equal inner, conn.builder.handlers[0]
235
+ end
236
+
237
+ def test_allows_extending_of_existing_connection_handlers
238
+ conn = Faraday::Connection.new
239
+ conn.to_app
240
+ mware = conn.builder.handlers[1].call({})
241
+ assert_kind_of Faraday::Adapter::NetHttp, mware
242
+ assert_equal 2, conn.builder.handlers.size
243
+
244
+ conn.build :keep => true do |b|
245
+ b.adapter :test
246
+ end
247
+ mware = conn.builder.handlers[1].call({})
248
+ assert_kind_of Faraday::Adapter::Test, mware
249
+ assert_equal 3, conn.builder.handlers.size
250
+ end
251
+
252
+ def test_sets_default_adapter_if_none_set
253
+ conn = Faraday::Connection.new
254
+ assert_equal 0, conn.builder.handlers.size
255
+
256
+ app = conn.to_app
257
+ mware = conn.builder.handlers[1].call({})
258
+ assert_kind_of Faraday::Adapter::NetHttp, mware
259
+ end
260
+ end
@@ -3,15 +3,18 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
3
3
  class TestEnv < Faraday::TestCase
4
4
  def setup
5
5
  @conn = Faraday::Connection.new :url => 'http://sushi.com/api', :headers => {'Mime-Version' => '1.0'}
6
+ @conn.options[:timeout] = 3
7
+ @conn.options[:open_timeout] = 5
8
+ @conn.ssl[:verify] = false
9
+ @conn.proxy 'http://proxy.com'
6
10
  @input = {
7
11
  :body => 'abc',
8
12
  :headers => {'Server' => 'Faraday'}}
9
- @env_setup = Faraday::Request.create do |req|
13
+ @env = env_for @conn do |req|
10
14
  req.url 'foo.json', 'a' => 1
11
15
  req['Server'] = 'Faraday'
12
16
  req.body = @input[:body]
13
17
  end
14
- @env = @env_setup.to_env_hash(@conn, :get)
15
18
  end
16
19
 
17
20
  def test_request_create_stores_method
@@ -30,4 +33,24 @@ class TestEnv < Faraday::TestCase
30
33
  def test_request_create_stores_body
31
34
  assert_equal @input[:body], @env[:body]
32
35
  end
36
+
37
+ def test_request_create_stores_ssl_options
38
+ assert_equal 3, @env[:request][:timeout]
39
+ assert_equal 5, @env[:request][:open_timeout]
40
+ end
41
+
42
+ def test_request_create_stores_ssl_options
43
+ assert_equal false, @env[:ssl][:verify]
44
+ end
45
+
46
+ def test_request_create_stores_proxy_options
47
+ assert_equal 'proxy.com', @env[:request][:proxy][:uri].host
48
+ end
49
+
50
+ def env_for(connection)
51
+ env_setup = Faraday::Request.create do |req|
52
+ yield req
53
+ end
54
+ env_setup.to_env_hash(connection, :get)
55
+ end
33
56
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - rick
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-04-22 00:00:00 -04:00
12
+ date: 2010-04-27 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency