def __init__(self, data):
        self.data = data
        self.boundary = 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 'voice' in data:
            self.input_name = 'voice'
            self.input_file = data.pop('voice')

        if isinstance(self.input_file, file):
            self.input_file_content = self.input_file.read()
            self.filename = os.path.basename(self.input_file.name)
            self.mimetype = mimetypes.guess_type(self.filename)[0] or \
                DEFAULT_MIME_TYPE

        if 'http' in self.input_file:
            self.input_file_content = urlopen(self.input_file).read()
            self.mimetype = InputFile.is_image(self.input_file_content)
            self.filename = self.mimetype.replace('/', '.')
Exemple #2
0
    def __init__(self, data):
        self.data = data
        self.boundary = choose_boundary()

        for t in FILE_TYPES:
            if t in data:
                self.input_name = t
                self.input_file = data.pop(t)
                break
        else:
            raise TelegramError('Unknown inputfile type')

        if hasattr(self.input_file, 'read'):
            self.filename = None
            self.input_file_content = self.input_file.read()
            if 'filename' in data:
                self.filename = self.data.pop('filename')
            elif hasattr(self.input_file, 'name'):
                # on py2.7, pylint fails to understand this properly
                # pylint: disable=E1101
                self.filename = os.path.basename(self.input_file.name)

            try:
                self.mimetype = self.is_image(self.input_file_content)
                if not self.filename or '.' not in self.filename:
                    self.filename = self.mimetype.replace('/', '.')
            except TelegramError:
                if self.filename:
                    self.mimetype = mimetypes.guess_type(
                        self.filename)[0] or DEFAULT_MIME_TYPE
                else:
                    self.mimetype = DEFAULT_MIME_TYPE
Exemple #3
0
    def multipart_encode(self, vars, files, boundary=None, buffer=None):
        if boundary is None:
            if isPython3:
                boundary = mimetools._make_boundary()
                boundary = boundary.replace("=", "-")
            else:
                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:
            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
            fd.seek(0)
            if isPython3:
                buffer = buffer.encode() + b'\r\n' + fd.read() + b'\r\n'
            else:
                buffer += '\r\n' + fd.read() + '\r\n'

        if isPython3:
            buffer += b'--%b--\r\n\r\n' % boundary.encode()
        else:
            buffer += '--%s--\r\n\r\n' % boundary
        return boundary, buffer
Exemple #4
0
    def __init__(self,
                 data):
        self.data = data
        self.boundary = 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 'sticker' in data:
            self.input_name = 'sticker'
            self.input_file = data.pop('sticker')
        if 'video' in data:
            self.input_name = 'video'
            self.input_file = data.pop('video')
        if 'voice' in data:
            self.input_name = 'voice'
            self.input_file = data.pop('voice')
        if 'certificate' in data:
            self.input_name = 'certificate'
            self.input_file = data.pop('certificate')

        if str(self.input_file).startswith('http'):
            from_url = True
            self.input_file = urlopen(self.input_file)
        else:
            from_url = False

        if hasattr(self.input_file, 'read') or from_url:
            self.filename = None
            self.input_file_content = self.input_file.read()
            if 'filename' in data:
                self.filename = self.data.pop('filename')
            elif hasattr(self.input_file, 'name'):
                # on py2.7, pylint fails to understand this properly
                # pylint: disable=E1101
                self.filename = os.path.basename(self.input_file.name)
            elif from_url:
                self.filename = os.path.basename(self.input_file.url) \
                    .split('?')[0].split('&')[0]

            try:
                self.mimetype = InputFile.is_image(self.input_file_content)
                if not self.filename or '.' not in self.filename:
                    self.filename = self.mimetype.replace('/', '.')
            except TelegramError:
                self.mimetype = mimetypes.guess_type(self.filename)[0] or \
                                DEFAULT_MIME_TYPE
