require 'net/https' require 'uri' class App def initialize argv @method = :put @postparam = 'uploaded' @capath = OpenSSL::X509::DEFAULT_CERT_DIR @cafile = nil @ctype = 'application/octet-stream' @gzip = false @verify = true @user = @pass = nil @endpoint = nil @files = [] optparse argv end def optparse argv for arg in argv case arg when /^--?h/ then help when /^--?v/ then $VERBOSE = true when /^--unsafe$/ then @verify = false when /^--capath=/ then @capath = $' when /^--cafile=/ then @cafile = $' when /^--ctype=/ then @ctype = $' when /^--user=(\w+)$/ then @user = $1 when /^--pass=/ then @pass = $' when /^--gzip$/ then @gzip = true when /^--post$/ then @method = :post when /^--post=(\w+)$/ then @postparam = $1 @method = :post else if @endpoint.nil? then @endpoint = arg else @files.push arg end end end help if @files.empty? end def help print < @ctype } data = File.read(file) if @gzip require 'stringio' require 'zlib' StringIO.open('', 'r+') {|sio| Zlib::GzipWriter.wrap(sio) {|gz| gz.orig_name = file gz.write data } data = sio.string } header['content-encoding'] = 'gzip' end #hack begin require 'digest/md5' header['content-md5'] = [Digest::MD5.digest(data)].pack('m').strip rescue LoadError $stderr.puts "MD5 cannot be computed" end puts uri2 if $VERBOSE resp = http.put(uri2.path, data, header) if '401' === resp.code then authorize(header, resp) resp = http.put(uri2.path, data, header) end showresp(resp, uri2) end def post http, uri, file buf = File.read(file) boundary = "----Boundary0000aaaa" loop { break unless buf.index(boundary) boundary = boundary.succ } sfile = File.basename(file).gsub(/[^-.+\w]/, '') data = [ "--#{boundary}\r\n", "Content-Disposition: form-data; name=\"#{@postparam}\";", " filename=\"#{sfile}\"\r\n", "Content-Type: #{@ctype}\r\n", "\r\n", buf, "\r\n--#{boundary}--\r\n" ].join header = { 'content-type' => "multipart/form-data; boundary=#{boundary}" } resp = http.post(uri.path, data, header) if '401' === resp.code then authorize(header, resp) resp = http.post(uri.path, data, header) end showresp(resp, sfile) end def run u = URI.parse(@endpoint) h = Net::HTTP.new(u.host, u.port) if 'https' == u.scheme h.use_ssl = true h.ca_path = @capath h.ca_file = @cafile if @cafile h.verify_mode = if @verify then OpenSSL::SSL::VERIFY_PEER else OpenSSL::SSL::VERIFY_NONE end end h.start {|http| for file in @files # calls put() or post() self.send(@method, http, u, file) end } end end App.new(ARGV).run