コード例 #1
0
ファイル: main.py プロジェクト: danhbear/dripls
    def stream_ts(self, p=None, **kwargs):
        """ Stream a ts from original location """

        import socket
        socket._fileobject.default_bufsize = 0

        serving_request = cherrypy.serving.request
        if serving_request.protocol >= (1, 1):
            r = httputil.get_ranges(serving_request.headers.get('Range'), sys.maxint)

            # TODO : do something with range request if need be
       
        req = urllib2.Request(kwargs['url'])
        for header in serving_request.headers:
             if header not in ['Range','Accept','User-Agent']:
                  continue
             req.headers[header] = serving_request.headers.get(header)
        ts = urllib2.urlopen(req)

        for h in ts.headers.keys():
            cherrypy.response.headers[h] = ts.headers[h]

        buffer = '_'
        while len(buffer) > 0:
          buffer = ts.read(30*1024)
          yield buffer
コード例 #2
0
ファイル: static.py プロジェクト: connoryang/1v1dec
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
コード例 #3
0
ファイル: static.py プロジェクト: connoryang/dec-eve-serenity
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 stream_ts(self, p=None, **kwargs):
        """ Stream a ts from original location """

        serving_request = cherrypy.serving.request
        if serving_request.protocol >= (1, 1):
            r = httputil.get_ranges(serving_request.headers.get('Range'), sys.maxint)

            # TODO : do something with range request if need be
       
        for bytes in self._stream_url(serving_request, kwargs.get("url")):
            yield bytes
コード例 #5
0
    def _handle_progressive_rules(self, url, rules, request, mock_shape_segment=True):
        stream_url = url
        matcher = progressive.from_rules(rules)

        if 'Range' in request.headers:
            ranges = httputil.get_ranges(request.headers.get('Range'), sys.maxint)
            if ranges:
                # can return multiple ranges
                # assume 1 for now
                action = matcher.get_action(ranges[0][0], ranges[0][1] -1) # make range inclusive
        else:
            # this is fetching an entire file, so this should be the same as matching 0-*
            action = matcher.get_action(0, sys.maxint)
        if action:
            if action.startswith("e"):
                self.ostatus(action[1:]) 
            else:
                (traffic_limit, traffic_loss, cache) = shaper.parse_net_rule_action(action)
                port = shaper.get_shape_port_for(traffic_limit, traffic_loss, {}, mock_shape_segment)
                stream_url=conf.common.get_final_url("/s/{0}/progressive?url={1}&from_dripls=1".format(port, urllib.quote_plus(url)),"")
        return stream_url
コード例 #6
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
コード例 #7
0
ファイル: test_core.py プロジェクト: bmbove/omxremote
 def get_ranges(self, bytes):
     return repr(httputil.get_ranges('bytes=%s' % bytes, 8))
