示例#1
0
    async def send_with_gzip(self, message: Message) -> None:
        message_type = message["type"]
        if message_type == "http.response.start":
            # Don't send the initial message until we've determined how to
            # modify the ougoging headers correctly.
            self.initial_message = message
        elif message_type == "http.response.body" and not self.started:
            self.started = True
            body = message.get("body", b"")
            more_body = message.get("more_body", False)
            if len(body) < self.minimum_size and not more_body:
                # Don't apply GZip to small outgoing responses.
                await self.send(self.initial_message)
                await self.send(message)
            elif not more_body:
                # Standard GZip response.
                self.gzip_file.write(body)
                self.gzip_file.close()
                body = self.gzip_buffer.getvalue()

                headers = MutableHeaders(raw=self.initial_message["headers"])
                headers["Content-Encoding"] = "gzip"
                headers["Content-Length"] = str(len(body))
                headers.add_vary_header("Accept-Encoding")
                message["body"] = body

                await self.send(self.initial_message)
                await self.send(message)
            else:
                # Initial body in streaming GZip response.
                headers = MutableHeaders(raw=self.initial_message["headers"])
                headers["Content-Encoding"] = "gzip"
                headers.add_vary_header("Accept-Encoding")
                del headers["Content-Length"]

                self.gzip_file.write(body)
                message["body"] = self.gzip_buffer.getvalue()
                self.gzip_buffer.seek(0)
                self.gzip_buffer.truncate()

                await self.send(self.initial_message)
                await self.send(message)

        elif message_type == "http.response.body":
            # Remaining body in streaming GZip response.
            body = message.get("body", b"")
            more_body = message.get("more_body", False)

            self.gzip_file.write(body)
            if not more_body:
                self.gzip_file.close()

            message["body"] = self.gzip_buffer.getvalue()
            self.gzip_buffer.seek(0)
            self.gzip_buffer.truncate()

            await self.send(message)
示例#2
0
    async def send_with_brotli(self, message: Message) -> None:
        """Apply compression using brotli."""
        message_type = message["type"]
        if message_type == "http.response.start":
            # Don't send the initial message until we've determined how to
            # modify the outgoing headers correctly.
            self.initial_message = message
        elif message_type == "http.response.body" and not self.started:
            self.started = True
            body = message.get("body", b"")
            more_body = message.get("more_body", False)
            if len(body) < self.minimum_size and not more_body:
                # Don't apply Brotli to small outgoing responses.
                await self.send(self.initial_message)
                await self.send(message)
            elif not more_body:
                # Standard Brotli response.
                body = self.br_file.process(body) + self.br_file.finish()
                headers = MutableHeaders(raw=self.initial_message["headers"])
                headers["Content-Encoding"] = "br"
                headers["Content-Length"] = str(len(body))
                headers.add_vary_header("Accept-Encoding")
                message["body"] = body
                await self.send(self.initial_message)
                await self.send(message)
            else:
                # Initial body in streaming Brotli response.
                headers = MutableHeaders(raw=self.initial_message["headers"])
                headers["Content-Encoding"] = "br"
                headers.add_vary_header("Accept-Encoding")
                del headers["Content-Length"]
                self.br_buffer.write(
                    self.br_file.process(body) + self.br_file.flush())

                message["body"] = self.br_buffer.getvalue()
                self.br_buffer.seek(0)
                self.br_buffer.truncate()
                await self.send(self.initial_message)
                await self.send(message)

        elif message_type == "http.response.body":
            # Remaining body in streaming Brotli response.
            body = message.get("body", b"")
            more_body = message.get("more_body", False)
            self.br_buffer.write(
                self.br_file.process(body) + self.br_file.flush())
            if not more_body:
                self.br_buffer.write(self.br_file.finish())
                message["body"] = self.br_buffer.getvalue()
                self.br_buffer.close()
                await self.send(message)
                return
            message["body"] = self.br_buffer.getvalue()
            self.br_buffer.seek(0)
            self.br_buffer.truncate()
            await self.send(message)
示例#3
0
    async def send(self, message, send, request_headers) -> None:
        if message["type"] != "http.response.start":
            await send(message)
            return

        message.setdefault("headers", [])
        headers = MutableHeaders(scope=message)
        headers.update(self.simple_headers)
        origin = request_headers["Origin"]
        has_cookie = "cookie" in request_headers

        if self.allow_all_origins and has_cookie:
            headers["Access-Control-Allow-Origin"] = origin

        elif not self.allow_all_origins and \
                self.is_allowed_origin(origin=origin):
            headers["Access-Control-Allow-Origin"] = origin
            headers.add_vary_header("Origin")
        await send(message)
