示例#1
0
文件: static.py 项目: Ladida1/MAS
                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)
                        gen = file_generator_limited(fileobj, stop - start)
                        for chunk in gen:
                            yield chunk
                        yield ntob("\r\n")
                    # Final boundary
                    yield ntob("--" + boundary + "--", 'ascii')

                    # Apache compatibility:
                    yield ntob("\r\n")
示例#2
0
文件: static.py 项目: coady/cherrypy
                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)
                        gen = file_generator_limited(fileobj, stop - start)
                        for chunk in gen:
                            yield chunk
                        yield ntob('\r\n')
                    # Final boundary
                    yield ntob('--' + boundary + '--', 'ascii')

                    # Apache compatibility:
                    yield ntob('\r\n')
示例#3
0
def _serve_fileobj(fileobj, content_type, content_length, debug = False):
    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
示例#4
0
def _serve_fileobj(fileobj, content_type, content_length, debug = False):
    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
示例#5
0
    def file_ranges():
        for start, stop in r:
            yield to_unicode("--" + boundary)
            yield to_unicode("\r\nContent-type: {0}".format(content_type))
            yield to_unicode(
                "\r\nContent-range: bytes {0}-{1}/{2}\r\n\r\n".format(
                    start, stop - 1, content_length))
            fileobj.seek(start)

            gen = file_generator_limited(fileobj, stop - start)
            for chunk in gen:
                yield chunk
            yield to_unicode("\r\n")

        yield to_unicode("--" + boundary + "--")
示例#6
0
                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')
示例#7
0
文件: static.py 项目: joaoAvno/Sonar
                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)
                        for chunk in file_generator_limited(bodyfile, stop - start):
                            yield chunk
                        yield "\r\n"
                    # Final boundary
                    yield "--" + boundary + "--"

                    # Apache compatibility:
                    yield "\r\n"
示例#8
0
    def file_ranges():
        for start, stop in r:
            yield to_unicode("--" + boundary)
            yield to_unicode("\r\nContent-type: {0}".format(content_type))
            yield to_unicode(
                "\r\nContent-range: bytes {0}-{1}/{2}\r\n\r\n".format(
                    start, stop - 1, content_length
                )
            )
            fileobj.seek(start)

            gen = file_generator_limited(fileobj, stop - start)
            for chunk in gen:
                yield chunk
            yield to_unicode("\r\n")

        yield to_unicode("--" + boundary + "--")
示例#9
0
文件: static.py 项目: Reve/eve
                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")
示例#10
0
                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)
                        for chunk in file_generator_limited(
                                bodyfile, stop - start):
                            yield chunk
                        yield "\r\n"
                    # Final boundary
                    yield "--" + boundary + "--"

                    # Apache compatibility:
                    yield "\r\n"
示例#11
0
 def file_ranges():
     # Apache compatibility:
     yield "\r\n"
     
     for start, stop in r:
         if debug:
             cherrypy.log('Multipart; start: %r, stop: %r' % (start, stop),
                          'TOOLS.STATIC')
         yield "--" + boundary
         yield "\r\nContent-type: %s" % content_type
         yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n"
                % (start, stop - 1, content_length))
         fileobj.seek(start)
         for chunk in file_generator_limited(fileobj, stop-start):
             yield chunk
         yield "\r\n"
     # Final boundary
     yield "--" + boundary + "--"
     
     # Apache compatibility:
     yield "\r\n"
示例#12
0
文件: static.py 项目: Ladida1/MAS
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 make_boundary
                except ImportError:
                    # Python 2
                    from mimetools import choose_boundary as make_boundary
                boundary = make_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)
                        gen = file_generator_limited(fileobj, stop - start)
                        for chunk in gen:
                            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
