add multipart support

This commit is contained in:
rick 2010-09-07 15:12:18 -07:00
parent e5a9bdcddb
commit 12b519aedc
9 changed files with 111 additions and 12 deletions

View File

@ -49,13 +49,16 @@ module Faraday
extend AutoloadHelper
autoload_all 'faraday',
:Adapter => 'adapter',
:Connection => 'connection',
:Middleware => 'middleware',
:Builder => 'builder',
:Request => 'request',
:Response => 'response',
:Error => 'error'
:Adapter => 'adapter',
:Connection => 'connection',
:Middleware => 'middleware',
:Builder => 'builder',
:Request => 'request',
:Response => 'response',
:CompositeReadIO => 'upload_io',
:UploadIO => 'upload_io',
:Parts => 'upload_io',
:Error => 'error'
end
# not pulling in active-support JUST for this method.

View File

@ -1,7 +1,9 @@
module Faraday
class Adapter < Middleware
FORM_TYPE = 'application/x-www-form-urlencoded'.freeze
MULTIPART_TYPE = 'multipart/form-data'.freeze
FORM_TYPE = 'application/x-www-form-urlencoded'.freeze
MULTIPART_TYPE = 'multipart/form-data'.freeze
CONTENT_TYPE = 'Content-Type'.freeze
DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze
extend AutoloadHelper
autoload_all 'faraday/adapter',
@ -36,9 +38,24 @@ module Faraday
# environment for you.
def process_body_for_request(env, body = env[:body], headers = env[:request_headers])
return if body.nil? || body.empty? || !body.respond_to?(:each_key)
type = headers['Content-Type'].to_s
headers['Content-Type'] ||= FORM_TYPE
env[:body] = create_form_params(body)
if body.values.any? { |v| v.respond_to?(:content_type) }
env[:request] ||= {}
env[:request][:boundary] ||= DEFAULT_BOUNDARY
headers[CONTENT_TYPE] = MULTIPART_TYPE + ";boundary=#{env[:request][:boundary]}"
env[:body] = create_multipart(env, body)
else
type = headers[CONTENT_TYPE]
headers[CONTENT_TYPE] = FORM_TYPE if type.nil? || type.empty?
env[:body] = create_form_params(body)
end
end
def create_multipart(env, params, boundary = nil)
boundary ||= env[:request][:boundary]
parts = params.map {|k,v| Faraday::Parts::Part.new(boundary, k, v)}
parts << Faraday::Parts::EpiloguePart.new(boundary)
env[:request_headers]['Content-Length'] = parts.inject(0) {|sum,i| sum + i.length }
Faraday::CompositeReadIO.new(*parts.map{|p| p.to_io })
end
def create_form_params(params, base = nil)

View File

@ -20,6 +20,7 @@ module Faraday
def call(env)
super
full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
body = env[:body].respond_to?(:read) ? env[:body]
@session.__send__(env[:method], full_path, env[:body], env[:request_headers])
resp = @session.response
env.update \
@ -28,6 +29,12 @@ module Faraday
:body => resp.body
@app.call env
end
# TODO: build in support for multipart streaming if action dispatch supports it.
def create_multipart(env, params, boundary = nil)
stream = super
stream.read
end
end
end
end

View File

@ -54,6 +54,12 @@ module Faraday
Net::HTTP
end
end
# TODO: build in support for multipart streaming
def create_multipart(env, params, boundary = nil)
stream = super
stream.read
end
end
end
end

View File

@ -28,6 +28,12 @@ module Faraday
rescue Errno::ECONNREFUSED
raise Error::ConnectionFailed, "connection refused"
end
# TODO: build in support for multipart streaming if patron supports it.
def create_multipart(env, params, boundary = nil)
stream = super
stream.read
end
end
end
end

View File

@ -112,6 +112,11 @@ module Faraday
end
@app.call(env)
end
def create_multipart(env, params, boundary = nil)
stream = super
stream.read
end
end
end
end

View File

@ -60,6 +60,12 @@ module Faraday
map! { |h| h.split(/:\s+/,2) }. # split key and value
map! { |(k, v)| [k.downcase, v] }.flatten!]
end
# TODO: build in support for multipart streaming if typhoeus supports it.
def create_multipart(env, params, boundary = nil)
stream = super
stream.read
end
end
end
end

14
lib/faraday/upload_io.rb Normal file
View File

@ -0,0 +1,14 @@
begin
require 'composite_io'
require 'parts'
require 'stringio'
rescue LoadError
puts "Install the multipart-post gem."
raise
end
module Faraday
CompositeReadIO = ::CompositeReadIO
UploadIO = ::UploadIO
Parts = ::Parts
end

35
test/multipart_test.rb Normal file
View File

@ -0,0 +1,35 @@
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
class MultipartTest < Faraday::TestCase
def setup
@app = Faraday::Adapter.new nil
@env = {:request_headers => {}}
end
def test_processes_nested_body
@env[:body] = {:a => 1, :b => Faraday::UploadIO.new(__FILE__, 'text/x-ruby')}
@app.process_body_for_request @env
assert_kind_of CompositeReadIO, @env[:body]
assert_equal "%s;boundary=%s" %
[Faraday::Adapter::MULTIPART_TYPE, Faraday::Adapter::DEFAULT_BOUNDARY],
@env[:request_headers]['Content-Type']
end
def test_processes_nil_body
@env[:body] = nil
@app.process_body_for_request @env
assert_nil @env[:body]
end
def test_processes_empty_body
@env[:body] = ''
@app.process_body_for_request @env
assert_equal '', @env[:body]
end
def test_processes_string_body
@env[:body] = 'abc'
@app.process_body_for_request @env
assert_equal 'abc', @env[:body]
end
end