faraday 0.4.6 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
- require 'rack/utils'
2
-
3
1
  module Faraday
2
+ VERSION = "0.5.0"
3
+
4
4
  class << self
5
5
  attr_accessor :default_adapter
6
6
  attr_writer :default_connection
@@ -42,37 +42,28 @@ module Faraday
42
42
  end
43
43
 
44
44
  def all_loaded_constants
45
- constants.map { |c| const_get(c) }.select { |a| a.loaded? }
45
+ constants.map { |c| const_get(c) }.
46
+ select { |a| a.respond_to?(:loaded?) && a.loaded? }
46
47
  end
47
48
  end
48
49
 
49
50
  extend AutoloadHelper
50
51
 
51
- autoload_all 'faraday',
52
- :Connection => 'connection',
53
- :Middleware => 'middleware',
54
- :Builder => 'builder',
55
- :Request => 'request',
56
- :Response => 'response',
57
- :Error => 'error'
58
-
59
- module Adapter
60
- extend AutoloadHelper
61
- autoload_all 'faraday/adapter',
62
- :NetHttp => 'net_http',
63
- :Typhoeus => 'typhoeus',
64
- :Patron => 'patron',
65
- :Test => 'test'
66
-
67
- register_lookup_modules \
68
- :test => :Test,
69
- :net_http => :NetHttp,
70
- :typhoeus => :Typhoeus,
71
- :patron => :Patron,
72
- :net_http => :NetHttp
73
- end
52
+ autoload_all 'faraday',
53
+ :Middleware => 'middleware',
54
+ :Builder => 'builder',
55
+ :Request => 'request',
56
+ :Response => 'response',
57
+ :CompositeReadIO => 'upload_io',
58
+ :UploadIO => 'upload_io',
59
+ :Parts => 'upload_io'
74
60
  end
75
61
 
62
+ require 'faraday/utils'
63
+ require 'faraday/connection'
64
+ require 'faraday/adapter'
65
+ require 'faraday/error'
66
+
76
67
  # not pulling in active-support JUST for this method.
77
68
  class Object
78
69
  # Yields <code>x</code> to the block, and then returns <code>x</code>.
