예제 #1
0
    def finalize_output(self, output, request, is_http1):
        none_match = parse_if_none_match(request.inheaders.get('If-None-Match', ''))
        if isinstance(output, ETaggedDynamicOutput):
            matched = '*' in none_match or (output.etag and output.etag in none_match)
            if matched:
                if self.method in ('GET', 'HEAD'):
                    self.send_not_modified(output.etag)
                else:
                    self.simple_response(httplib.PRECONDITION_FAILED)
                return

        opts = self.opts
        outheaders = request.outheaders
        stat_result = file_metadata(output)
        if stat_result is not None:
            output = filesystem_file_output(output, outheaders, stat_result)
            if 'Content-Type' not in outheaders:
                mt = guess_type(output.name)[0]
                if mt:
                    if mt in {'text/plain', 'text/html', 'application/javascript', 'text/css'}:
                        mt += '; charset=UTF-8'
                    outheaders['Content-Type'] = mt
        elif isinstance(output, (bytes, type(''))):
            output = dynamic_output(output, outheaders)
        elif hasattr(output, 'read'):
            output = ReadableOutput(output)
        elif isinstance(output, StaticOutput):
            output = ReadableOutput(ReadOnlyFileBuffer(output.data), etag=output.etag, content_length=output.content_length)
        elif isinstance(output, ETaggedDynamicOutput):
            output = dynamic_output(output(), outheaders, etag=output.etag)
        else:
            output = GeneratedOutput(output)
        ct = outheaders.get('Content-Type', '').partition(';')[0]
        compressible = (not ct or ct.startswith('text/') or ct.startswith('image/svg') or
                        ct.partition(';')[0] in COMPRESSIBLE_TYPES)
        compressible = (compressible and request.status_code == httplib.OK and
                        (opts.compress_min_size > -1 and output.content_length >= opts.compress_min_size) and
                        acceptable_encoding(request.inheaders.get('Accept-Encoding', '')) and not is_http1)
        accept_ranges = (not compressible and output.accept_ranges is not None and request.status_code == httplib.OK and
                        not is_http1)
        ranges = get_ranges(request.inheaders.get('Range'), output.content_length) if output.accept_ranges and self.method in ('GET', 'HEAD') else None
        if_range = (request.inheaders.get('If-Range') or '').strip()
        if if_range and if_range != output.etag:
            ranges = None
        if ranges is not None and not ranges:
            return self.send_range_not_satisfiable(output.content_length)

        for header in ('Accept-Ranges', 'Content-Encoding', 'Transfer-Encoding', 'ETag', 'Content-Length'):
            outheaders.pop(header, all=True)

        matched = '*' in none_match or (output.etag and output.etag in none_match)
        if matched:
            if self.method in ('GET', 'HEAD'):
                self.send_not_modified(output.etag)
            else:
                self.simple_response(httplib.PRECONDITION_FAILED)
            return

        output.ranges = None

        if output.etag and self.method in ('GET', 'HEAD'):
            outheaders.set('ETag', output.etag, replace_all=True)
        if accept_ranges:
            outheaders.set('Accept-Ranges', 'bytes', replace_all=True)
        if compressible and not ranges:
            outheaders.set('Content-Encoding', 'gzip', replace_all=True)
            if getattr(output, 'content_length', None):
                outheaders.set('Calibre-Uncompressed-Length', '%d' % output.content_length)
            output = GeneratedOutput(compress_readable_output(output.src_file), etag=output.etag)
        if output.content_length is not None and not compressible and not ranges:
            outheaders.set('Content-Length', '%d' % output.content_length, replace_all=True)

        if compressible or output.content_length is None:
            outheaders.set('Transfer-Encoding', 'chunked', replace_all=True)

        if ranges:
            if len(ranges) == 1:
                r = ranges[0]
                outheaders.set('Content-Length', '%d' % r.size, replace_all=True)
                outheaders.set('Content-Range', 'bytes %d-%d/%d' % (r.start, r.stop, output.content_length), replace_all=True)
                output.ranges = r
            else:
                range_parts = get_range_parts(ranges, outheaders.get('Content-Type'), output.content_length)
                size = sum(map(len, range_parts)) + sum(r.size + 4 for r in ranges)
                outheaders.set('Content-Length', '%d' % size, replace_all=True)
                outheaders.set('Content-Type', 'multipart/byteranges; boundary=' + MULTIPART_SEPARATOR, replace_all=True)
                output.ranges = izip_longest(ranges, range_parts)
            request.status_code = httplib.PARTIAL_CONTENT
        return output