Exemple #5
0
    def post_files(self, url, json_data, files=None):
        if not files or not isinstance(files, dict):
            raise ValueError('One or more files is required. Files should be '
                             'passed as a dictionary of filename: file-like-'
                             'object.')
        boundary = choose_boundary()
        form_files = []
        for i, (filename, file_obj) in enumerate(files.items()):
            try:
                data = file_obj.read()
            except AttributeError:
                data = bytes(file_obj)
            mimetype = mimetypes.guess_type(filename)[0]
            form_files.append((
                'file_%s' % i,
                filename,
                mimetype or 'application/octet-stream',
                data))

        part_boundary = '--' + boundary
        parts = [
            part_boundary,
            'Content-Disposition: form-data; name="data"',
            '',
            json.dumps(json_data)]
        for field_name, filename, mimetype, data in form_files:
            parts.extend((
                part_boundary,
                'Content-Disposition: file; name="%s"; filename="%s"' % (
                    field_name, filename),
                'Content-Type: %s' % mimetype,
                '',
                data))
        parts.append('--' + boundary + '--')
        parts.append('')

        headers = {'Content-Type': 'multipart/form-data; boundary=%s' %
                   boundary}
        if self.key:
            headers['key'] = self.key

        data = '\r\n'.join(parts)
        if not isinstance(data, bytes):
            data = data.encode('utf-8')

        request = Request(self.get_full_url(url), data=data, headers=headers)
        return json.loads(urlopen(request).read())
Exemple #6
0
    def __init__(self, data):
        self.data = data
        self.boundary = choose_boundary()

        if 'audio' in data:
            self.input_name = 'audio'
            self.input_file = data.pop('audio')
        elif 'document' in data:
            self.input_name = 'document'
            self.input_file = data.pop('document')
        elif 'photo' in data:
            self.input_name = 'photo'
            self.input_file = data.pop('photo')
        elif 'sticker' in data:
            self.input_name = 'sticker'
            self.input_file = data.pop('sticker')
        elif 'video' in data:
            self.input_name = 'video'
            self.input_file = data.pop('video')
        elif 'voice' in data:
            self.input_name = 'voice'
            self.input_file = data.pop('voice')
        elif 'certificate' in data:
            self.input_name = 'certificate'
            self.input_file = data.pop('certificate')
        else:
            raise TelegramError('Unknown inputfile type')

        if hasattr(self.input_file, 'read'):
            self.filename = None
            self.input_file_content = self.input_file.read()
            if 'filename' in data:
                self.filename = self.data.pop('filename')
            elif hasattr(self.input_file, 'name'):
                # on py2.7, pylint fails to understand this properly
                # pylint: disable=E1101
                self.filename = os.path.basename(self.input_file.name)

            try:
                self.mimetype = self.is_image(self.input_file_content)
                if not self.filename or '.' not in self.filename:
                    self.filename = self.mimetype.replace('/', '.')
            except TelegramError:
                self.mimetype = mimetypes.guess_type(
                    self.filename)[0] or DEFAULT_MIME_TYPE
    def __init__(self, data):
        self.data = data
        self.boundary = choose_boundary()

        for t in FILE_TYPES:
            if t in data:
                self.input_name = t
                self.input_file = data.pop(t)
                break
        else:
            raise TelegramError('Unknown inputfile type')

        if hasattr(self.input_file, 'read'):
            self.filename = None
            self.input_file_content = self.input_file.read()
            if 'filename' in data:
                self.filename = self.data.pop('filename')
            elif (hasattr(self.input_file, 'name') and
                  not isinstance(self.input_file.name, int) and  # py3
                  self.input_file.name != '<fdopen>'):  # py2
                # on py2.7, pylint fails to understand this properly
                # pylint: disable=E1101
                self.filename = os.path.basename(self.input_file.name)

            try:
                self.mimetype = self.is_image(self.input_file_content)
                if not self.filename or '.' not in self.filename:
                    self.filename = self.mimetype.replace('/', '.')
            except TelegramError:
                if self.filename:
                    self.mimetype = mimetypes.guess_type(
                        self.filename)[0] or DEFAULT_MIME_TYPE
                else:
                    self.mimetype = DEFAULT_MIME_TYPE

        if sys.version_info < (3,):
            if isinstance(self.filename, unicode):  # flake8: noqa  pylint: disable=E0602
                self.filename = self.filename.encode('utf-8', 'replace')