@@ -0,0 +1,102 @@
1
+ module Faraday
2
+ class Adapter < Middleware
3
+ FORM_TYPE = 'application/x-www-form-urlencoded'.freeze
4
+ MULTIPART_TYPE = 'multipart/form-data'.freeze
5
+ CONTENT_TYPE = 'Content-Type'.freeze
6
+ DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze
7
+
8
+ extend AutoloadHelper
9
+ autoload_all 'faraday/adapter',
10
+ :ActionDispatch => 'action_dispatch',
11
+ :NetHttp => 'net_http',
12
+ :Typhoeus => 'typhoeus',
13
+ :Patron => 'patron',
14
+ :Test => 'test'
15
+
16
+ register_lookup_modules \
17
+ :action_dispatch => :ActionDispatch,
18
+ :test => :Test,
19
+ :net_http => :NetHttp,
20
+ :typhoeus => :Typhoeus,
21
+ :patron => :Patron,
22
+ :net_http => :NetHttp
23
+
24
+ def call(env)
25
+ process_body_for_request(env)
26
+ end
27
+
28
+ # Converts a body hash into encoded form params. This is done as late
29
+ # as possible in the request cycle in case some other middleware wants to
30
+ # act on the request before sending it out.
31
+ #
32
+ # env - The current request environment Hash.
33
+ # body - A Hash of keys/values. Strings and empty values will be
34
+ # ignored. Default: env[:body]
35
+ # headers - The Hash of request headers. Default: env[:request_headers]
36
+ #
37
+ # Returns nothing. If the body is processed, it is replaced in the
38
+ # environment for you.
39
+ def process_body_for_request(env, body = env[:body], headers = env[:request_headers])
40
+ return if body.nil? || body.empty? || !body.respond_to?(:each_key)
41
+ if has_multipart?(body)
42
+ env[:request] ||= {}
43
+ env[:request][:boundary] ||= DEFAULT_BOUNDARY
44
+ headers[CONTENT_TYPE] = MULTIPART_TYPE + ";boundary=#{env[:request][:boundary]}"
45
+ env[:body] = create_multipart(env, body)
46
+ else
47
+ type = headers[CONTENT_TYPE]
48
+ headers[CONTENT_TYPE] = FORM_TYPE if type.nil? || type.empty?
49
+ parts = []
50
+ process_to_params(parts, env[:body]) do |key, value|
51
+ "#{key}=#{escape(value.to_s)}"
52
+ end
53
+ env[:body] = parts * "&"
54
+ end
55
+ end
56
+
57
+ def has_multipart?(body)
58
+ body.values.each do |v|
59
+ if v.respond_to?(:content_type)
60
+ return true
61
+ elsif v.respond_to?(:values)
62
+ return true if has_multipart?(v)
63
+ end
64
+ end
65
+ false
66
+ end
67
+
68
+ def create_multipart(env, params, boundary = nil)
69
+ boundary ||= env[:request][:boundary]
70
+ parts = []
71
+ process_to_params(parts, params) do |key, value|
72
+ Faraday::Parts::Part.new(boundary, key, value)
73
+ end
74
+ parts << Faraday::Parts::EpiloguePart.new(boundary)
75
+ env[:request_headers]['Content-Length'] = parts.inject(0) {|sum,i| sum + i.length }.to_s
76
+ Faraday::CompositeReadIO.new(*parts.map{|p| p.to_io })
77
+ end
78
+
79
+ def process_to_params(pieces, params, base = nil, &block)
80
+ params.each do |key, value|
81
+ key_str = base ? "#{base}[#{key}]" : key
82
+ if value.kind_of?(Hash)
83
+ process_to_params(pieces, value, key_str, &block)
84
+ else
85
+ pieces << block.call(key_str, value)
86
+ end
87
+ end
88
+ end
89
+
90
+ # assume that query and fragment are already encoded properly
91
+ def full_path_for(path, query = nil, fragment = nil)
92
+ full_path = path.dup
93
+ if query && !query.empty?
94
+ full_path << "?#{query}"
95
+ end
96
+ if fragment && !fragment.empty?
97
+ full_path << "##{fragment}"
98
+ end
99
+ full_path
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,39 @@
1
+ module Faraday
2
+ class Adapter
3
+ class ActionDispatch < Faraday::Adapter
4
+ attr_reader :session
5
+
6
+ # Initializes a new middleware instance for each request. Instead of
7
+ # initiating an HTTP request with a web server, this adapter calls
8
+ # a Rails 3 app using integration tests.
9
+ #
10
+ # app - The current Faraday request.
11
+ # session - An ActionDispatch::Integration::Session instance.
12
+ #
13
+ # Returns nothing.
14
+ def initialize(app, session)
15
+ super(app)
16
+ @session = session
17
+ @session.reset!
18
+ end
19
+
20
+ def call(env)
21
+ super
22
+ full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
23
+ @session.__send__(env[:method], full_path, env[:body], env[:request_headers])
24
+ resp = @session.response
25
+ env.update \
26
+ :status => resp.status,
27
+ :response_headers => resp.headers,
28
+ :body => resp.body
29
+ @app.call env
30
+ end
31
+
32
+ # TODO: build in support for multipart streaming if action dispatch supports it.
33
+ def create_multipart(env, params, boundary = nil)
34
+ stream = super
35
+ stream.read
36
+ end
37
+ end
38
+ end
39
+ end
@@ -6,10 +6,10 @@ rescue LoadError
6
6
  end
7
7
 
8
8
  module Faraday
9
- module Adapter
10
- class NetHttp < Middleware
9
+ class Adapter
10
+ class NetHttp < Faraday::Adapter
11
11
  def call(env)
12
- process_body_for_request(env)
12
+ super
13
13
 
14
14
  is_ssl = env[:url].scheme == 'https'
15
15
 
@@ -28,9 +28,21 @@ module Faraday
28
28
  req = env[:request]
29
29
  http.read_timeout = net.open_timeout = req[:timeout] if req[:timeout]
30
30
  http.open_timeout = req[:open_timeout] if req[:open_timeout]
31
-
31
+
32
32
  full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
33
- http_resp = http.send_request(env[:method].to_s.upcase, full_path, env[:body], env[:request_headers])
33
+ http_req = Net::HTTPGenericRequest.new(
34
+ env[:method].to_s.upcase, # request method
35
+ (env[:body] ? true : false), # is there data
36
+ true, # does net/http love you, true or false?
37
+ full_path, # request uri path
38
+ env[:request_headers]) # request headers
39
+
40
+ if env[:body].respond_to?(:read)
41
+ http_req.body_stream = env[:body]
42
+ env[:body] = nil
43
+ end
44
+
45
+ http_resp = http.request http_req, env[:body]
34
46
 
35
47
  resp_headers = {}
36
48
  http_resp.each_header do |key, value|