예제 #2
0
    def finalize_output(self, output, request, is_http1):
        none_match = parse_if_none_match(
            request.inheaders.get('If-None-Match', ''))
        if isinstance(output, ETaggedDynamicOutput):
            matched = '*' in none_match or (output.etag
                                            and output.etag in none_match)
            if matched:
                if self.method in ('GET', 'HEAD'):
                    self.send_not_modified(output.etag)
                else:
                    self.simple_response(httplib.PRECONDITION_FAILED)
                return

        opts = self.opts
        outheaders = request.outheaders
        stat_result = file_metadata(output)
        if stat_result is not None:
            output = filesystem_file_output(output, outheaders, stat_result)
            if 'Content-Type' not in outheaders:
                mt = guess_type(output.name)[0]
                if mt:
                    if mt in {
                            'text/plain', 'text/html',
                            'application/javascript', 'text/css'
                    }:
                        mt += '; charset=UTF-8'
                    outheaders['Content-Type'] = mt
        elif isinstance(output, (bytes, type(''))):
            output = dynamic_output(output, outheaders)
        elif hasattr(output, 'read'):
            output = ReadableOutput(output)
        elif isinstance(output, StaticOutput):
            output = ReadableOutput(ReadOnlyFileBuffer(output.data),
                                    etag=output.etag,
                                    content_length=output.content_length)
        elif isinstance(output, ETaggedDynamicOutput):
            output = dynamic_output(output(), outheaders, etag=output.etag)
        else:
            output = GeneratedOutput(output)
        ct = outheaders.get('Content-Type', '').partition(';')[0]
        compressible = (not ct or ct.startswith('text/')
                        or ct.startswith('image/svg')
                        or ct.partition(';')[0] in COMPRESSIBLE_TYPES)
        compressible = (compressible and request.status_code == httplib.OK and
                        (opts.compress_min_size > -1
                         and output.content_length >= opts.compress_min_size)
                        and acceptable_encoding(
                            request.inheaders.get('Accept-Encoding', ''))
                        and not is_http1)
        accept_ranges = (not compressible and output.accept_ranges is not None
                         and request.status_code == httplib.OK
                         and not is_http1)
        ranges = get_ranges(
            request.inheaders.get('Range'), output.content_length
        ) if output.accept_ranges and self.method in ('GET', 'HEAD') else None
        if_range = (request.inheaders.get('If-Range') or '').strip()
        if if_range and if_range != output.etag:
            ranges = None
        if ranges is not None and not ranges:
            return self.send_range_not_satisfiable(output.content_length)

        for header in ('Accept-Ranges', 'Content-Encoding',
                       'Transfer-Encoding', 'ETag', 'Content-Length'):
            outheaders.pop(header, all=True)

        matched = '*' in none_match or (output.etag
                                        and output.etag in none_match)
        if matched:
            if self.method in ('GET', 'HEAD'):
                self.send_not_modified(output.etag)
            else:
                self.simple_response(httplib.PRECONDITION_FAILED)
            return

        output.ranges = None

        if output.etag and self.method in ('GET', 'HEAD'):
            outheaders.set('ETag', output.etag, replace_all=True)
        if accept_ranges:
            outheaders.set('Accept-Ranges', 'bytes', replace_all=True)
        if compressible and not ranges:
            outheaders.set('Content-Encoding', 'gzip', replace_all=True)
            if getattr(output, 'content_length', None):
                outheaders.set('Calibre-Uncompressed-Length',
                               '%d' % output.content_length)
            output = GeneratedOutput(compress_readable_output(output.src_file),
                                     etag=output.etag)
        if output.content_length is not None and not compressible and not ranges:
            outheaders.set('Content-Length',
                           '%d' % output.content_length,
                           replace_all=True)

        if compressible or output.content_length is None:
            outheaders.set('Transfer-Encoding', 'chunked', replace_all=True)

        if ranges:
            if len(ranges) == 1:
                r = ranges[0]
                outheaders.set('Content-Length',
                               '%d' % r.size,
                               replace_all=True)
                outheaders.set('Content-Range',
                               'bytes %d-%d/%d' %
                               (r.start, r.stop, output.content_length),
                               replace_all=True)
                output.ranges = r
            else:
                range_parts = get_range_parts(ranges,
                                              outheaders.get('Content-Type'),
                                              output.content_length)
                size = sum(map(len, range_parts)) + sum(r.size + 4
                                                        for r in ranges)
                outheaders.set('Content-Length', '%d' % size, replace_all=True)
                outheaders.set('Content-Type',
                               'multipart/byteranges; boundary=' +
                               MULTIPART_SEPARATOR,
                               replace_all=True)
                output.ranges = zip_longest(ranges, range_parts)
            request.status_code = httplib.PARTIAL_CONTENT
        return output