Exemple #8
0
 def __init__(self):
     self.form_fields = []
     self.files = []
     self.boundary = choose_boundary()
     return
 def multipart_encode(self, v_vars, files, boundary=None, buf=None):
     if six.PY3:
         if boundary is None:
             boundary = choose_boundary()
         if buf is None:
             buf = io.BytesIO()
         for(key, value) in v_vars:
             buf.write(b'--' + boundary.encode("utf-8") + b'\r\n')
             buf.write(
                 b'Content-Disposition: form-data; name="' +
                 key.encode("utf-8") +
                 b'"'
             )
             buf.write(b'\r\n\r\n' + value.encode("utf-8") + b'\r\n')
         for(key, fd) in files:
             try:
                 filename = fd.name.split('/')[-1]
             except AttributeError:
                 # Spoof a file name if the object doesn't have one.
                 # This is designed to catch when the user submits
                 # a StringIO object
                 filename = 'temp.pdf'
             contenttype = mimetypes.guess_type(filename)[0] or \
                 b'application/octet-stream'
             buf.write(b'--' + boundary.encode("utf-8") + b'\r\n')
             buf.write(
                 b'Content-Disposition: form-data; ' +
                 b'name="' + key.encode("utf-8") + b'"; ' +
                 b'filename="' + filename.encode("utf-8") + b'"\r\n'
             )
             buf.write(
                 b'Content-Type: ' +
                 contenttype.encode("utf-8") +
                 b'\r\n'
             )
             fd.seek(0)
             buf.write(
                 b'\r\n' + fd.read() + b'\r\n'
             )
         buf.write(b'--')
         buf.write(boundary.encode("utf-8"))
         buf.write(b'--\r\n\r\n')
         buf = buf.getvalue()
         return boundary, buf
     else:
         if boundary is None:
             boundary = choose_boundary()
         if buf is None:
             buf = io.StringIO()
         for(key, value) in v_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:
             try:
                 filename = fd.name.split('/')[-1]
             except AttributeError:
                 # Spoof a file name if the object doesn't have one.
                 # This is designed to catch when the user submits
                 # a StringIO object
                 filename = 'temp.pdf'
             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)
             # buffer += 'Content-Length: %s\r\n' % file_size
             fd.seek(0)
             buf.write('\r\n' + fd.read() + '\r\n')
         buf.write('--' + boundary + '--\r\n\r\n')
         buf = buf.getvalue()
         return boundary, buf
Exemple #10
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
    
    # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
    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:
                # Return a single-part response.
                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:
                # Return a multipart/byteranges response.
                response.status = "206 Partial Content"
                try:
                    # Python 3
                    from email.generator import _make_boundary as choose_boundary
                except ImportError:
                    # Python 2
                    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:
                    # Delete Content-Length header so finalize() recalcs it.
                    del response.headers["Content-Length"]
                
                def file_ranges():
                    # Apache compatibility:
                    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")
                    # Final boundary
                    yield ntob("--" + boundary + "--", 'ascii')
                    
                    # Apache compatibility:
                    yield ntob("\r\n")
                response.body = file_ranges()
            return response.body
        else:
            if debug:
                cherrypy.log('No byteranges requested', 'TOOLS.STATIC')
    
    # Set Content-Length and use an iterable (file object)
    #   this way CP won't load the whole file in memory
    response.headers['Content-Length'] = content_length
    response.body = fileobj
    return response.body
Exemple #11
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 = int(DateTime(date).timeTime())
                    except:
                        mod_since = None
                    if mod_since is not None:
                        if self.aq_parent._p_mtime:
                            last_mod = int(self.aq_parent._p_mtime)
                        else:
                            last_mod = int(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.aq_parent._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.aq_parent._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, StringType):
                        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.aq_parent._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, StringType):
                            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