@@ -38,13 +50,13 @@ module Faraday
38
50
  end
39
51
 
40
52
  env.update \
41
- :status => http_resp.code.to_i,
42
- :response_headers => resp_headers,
53
+ :status => http_resp.code.to_i,
54
+ :response_headers => resp_headers,
43
55
  :body => http_resp.body
44
56
 
45
57
  @app.call env
46
58
  rescue Errno::ECONNREFUSED
47
- raise Error::ConnectionFailed, "connection refused"
59
+ raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
48
60
  end
49
61
 
50
62
  def net_http_class(env)
@@ -1,6 +1,6 @@
1
1
  module Faraday
2
- module Adapter
3
- class Patron < Middleware
2
+ class Adapter
3
+ class Patron < Faraday::Adapter
4
4
  begin
5
5
  require 'patron'
6
6
  rescue LoadError, NameError => e
@@ -8,7 +8,7 @@ module Faraday
8
8
  end
9
9
 
10
10
  def call(env)
11
- process_body_for_request(env)
11
+ super
12
12
 
13
13
  sess = ::Patron::Session.new
14
14
  args = [env[:method], env[:url].to_s, env[:request_headers]]
@@ -26,7 +26,13 @@ module Faraday
26
26
 
27
27
  @app.call env
28
28
  rescue Errno::ECONNREFUSED
29
- raise Error::ConnectionFailed, "connection refused"
29
+ raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
30
+ end
31
+
32
+ # TODO: build in support for multipart streaming if patron supports it.
33
+ def create_multipart(env, params, boundary = nil)
34
+ stream = super
35
+ stream.read
30
36
  end
31
37
  end
32
38
  end
@@ -1,5 +1,5 @@
1
1
  module Faraday
2
- module Adapter
2
+ class Adapter
3
3
  # test = Faraday::Connection.new do
4
4
  # use Faraday::Adapter::Test do |stub|
5
5
  # stub.get '/nigiri/sake.json' do
@@ -19,7 +19,7 @@ module Faraday
19
19
  class Stubs
20
20
  def initialize
21
21
  # {:get => [Stub, Stub]}
22
- @stack = {}
22
+ @stack, @consumed = {}, {}
23
23
  yield self if block_given?
24
24
  end
25
25
 
@@ -29,8 +29,15 @@ module Faraday
29
29
 
30
30
  def match(request_method, path, body)
31
31
  return false if !@stack.key?(request_method)
32
- stub = @stack[request_method].detect { |stub| stub.matches?(path, body) }
33
- @stack[request_method].delete stub
32
+ stack = @stack[request_method]
33
+ consumed = (@consumed[request_method] ||= [])
34
+
35
+ if stub = matches?(stack, path, body)
36
+ consumed << stack.delete(stub)
37
+ stub
38
+ else
39
+ matches?(consumed, path, body)
40
+ end
34
41
  end
35
42
 
36
43
  def get(path, &block)
@@ -53,10 +60,6 @@ module Faraday
53
60
  new_stub(:delete, path, &block)
54
61
  end
55
62
 
56
- def new_stub(request_method, path, body=nil, &block)
57
- (@stack[request_method] ||= []) << Stub.new(path, body, block)
58
- end
59
-
60
63
  # Raises an error if any of the stubbed calls have not been made.
61
64
  def verify_stubbed_calls
62
65
  failed_stubs = []
@@ -69,6 +72,16 @@ module Faraday
69
72
  end
70
73
  raise failed_stubs.join(" ") unless failed_stubs.size == 0
71
74
  end
75
+
76
+ protected
77
+
78
+ def new_stub(request_method, path, body=nil, &block)
79
+ (@stack[request_method] ||= []) << Stub.new(path, body, block)
80
+ end
81
+
82
+ def matches?(stack, path, body)
83
+ stack.detect { |stub| stub.matches?(path, body) }
84
+ end
72
85
  end
73
86
 
74
87
  class Stub < Struct.new(:path, :body, :block)
@@ -81,7 +94,7 @@ module Faraday
81
94
  end
82
95
  end
83
96
 
84
- def initialize app, stubs=nil, &block
97
+ def initialize(app, stubs=nil, &block)
85
98
  super(app)
86
99
  @stubs = stubs || Stubs.new
87
100
  configure(&block) if block
@@ -91,13 +104,8 @@ module Faraday
91
104
  yield stubs
92
105
  end
93
106
 
94
- def request_uri url
95
- (url.path != "" ? url.path : "/") +
96
- (url.query ? "?#{url.query}" : "")
97
- end
98
-
99
107
  def call(env)
