class Net::HTTP::Post

Public Instance Methods

set_multipart_data(files_params, other_params={}, boundary1="paranguaricutirimirruaru0xdeadbeef", boundary2="paranguaricutirimirruaru0x20132") click to toggle source

Similar to Net::HTTP::Post#set_form_data (in Ruby's stardard library), but set up file upload parameters using the appropriate HTTP/HTML Forms multipart format.

Arguments

files_params

A hash of file upload parameters. The keys are parameter names, and the values are Net::HTTP::FileForPost instances. See that class documentation for more info about how POST file upload works.

other_params

A hash of {key => value} pairs for the regular POST parameters, just like in set_form_data. Don't mix set_form_data and #set_multipart_data; they'll overwrite each other's work.

boundary1, boundary2

A couple of strings which doesn't occur in your files. Boundary2 is only needed if you're using the multipart/mixed technique. The defaults should be OK for most cases.

Examples

Simplest case (single-parameter single-file), complete:

require 'net/http'
require 'rubygems'
require 'multipart'

req = Net::HTTP::Post.new('/scripts/upload.rb')
req.basic_auth('jack', 'inflamed sense of rejection')

file = Net::HTTP::FileForPost.new('/tmp/yourlife.txt', 'text/plain')
req.set_multipart_data({:poem => file},

                       {:author => 'jack',
                         :user_agent => 'soapfactory'})

res = Net::HTTP.new(url.host, url.port).start do |http|
  http.request(req)
end

Convoluted example:

pic1 = Net::HTTP::FileForPost.new('pic1.jpeg', 'image/jpeg')
pic2 = Net::HTTP::FileForPost.new(pic2_io, 'image/jpeg')
pic3 = Net::HTTP::FileForPost.new('pic3.png', 'image/png')
pic1_t = Net::HTTP::FileForPost.new('pic1_thumb.jpeg', 'image/jpeg')
pic2_t = Net::HTTP::FileForPost.new(pic2_t_io, 'image/jpeg')
desc = Net::HTTP::FileForPost.new('desc.html', 'text/html',
                                   'index.html') # remote fname

req.set_multipart_data({:gallery_description => des,
                        :pictures => [pic1, pic2, pic3],
                        :thumbnails => [pic1_t, pic2_t]},

                       {:gallery_name => 'mygallery',
                        :encoding => 'utf-8'})
# File multipart.rb, line 143
def set_multipart_data(files_params,
                       other_params={},
                       boundary1="paranguaricutirimirruaru0xdeadbeef",
                       boundary2="paranguaricutirimirruaru0x20132")

  self.content_type = "multipart/form-data; boundary=\"#{boundary1}\""

  tmp = StringIO.new('r+b')

  # let's do the easy ones first
  other_params.each do |key,val|
    tmp.write "--#{boundary1}\r\n"
    tmp.write "content-disposition: form-data; name=\"#{key}\"\r\n"
    tmp.write "\r\n"
    tmp.write "#{val}\r\n"
  end

  # now handle the files...
  files_params.each do |name, file|
    tmp.write "\r\n--#{boundary1}\r\n"

    # no \r\n
    tmp.write "content-disposition: form-data; name=\"#{name}\""

    if not file.is_a? Enumerable
      # single-file multipart is different

      if file.filename
        # right in content-dispo line
        tmp.write "; filename=\"#{file.filename}\"\r\n"
      else
        tmp.write "\r\n"
      end

      tmp.write "Content-Type: #{file.mimetype}\r\n"
      tmp.write "Content-Transfer-Encoding: binary\r\n"
      tmp.write "\r\n"
      tmp.write(file.read())
      file.maybeclose
    else
      # multiple-file parameter (multipart/mixed)
      tmp.write "\r\n"
      tmp.write "Content-Type: multipart/mixed;"
      tmp.write " boundary=\"#{boundary2}\"\r\n"

      file.each do |f|
        tmp.write "\r\n--#{boundary2}\r\n"

        tmp.write "Content-disposition: attachment"
        if f.filename
          tmp.write "; filename=\"#{f.filename}\"\r\n"
        else
          tmp.write "\r\n"
        end

        tmp.write "Content-Type: #{f.mimetype}\r\n"
        tmp.write "Content-Transfer-Encoding: binary\r\n"
        tmp.write "\r\n"
        tmp.write(f.read())
        f.maybeclose
      end
      tmp.write "\r\n--#{boundary2}--\r\n"
    end
  end
  tmp.write "--#{boundary1}--\r\n"

  
  tmp.flush
  self.content_length = tmp.size
  self.body_stream = tmp
  self.body_stream.seek(0)
  nil
end