예제 #3
0
    def finalize_output(self, output, request, is_http1):
        opts = self.opts
        outheaders = request.outheaders
        stat_result = file_metadata(output)
        if stat_result is not None:
            output = filesystem_file_output(output, outheaders, stat_result)
            if "Content-Type" not in outheaders:
                mt = guess_type(output.name)[0]
                if mt:
                    if mt in {"text/plain", "text/html", "application/javascript", "text/css"}:
                        mt += "; charset=UTF-8"
                    outheaders["Content-Type"] = mt
        elif isinstance(output, (bytes, type(""))):
            output = dynamic_output(output, outheaders)
        elif hasattr(output, "read"):
            output = ReadableOutput(output)
        elif isinstance(output, StaticOutput):
            output = ReadableOutput(BytesIO(output.data), etag=output.etag, content_length=output.content_length)
        else:
            output = GeneratedOutput(output)
        ct = outheaders.get("Content-Type", "").partition(";")[0]
        compressible = (
            not ct or ct.startswith("text/") or ct.startswith("image/svg") or ct.partition(";")[0] in COMPRESSIBLE_TYPES
        )
        compressible = (
            compressible
            and request.status_code == httplib.OK
            and (opts.compress_min_size > -1 and output.content_length >= opts.compress_min_size)
            and acceptable_encoding(request.inheaders.get("Accept-Encoding", ""))
            and not is_http1
        )
        accept_ranges = (
            not compressible and output.accept_ranges is not None and request.status_code == httplib.OK and not is_http1
        )
        ranges = (
            get_ranges(request.inheaders.get("Range"), output.content_length)
            if output.accept_ranges and self.method in ("GET", "HEAD")
            else None
        )
        if_range = (request.inheaders.get("If-Range") or "").strip()
        if if_range and if_range != output.etag:
            ranges = None
        if ranges is not None and not ranges:
            return self.send_range_not_satisfiable(output.content_length)

        for header in ("Accept-Ranges", "Content-Encoding", "Transfer-Encoding", "ETag", "Content-Length"):
            outheaders.pop("header", all=True)

        none_match = parse_if_none_match(request.inheaders.get("If-None-Match", ""))
        matched = "*" in none_match or (output.etag and output.etag in none_match)
        if matched:
            if self.method in ("GET", "HEAD"):
                self.send_not_modified(output.etag)
            else:
                self.simple_response(httplib.PRECONDITION_FAILED)
            return

        output.ranges = None

        if output.etag and self.method in ("GET", "HEAD"):
            outheaders.set("ETag", output.etag, replace_all=True)
        if accept_ranges:
            outheaders.set("Accept-Ranges", "bytes", replace_all=True)
        if compressible and not ranges:
            outheaders.set("Content-Encoding", "gzip", replace_all=True)
            output = GeneratedOutput(compress_readable_output(output.src_file), etag=output.etag)
        if output.content_length is not None and not compressible and not ranges:
            outheaders.set("Content-Length", "%d" % output.content_length, replace_all=True)

        if compressible or output.content_length is None:
            outheaders.set("Transfer-Encoding", "chunked", replace_all=True)

        if ranges:
            if len(ranges) == 1:
                r = ranges[0]
                outheaders.set("Content-Length", "%d" % r.size, replace_all=True)
                outheaders.set(
                    "Content-Range", "bytes %d-%d/%d" % (r.start, r.stop, output.content_length), replace_all=True
                )
                output.ranges = r
            else:
                range_parts = get_range_parts(ranges, outheaders.get("Content-Type"), output.content_length)
                size = sum(map(len, range_parts)) + sum(r.size + 4 for r in ranges)
                outheaders.set("Content-Length", "%d" % size, replace_all=True)
                outheaders.set(
                    "Content-Type", "multipart/byteranges; boundary=" + MULTIPART_SEPARATOR, replace_all=True
                )
                output.ranges = izip_longest(ranges, range_parts)
            request.status_code = httplib.PARTIAL_CONTENT
        return output