コード例 #8
0
ファイル: VideoServer.py プロジェクト: Antiade/tribler
    def do_GET(self):
        if self.request_version == 'HTTP/1.1':
            self.protocol_version = 'HTTP/1.1'

        self._logger.debug("VOD request %s %s", self.client_address, self.path)
        downloadhash, fileindex = self.path.strip('/').split('/')
        downloadhash = unhexlify(downloadhash)
        download = self.server.session.get_download(downloadhash)

        if not download or not fileindex.isdigit() or int(fileindex) > len(download.get_def().get_files()):
            self.send_error(404, "Not Found")
            return

        fileindex = int(fileindex)
        filename, length = download.get_def().get_files_as_unicode_with_length()[fileindex]

        requested_range = get_ranges(self.headers.getheader('range'), length)
        if requested_range is not None and len(requested_range) != 1:
            self.send_error(416, "Requested Range Not Satisfiable")
            return

        has_changed = self.videoplayer.get_vod_fileindex() != fileindex or\
            self.videoplayer.get_vod_download() != download
        if has_changed:
            # Notify the videoplayer (which will put the old VOD download back in normal mode).
            self.videoplayer.set_vod_fileindex(fileindex)
            self.videoplayer.set_vod_download(download)

            # Put download in sequential mode + trigger initial buffering.
            if download.get_def().is_multifile_torrent():
                download.set_selected_files([filename])
            download.set_mode(DLMODE_VOD)
            download.restart()

        piecelen = download.get_def().get_piece_length()
        blocksize = piecelen

        if requested_range is not None:
            firstbyte, lastbyte = requested_range[0]
            nbytes2send = lastbyte - firstbyte
            self.send_response(206)
            self.send_header('Content-Range', 'bytes %d-%d/%d' % (firstbyte, lastbyte - 1, length))
        else:
            firstbyte = 0
            nbytes2send = length
            self.send_response(200)

        self._logger.debug("requested range %d - %d", firstbyte, firstbyte + nbytes2send)

        mimetype = mimetypes.guess_type(filename)[0]
        if mimetype:
            self.send_header('Content-Type', mimetype)
        self.send_header('Accept-Ranges', 'bytes')

        if length is not None:
            self.send_header('Content-Length', nbytes2send)
        else:
            self.send_header('Transfer-Encoding', 'chunked')

        if self.request_version == 'HTTP/1.1' and self.headers.get('Connection', '').lower() != 'close':
            self.send_header('Connection', 'Keep-Alive')
            self.send_header('Keep-Alive', 'timeout=300, max=1')

        self.end_headers()

        if has_changed:
            self.wait_for_buffer(download)

        stream, lock = self.videoplayer.get_vod_stream(downloadhash, wait=True)

        with lock:
            if stream.closed:
                return

            stream.seek(firstbyte)
            nbyteswritten = 0
            while True:
                data = stream.read(blocksize)

                if len(data) == 0:
                    break
                elif length is not None and nbyteswritten + len(data) > nbytes2send:
                    endlen = nbytes2send - nbyteswritten
                    if endlen != 0:
                        self.wfile.write(data[:endlen])
                        nbyteswritten += endlen
                    break
                else:
                    self.wfile.write(data)
                    nbyteswritten += len(data)

            if nbyteswritten != nbytes2send:
                self._logger.error("sent wrong amount, wanted %s got %s", nbytes2send, nbyteswritten)

            if not requested_range:
                stream.close()
コード例 #9
0
ファイル: static.py プロジェクト: PavloKapyshin/Clay
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
コード例 #10
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
コード例 #11
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
コード例 #12
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
コード例 #13
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
コード例 #14
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
コード例 #15
0
ファイル: VideoServer.py プロジェクト: yorig/tribler
    def do_GET(self):
        if self.request_version == 'HTTP/1.1':
            self.protocol_version = 'HTTP/1.1'

        self._logger.debug("VOD request %s %s", self.client_address, self.path)
        downloadhash, fileindex = self.path.strip('/').split('/')
        downloadhash = unhexlify(downloadhash)
        download = self.server.session.get_download(downloadhash)

        if not download or not fileindex.isdigit() or int(fileindex) > len(
                download.get_def().get_files()):
            self.send_error(404, "Not Found")
            return

        fileindex = int(fileindex)
        filename, length = download.get_def().get_files_as_unicode_with_length(
        )[fileindex]

        requested_range = get_ranges(self.headers.getheader('range'), length)
        if requested_range is not None and len(requested_range) != 1:
            self.send_error(416, "Requested Range Not Satisfiable")
            return

        has_changed = self.videoplayer.get_vod_fileindex() != fileindex or\
            self.videoplayer.get_vod_download() != download
        if has_changed:
            # Notify the videoplayer (which will put the old VOD download back in normal mode).
            self.videoplayer.set_vod_fileindex(fileindex)
            self.videoplayer.set_vod_download(download)

            # Put download in sequential mode + trigger initial buffering.
            if download.get_def().is_multifile_torrent():
                download.set_selected_files([filename])
            download.set_mode(DLMODE_VOD)
            download.restart()

        piecelen = download.get_def().get_piece_length()
        blocksize = piecelen

        if requested_range is not None:
            firstbyte, lastbyte = requested_range[0]
            nbytes2send = lastbyte - firstbyte
            self.send_response(206)
            self.send_header(
                'Content-Range',
                'bytes %d-%d/%d' % (firstbyte, lastbyte - 1, length))
        else:
            firstbyte = 0
            nbytes2send = length
            self.send_response(200)

        self._logger.debug("requested range %d - %d", firstbyte,
                           firstbyte + nbytes2send)

        mimetype = mimetypes.guess_type(filename)[0]
        if mimetype:
            self.send_header('Content-Type', mimetype)
        self.send_header('Accept-Ranges', 'bytes')

        if length is not None:
            self.send_header('Content-Length', nbytes2send)
        else:
            self.send_header('Transfer-Encoding', 'chunked')

        if self.request_version == 'HTTP/1.1' and self.headers.get(
                'Connection', '').lower() != 'close':
            self.send_header('Connection', 'Keep-Alive')
            self.send_header('Keep-Alive', 'timeout=300, max=1')

        self.end_headers()

        if has_changed:
            self.wait_for_buffer(download)

        stream, lock = self.videoplayer.get_vod_stream(downloadhash, wait=True)

        with lock:
            if stream.closed:
                return

            stream.seek(firstbyte)
            nbyteswritten = 0
            while True:
                data = stream.read(blocksize)

                if len(data) == 0:
                    break
                elif length is not None and nbyteswritten + len(
                        data) > nbytes2send:
                    endlen = nbytes2send - nbyteswritten
                    if endlen != 0:
                        self.wfile.write(data[:endlen])
                        nbyteswritten += endlen
                    break
                else:
                    self.wfile.write(data)
                    nbyteswritten += len(data)

            if nbyteswritten != nbytes2send:
                self._logger.error("sent wrong amount, wanted %s got %s",
                                   nbytes2send, nbyteswritten)

            if not requested_range:
                stream.close()