100
- if stub = stubs.match(env[:method], request_uri(env[:url]), env[:body])
108
+ if stub = stubs.match(env[:method], Faraday::Utils.normalize_path(env[:url]), env[:body])
101
109
  status, headers, body = stub.block.call(env)
102
110
  env.update \
103
111
  :status => status,
@@ -108,6 +116,11 @@ module Faraday
108
116
  end
109
117
  @app.call(env)
110
118
  end
119
+
120
+ def create_multipart(env, params, boundary = nil)
121
+ stream = super
122
+ stream.read
123
+ end
111
124
  end
112
125
  end
113
126
  end
@@ -1,6 +1,6 @@
1
1
  module Faraday
2
- module Adapter
3
- class Typhoeus < Middleware
2
+ class Adapter
3
+ class Typhoeus < Faraday::Adapter
4
4
  self.supports_parallel_requests = true
5
5
 
6
6
  def self.setup_parallel_manager(options = {})
@@ -14,15 +14,18 @@ module Faraday
14
14
  end
15
15
 
16
16
  def call(env)
17
- process_body_for_request(env)
17
+ super
18
18
 
19
- hydra = env[:parallel_manager] || self.class.setup_parallel_manager
20
- req = ::Typhoeus::Request.new env[:url].to_s,
19
+ req = ::Typhoeus::Request.new env[:url].to_s,
21
20
  :method => env[:method],
22
21
  :body => env[:body],
23
22
  :headers => env[:request_headers],
24
23
  :disable_ssl_peer_verification => (env[:ssl][:verify] == false)
25
24
 
25
+ env_req = env[:request]
26
+ req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout]
27
+ req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout]
28
+
26
29
  req.on_complete do |resp|
27
30
  env.update \
28
31
  :status => resp.code,
@@ -31,6 +34,7 @@ module Faraday
31
34
  env[:response].finish(env)
32
35
  end
33
36
 
37
+ hydra = env[:parallel_manager] || self.class.setup_parallel_manager
34
38
  hydra.queue req
35
39
 
36
40
  if !env[:parallel_manager]
@@ -39,7 +43,7 @@ module Faraday
39
43
 
40
44
  @app.call env
41
45
  rescue Errno::ECONNREFUSED
42
- raise Error::ConnectionFailed, "connection refused"
46
+ raise Error::ConnectionFailed.new(Errno::ECONNREFUSED)
43
47
  end
44
48
 
45
49
  def in_parallel(options = {})
@@ -56,6 +60,12 @@ module Faraday
56
60
  map! { |h| h.split(/:\s+/,2) }. # split key and value
57
61
  map! { |(k, v)| [k.downcase, v] }.flatten!]
58
62
  end
63
+
64
+ # TODO: build in support for multipart streaming if typhoeus supports it.
65
+ def create_multipart(env, params, boundary = nil)
66
+ stream = super
67
+ stream.read
68
+ end
59
69
  end
60
70
  end
61
71
  end
@@ -14,7 +14,7 @@ module Faraday
14
14
  end
15
15
 
16
16
  def self.inner_app
17
- lambda do |env|
17
+ lambda do |env|
18
18
  env[:parallel_manager] ? env[:response] : env[:response].finish(env)
19
19
  end
20
20
  end
@@ -56,19 +56,19 @@ module Faraday
56
56
  end
57
57
 
58
58
  def request(key, *args, &block)
59
- use_symbol Faraday::Request, key, *args, &block
59
+ use_symbol(Faraday::Request, key, *args, &block)
60
60
  end
61
61
 
62
62
  def response(key, *args, &block)
63
- use_symbol Faraday::Response, key, *args, &block
63
+ use_symbol(Faraday::Response, key, *args, &block)
64
64
  end
65
65
 
66
66
  def adapter(key, *args, &block)
67
- use_symbol Faraday::Adapter, key, *args, &block
67
+ use_symbol(Faraday::Adapter, key, *args, &block)
68
68
  end
69
69
 
70
70
  def use_symbol(mod, key, *args, &block)
71
- use mod.lookup_module(key), *args, &block
71
+ use(mod.lookup_module(key), *args, &block)
72
72
  end
73
73
 
74
74
  def ==(other)
@@ -76,7 +76,7 @@ module Faraday
76
76
  end
77
77
 
78
78
  def dup
79
- self.class.new @handlers.dup
79
+ self.class.new(@handlers.dup)
80
80
  end
81
81
  end
82
82
  end