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
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
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