コード例 #16
0
 def get_ranges(self, bytes):
     return repr(httputil.get_ranges('bytes=%s' % bytes, 8))
コード例 #17
0
 def getMedia(self, id):
     #https://github.com/happyworm/smartReadFile/blob/master/smartReadFile.php
     if not self.isValidId(id):
         raise cherrypy.HTTPError(404)
     
     itemService = ItemService()
     item = itemService.findOne(id)
     
     if item is None:
         raise cherrypy.HTTPError(404)
     
     if not os.path.isfile(item.mediaUri):
         raise cherrypy.HTTPError(404)
     
     from cherrypy.lib import httputil
     
     file = os.stat(item.mediaUri)
     contentLength = file.st_size
     
     begin = 0
     end = contentLength - 1
     
     r = httputil.get_ranges(cherrypy.request.headers.get("Range"), contentLength)        
     
     if r is None:
         pass
     else:
         if r==[]:
             pass
         else:
             begin, end = r[0]
             
     if range in cherrypy.request.headers:
         cherrypy.response.status = "206 Partial Content"
     else:
         cherrypy.response.status = "200 OK"
     
     cherrypy.response.headers["Content-Type"] = mimetypes.guess_type(item.mediaUri)[0]
     cherrypy.response.headers["Cache-Control"] = "public, must-revalidate, max-age=0"
     cherrypy.response.headers["Pragma"] = "no-cache"
     cherrypy.response.headers["Accept-Ranges"] = "bytes"
     cherrypy.response.headers["Content-Length"] = str(end-begin+1)
     
     if range in cherrypy.request.headers:
         cherrypy.response.headers["Content-Range"] = "bytes {0}-{1}/{contentLength}".format(begin, end, contentLength)
         
     cherrypy.response.headers["Content-Disposition"] = "inline; filename="  + os.path.basename(item.mediaUri)
     cherrypy.response.headers["Content-Transfer-Encoding"] = "binary"
     cherrypy.response.headers["Last-Modified"] = file.st_mtime
     
     file = open (item.mediaUri, "rb")
     current = begin
     file.seek(current, 0)
     
     def stream(file, current, end):
         bufferSize = 1024*128
         
         while current<=end:
             data = file.read(min(bufferSize, (end-current)+1))
             
             if len(data)==0:
                 if file is not None:
                     file.close()
                     
                 return
             
             yield data
             current += bufferSize
             
     return stream(file, current, end)