August 31, 2007

OMG Multipart file uploads in Ruby are ugly

Maybe my google-fu just failed me, but this is the best I can dig up for using Ruby’s Net::HTTP to make a multipart post for uploading files to a webapp. Eww…

require 'open-uri'
require 'net/http'
require 'cgi'

def post( query, headers={} )
   Net::HTTP.start( "www.yourserver.com", 80 ) { |h|
     h.post( "/cgi-bin/your_script.rb", query, headers )
   }
end

class Param
   attr_accessor :k, :v
   def initialize( k, v )
     @k = k
     @v = v
   end

   def to_multipart
     return "Content-Disposition: form-data; 
name=\"#{CGI::escape(k)}\"\r\n\r\n#{v}\r\n"
   end
end

class FileParam
   attr_accessor :k, :filename, :content
   def initialize( k, filename, content )
     @k = k
     @filename = filename
     @content = content
   end

   def to_multipart
     return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"; 
filename=\"#{filename}\"\r\n" +
     	   "Content-Transfer-Encoding: binary\r\n" +
            "Content-Type: #{Web::Mime.get_mime_type(filename)}\r\n\r\n" 
+ content + "\r\n"

   end
end

filename = 'some_image.jpg'
content = open( 'some_image.jpg' ) { |f|
   f.read
}

boundary = "7d21f962d00c4"
params = [ Param.new(     "action",    "Upload"          ),
     	           FileParam.new( "upload",    filename, content ) ]

query = params.collect { |p|
     "--" + boundary + "\r\n" + p.to_multipart
   }.join("") + "--" + boundary + "--"

resp, data = post( query, "Content-type" => "multipart/form-data, 
boundary=" + boundary + " " )