示例#13
0
文件: static.py 项目: joaoAvno/Sonar
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 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.
    """

    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]
                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
                bodyfile.seek(start)
                response.body = file_generator_limited(bodyfile, 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 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)
                        for chunk in file_generator_limited(bodyfile, 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 = bodyfile
    else:
        response.headers["Content-Length"] = c_len
        response.body = bodyfile
    return response.body
示例#14
0
def serve_fileobj(fileobj, headers, content_length):
    status_code = 200
    headers["Accept-Ranges"] = "bytes"

    r = httputil.get_ranges(headers.get('Range'), content_length)

    if r == []:
        headers['Content-Range'] = "bytes */{0}".format(content_length)
        message = "Invalid Range (first-byte-pos greater than Content-Length)"
        raise RequestedRangeNotSatisfiable(message)

    if not r:
        headers['Content-Length'] = content_length
        return fileobj, headers, status_code

    # Return a multipart/byteranges response.
    status_code = 206

    if len(r) == 1:
        # Return a single-part response.
        start, stop = r[0]
        if stop > content_length:
            stop = content_length
        r_len = stop - start

        headers['Content-Range'] = "bytes {0}-{1}/{2}".format(
            start, stop - 1, content_length
        )
        headers['Content-Length'] = r_len
        fileobj.seek(start)
        body = file_generator_limited(fileobj, r_len)
        return body, headers, status_code

    try:
        # Python 3
        from email.generator import _make_boundary as make_boundary
    except ImportError:
        # Python 2
        from mimetools import choose_boundary as make_boundary

    boundary = make_boundary()
    content_type = "multipart/byteranges; boundary={0}".format(boundary)
    headers['Content-Type'] = content_type
    if "Content-Length" in headers:
        del headers["Content-Length"]

    def file_ranges():
        for start, stop in r:
            yield to_unicode("--" + boundary)
            yield to_unicode("\r\nContent-type: {0}".format(content_type))
            yield to_unicode(
                "\r\nContent-range: bytes {0}-{1}/{2}\r\n\r\n".format(
                    start, stop - 1, content_length
                )
            )
            fileobj.seek(start)

            gen = file_generator_limited(fileobj, stop - start)
            for chunk in gen:
                yield chunk
            yield to_unicode("\r\n")

        yield to_unicode("--" + boundary + "--")

    body = file_ranges()
    return body, headers, status_code
示例#15
0
文件: static.py 项目: Trixter69/XDM
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
示例#16
0
文件: static.py 项目: coady/cherrypy
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'
                boundary = make_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)
                        gen = file_generator_limited(fileobj, stop - start)
                        for chunk in gen:
                            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
示例#17
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 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.
    """

    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.staticdir, you can make your relative
    # paths become absolute by supplying a value for "tools.staticdir.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]
                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
                bodyfile.seek(start)
                response.body = file_generator_limited(bodyfile, 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 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)
                        for chunk in file_generator_limited(
                                bodyfile, stop - start):
                            yield chunk
                        yield "\r\n"
                    # Final boundary
                    yield "--" + boundary + "--"

                    # Apache compatibility:
                    yield "\r\n"

                response.body = file_ranges()
            return response.body

    response.headers['Content-Length'] = c_len
    response.body = bodyfile
    return response.body
示例#18
0
文件: static.py 项目: Reve/eve
def _serve_fileobj(fileobj, content_type, content_length, debug=False):
    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
示例#19
0
def serve_fileobj(fileobj, headers, content_length):
    status_code = 200
    headers["Accept-Ranges"] = "bytes"

    r = httputil.get_ranges(headers.get('Range'), content_length)

    if r == []:
        headers['Content-Range'] = "bytes */{0}".format(content_length)
        message = "Invalid Range (first-byte-pos greater than Content-Length)"
        raise RequestedRangeNotSatisfiable(message)

    if not r:
        headers['Content-Length'] = content_length
        return fileobj, headers, status_code

    # Return a multipart/byteranges response.
    status_code = 206

    if len(r) == 1:
        # Return a single-part response.
        start, stop = r[0]
        if stop > content_length:
            stop = content_length
        r_len = stop - start

        headers['Content-Range'] = "bytes {0}-{1}/{2}".format(
            start, stop - 1, content_length)
        headers['Content-Length'] = r_len
        fileobj.seek(start)
        body = file_generator_limited(fileobj, r_len)
        return body, headers, status_code

    try:
        # Python 3
        from email.generator import _make_boundary as make_boundary
    except ImportError:
        # Python 2
        from mimetools import choose_boundary as make_boundary

    boundary = make_boundary()
    content_type = "multipart/byteranges; boundary={0}".format(boundary)
    headers['Content-Type'] = content_type
    if "Content-Length" in headers:
        del headers["Content-Length"]

    def file_ranges():
        for start, stop in r:
            yield to_unicode("--" + boundary)
            yield to_unicode("\r\nContent-type: {0}".format(content_type))
            yield to_unicode(
                "\r\nContent-range: bytes {0}-{1}/{2}\r\n\r\n".format(
                    start, stop - 1, content_length))
            fileobj.seek(start)

            gen = file_generator_limited(fileobj, stop - start)
            for chunk in gen:
                yield chunk
            yield to_unicode("\r\n")

        yield to_unicode("--" + boundary + "--")

    body = file_ranges()
    return body, headers, status_code
示例#20
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