示例#4
0
    async def send(
        self, message: Message, send: Send, request_headers: Headers
    ) -> None:
        if message["type"] != "http.response.start":
            await send(message)
            return

        message.setdefault("headers", [])
        headers = MutableHeaders(scope=message)
        headers.update(self.simple_headers)
        origin = request_headers["Origin"]
        has_cookie = "cookie" in request_headers

        # If request includes any cookie headers, then we must respond
        # with the specific origin instead of '*'.
        if self.allow_all_origins and has_cookie:
            headers["Access-Control-Allow-Origin"] = origin

        # If we only allow specific origins, then we have to mirror back
        # the Origin header in the response.
        elif not self.allow_all_origins and self.is_allowed_origin(origin=origin):
            headers["Access-Control-Allow-Origin"] = origin
            headers.add_vary_header("Origin")
        await send(message)
示例#5
0
文件: cors.py 项目: joshis1/Python
 def allow_explicit_origin(headers: MutableHeaders, origin: str) -> None:
     headers["Access-Control-Allow-Origin"] = origin
     headers.add_vary_header("Origin")
示例#6
0
    async def send_compressed(self, message: Message) -> None:
        message_type = message["type"]
        if message_type == "http.response.start":
            # Don't send the initial message until we've determined how to
            # modify the outgoing headers correctly.
            self.initial_message = message
            headers = MutableHeaders(raw=self.initial_message["headers"])
            media_type = headers.get("Content-Type")
            for encoding in self.compression_registry.encodings(media_type):
                if encoding in self.accepted:
                    file_factory = self.compression_registry.dispatch(
                        media_type=media_type, encoding=encoding)
                    self.compressed_buffer = io.BytesIO()
                    self.compressed_file = file_factory(self.compressed_buffer)
                    self.encoding = encoding
                    break
            else:
                self.encoding = None
        elif message_type == "http.response.body" and not self.started:
            headers = MutableHeaders(raw=self.initial_message["headers"])
            self.started = True
            body = message.get("body", b"")
            more_body = message.get("more_body", False)
            if len(body) < self.minimum_size and not more_body:
                # Don't apply compression to small outgoing responses.
                await self.send(self.initial_message)
                await self.send(message)
            elif not more_body:
                if self.encoding is not None:
                    # Standard (non-streaming) response.
                    t0 = time.perf_counter()
                    self.compressed_file.write(body)
                    self.compressed_file.close()
                    compression_time = time.perf_counter() - t0
                    compressed_body = self.compressed_buffer.getvalue()
                    # Check to see if the compression ratio is significant.
                    # If it isn't just send the original; the savings isn't worth the decompression time.
                    compression_ratio = len(body) / len(
                        compressed_body)  # higher is better
                    THRESHOLD = 1 / 0.9
                    if compression_ratio > THRESHOLD:
                        headers["Content-Encoding"] = self.encoding
                        headers["Content-Length"] = str(len(compressed_body))
                        headers.add_vary_header("Accept-Encoding")
                        message["body"] = compressed_body
                        # The Server-Timing middleware, which runs after this
                        # CompressionMiddleware, formats these metrics alongside
                        # others in the Server-Timing header.
                        self.scope["state"]["metrics"]["compress"] = {
                            "dur": compression_time,  # Units: seconds
                            "ratio": compression_ratio,
                        }

                await self.send(self.initial_message)
                await self.send(message)
            else:
                # Initial body in streaming response.
                if self.encoding is not None:
                    headers = MutableHeaders(
                        raw=self.initial_message["headers"])
                    headers["Content-Encoding"] = self.encoding
                    headers.add_vary_header("Accept-Encoding")
                    del headers["Content-Length"]

                    self.compressed_file.write(body)
                    message["body"] = self.compressed_buffer.getvalue()
                    self.compressed_buffer.seek(0)
                    self.compressed_buffer.truncate()

                await self.send(self.initial_message)
                await self.send(message)

        elif message_type == "http.response.body":
            # Remaining body in streaming response.
            if self.encoding is not None:
                body = message.get("body", b"")
                more_body = message.get("more_body", False)

                self.compressed_file.write(body)
                if not more_body:
                    self.compressed_file.close()

                message["body"] = self.compressed_buffer.getvalue()
                self.compressed_buffer.seek(0)
                self.compressed_buffer.truncate()

            await self.send(message)