べるべる研究日誌

なんでもやる系エンジニアの日々

ファイルアップロード

Rubyからファイルをアップロードする方法を探してみたけど見つからない。受けるサーバー側のコードはcgi.rbにあるのだけど。いろいろやってみたけど、普通にNet::HTTP::Postでセットするだけではmultipart/form-dataが送れないっぽい。できればnet/httpだけでやりたい...ということで、頭を悩ませつつWeb上のコードとRFCを参考にベタベタ書く事にした。

Net::HTTP::Postで作ったリクエストに対して、content-typeをmultipart/form-dataで設定。 body部分を生成してセット。それを通常通り送る方法でいけました。API用に作ったので、user/passとhttpオブジェクトが分離しています。

@username = "user"
@password = "pass"
@http = Net::HTTP.start("somedomain.com",80)

def file_upload(path,options = Array.new)	
  case File.extname(path)
    when ".jpg"	then mime = "image/jpeg"	
    when ".gif"	then mime = "image/gif"	
    when ".png"	then mime = "image/png"	
  end
  mime = options['mime'] unless options['mime'].nil?

  boundary = "AaB03x"
  data = "--#{boundary}\r\n" +		
	"content-disposition: form-data; name=\"file\"; filename=\"#{File.basename(path)} \"\r\n" +
	"content-type: #{mime}\r\n" +
	"content-transfer-encoding: binary\r\n\r\n" +
	File.open(path).read + "\r\n"

  options.each{|k,v|
    data += "--#{boundary}\r\n" +
      "content-disposition: form-data; name=\"#{k}\"\r\n\r\n#{URI.encode(v)}\r\n"
  }					
  data += "--#{boundary}--\r\n"

  req = Net::HTTP::Post.new("/file_upload.cgi")
  req['content-type'] = "multipart/form-data; boundary=#{boundary}"
  # req.basic_auth(@username,@password)
  req.body = data
  res = @http.request(req)
  res.body
end

RFC2388
[ruby-dev:28470] cgi.rbを使ったファイルアップロードについて