среда, 21 мая 2008 г.

Ruby: file upload

В ruby есть библиотека для работы с http протоколом 'net/http'. Но по неизвестным причинам она не умеет аплоадить файлы на сервер. Эту функциональность приходиться реализовывать самостоятельно. Для этого необходимо сформировать правильный POST запрос, формат которого подробно описан в rfc1867.

Для тех кому лень читать - запрос выглядит примерно так:
Content-type: multipart/form-data, boundary=AaB03x

--AaB03x
content-disposition: form-data; name="parameter_name"

Parameter value
--AaB03x
content-disposition: form-data; name="name"; filename="file_name"
Content-Type: text/plain (зависит от типа файла)

... содержание файла ...
--AaB03x--

Запрос не сложный, реализация тоже.
require 'net/http'

class MultipartPostRequest
#
# url = URI.parse('http://test.com/path')
# post = MultipartPostRequest.create(url,
# { :file => File.open(filename), :filename => filename })
# res = Net::HTTP.start(url.host, url.port) do |http|
# http.request(post)
# end
#
def self.create(uri, pars)
post = Net::HTTP::Post.new(uri.path)
boundary = (rand*1000000000).to_i.to_s
post.set_content_type("multipart/form-data", {:boundary => boundary})

body = ""
pars.each do |key, value|
body << "--#{boundary}\r\n"
append_post_parameter(body, key, value)
end
body << "--#{boundary}--"

post.content_length = body.length
post.body = body
return post
end

def self.append_post_parameter(body, key, value)
if value.class == File
body << "Content-disposition: form-data; name=\"#{key}\";\
filename=\"#{File.basename(value.path)}\"\r\n"
body << "Content-type: application\r\n"
body << "Content-Transfer-Encoding: binary\r\n\r\n"
body << value.binmode.read
body << "\r\n"
else
body << "Content-disposition: form-data; name=\"#{key}\"\r\n\r\n"
body << "#{value}\r\n"
end
end
end

Пример использования:

uri = URI.parse('http://test.com/path')
post = MultipartPostRequest.create(uri,
{ :file => File.open(filename), :another => "parameter" })
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(post)
end

Комментариев нет: