コード例 #1
0
 async def read_data(self) -> None:
     if self.connection.they_are_waiting_for_100_continue:
         await self.asend(
             h11.InformationalResponse(status_code=100,
                                       headers=self.response_headers()))
     data = await self.stream.receive_some(MAX_RECV)
     self.connection.receive_data(data)
コード例 #2
0
    async def receive(self):
        if self.waiting_for_100_continue and not self.transport.is_closing():
            event = h11.InformationalResponse(
                status_code=100, headers=[], reason="Continue"
            )
            output = self.conn.send(event)
            self.transport.write(output)
            self.waiting_for_100_continue = False

        if not self.disconnected and not self.response_complete:
            self.flow.resume_reading()
            await self.message_event.wait()
            self.message_event.clear()

        if self.disconnected or self.response_complete:
            message = {"type": "http.disconnect"}
        else:
            message = {
                "type": "http.request",
                "body": self.body,
                "more_body": self.more_body,
            }
            self.body = b""

        return message
コード例 #3
0
 async def stream_send(self, event: StreamEvent) -> None:
     if isinstance(event, Response):
         if event.status_code >= 200:
             await self._send_h11_event(
                 h11.Response(
                     headers=chain(event.headers,
                                   self.config.response_headers("h11")),
                     status_code=event.status_code,
                 ))
         else:
             await self._send_h11_event(
                 h11.InformationalResponse(
                     headers=chain(event.headers,
                                   self.config.response_headers("h11")),
                     status_code=event.status_code,
                 ))
     elif isinstance(event, Body):
         await self._send_h11_event(h11.Data(data=event.data))
     elif isinstance(event, EndBody):
         await self._send_h11_event(h11.EndOfMessage())
     elif isinstance(event, Data):
         await self.send(RawData(data=event.data))
     elif isinstance(event, EndData):
         pass
     elif isinstance(event, StreamClosed):
         await self._maybe_recycle()
コード例 #4
0
ファイル: serving.py プロジェクト: zhengxiaowai/quart
 def _handle_events(self) -> None:
     if self.connection.they_are_waiting_for_100_continue:
         self._send(
             h11.InformationalResponse(status_code=100,
                                       headers=(('Date', ''), ('Server',
                                                               ''))), )
     while True:
         try:
             event = self.connection.next_event()
         except h11.ProtocolError:
             self._handle_error()
             self.transport.close()
         else:
             if isinstance(event, h11.Request):
                 headers = CIMultiDict()
                 for name, value in event.headers:
                     headers.add(name.decode().title(), value.decode())
                 self.streams[0] = Stream(self.loop)
                 self.handle_request(
                     0,
                     event.method.decode().upper(),
                     event.target.decode(),
                     headers,
                 )
             elif isinstance(event, h11.EndOfMessage):
                 self.streams[0].complete()
             elif isinstance(event, h11.Data):
                 self.streams[0].append(event.data)
             elif event is h11.NEED_DATA:
                 break
     if self.connection.our_state is h11.MUST_CLOSE:
         self.transport.close()
     elif self.connection.our_state is h11.DONE:
         self.connection.start_next_cycle()
コード例 #5
0
ファイル: h11.py プロジェクト: tharvik/quart
 def _handle_events(self) -> None:
     while True:
         if self.connection.they_are_waiting_for_100_continue:
             self._send(
                 h11.InformationalResponse(status_code=100, headers=self.response_headers()),
             )
         try:
             event = self.connection.next_event()
         except h11.RemoteProtocolError:
             self._handle_error()
             self.close()
             break
         else:
             if isinstance(event, h11.Request):
                 headers = CIMultiDict()
                 if event.http_version < b'1.1':
                     headers.setdefault('host', self.app.config['SERVER_NAME'] or '')
                 for name, value in event.headers:
                     headers.add(name.decode().title(), value.decode())
                 if 'Upgrade' in headers:
                     self._handle_upgrade_request(headers, event)
                     break
                 self.handle_request(
                     0, event.method.decode().upper(), event.target.decode(), headers,
                 )
             elif isinstance(event, h11.EndOfMessage):
                 self.streams[0].complete()
             elif isinstance(event, h11.Data):
                 self.streams[0].append(event.data)
             elif event is h11.NEED_DATA or event is h11.PAUSED:
                 break
             elif isinstance(event, h11.ConnectionClosed):
                 break
     if self.connection.our_state is h11.MUST_CLOSE:
         self.close()
コード例 #6
0
    async def handle_connection(self) -> None:
        try:
            # Loop over the requests in order of receipt (either
            # pipelined or due to keep-alive).
            while True:
                with trio.fail_after(self.config.keep_alive_timeout):
                    request = await self.read_request()
                self.raise_if_upgrade(request,
                                      self.connection.trailing_data[0])

                async with trio.open_nursery() as nursery:
                    nursery.start_soon(self.handle_request, request)
                    await self.read_body()

                await self.recycle_or_close()
        except (trio.BrokenResourceError, trio.ClosedResourceError):
            await self.asgi_put({"type": "http.disconnect"})
            await self.aclose()
        except (trio.TooSlowError, MustCloseError):
            await self.aclose()
        except H2CProtocolRequired as error:
            await self.asend(
                h11.InformationalResponse(status_code=101,
                                          headers=[(b"upgrade", b"h2c")] +
                                          self.response_headers()))
            raise error
        except WrongProtocolError:
            raise  # Do not close the connection
コード例 #7
0
    async def _check_protocol(self, event: h11.Request) -> None:
        upgrade_value = ""
        has_body = False
        for name, value in event.headers:
            sanitised_name = name.decode("latin1").strip().lower()
            if sanitised_name == "upgrade":
                upgrade_value = value.decode("latin1").strip()
            elif sanitised_name in {"content-length", "transfer-encoding"}:
                has_body = True

        # h2c Upgrade requests with a body are a pain as the body must
        # be fully recieved in HTTP/1.1 before the upgrade response
        # and HTTP/2 takes over, so Hypercorn ignores the upgrade and
        # responds in HTTP/1.1. Use a preflight OPTIONS request to
        # initiate the upgrade if really required (or just use h2).
        if upgrade_value.lower() == "h2c" and not has_body:
            await self._send_h11_event(
                h11.InformationalResponse(
                    status_code=101,
                    headers=self.config.response_headers("h11") +
                    [(b"connection", b"upgrade"), (b"upgrade", b"h2c")],
                ))
            raise H2CProtocolRequired(self.connection.trailing_data[0], event)
        elif event.method == b"PRI" and event.target == b"*" and event.http_version == b"2.0":
            raise H2ProtocolAssumed(b"PRI * HTTP/2.0\r\n\r\n" +
                                    self.connection.trailing_data[0])
コード例 #8
0
    def accept(self, event, subprotocol=None):
        request = event.h11request
        request_headers = _normed_header_dict(request.headers)

        nonce = request_headers[b'sec-websocket-key']
        accept_token = self._generate_accept_token(nonce)

        headers = {
            b"Upgrade": b'WebSocket',
            b"Connection": b'Upgrade',
            b"Sec-WebSocket-Accept": accept_token,
        }

        if subprotocol is not None:
            if subprotocol not in event.proposed_subprotocols:
                raise ValueError(
                    "unexpected subprotocol {!r}".format(subprotocol))
            headers[b'Sec-WebSocket-Protocol'] = subprotocol

        extensions = request_headers.get(b'sec-websocket-extensions', None)
        if extensions:
            accepts = self._extension_accept(extensions)
            if accepts:
                headers[b"Sec-WebSocket-Extensions"] = accepts

        response = h11.InformationalResponse(status_code=101,
                                             headers=headers.items())
        self._outgoing += self._upgrade_connection.send(response)
        self._proto = FrameProtocol(self.client, self.extensions)
        self._state = ConnectionState.OPEN
コード例 #9
0
 async def _read_from_peer(self):
     if self.conn.they_are_waiting_for_100_continue:
         go_ahead = h11.InformationalResponse(status_code=100,
                                              headers=self.basic_headers())
         await self.send(go_ahead)
     data = await self.stream.receive_some(4096)
     self.conn.receive_data(data)
コード例 #10
0
    def _accept(self, event):
        # type: (AcceptConnection) -> None
        request_headers = normed_header_dict(
            self._initiating_request.extra_headers)

        nonce = request_headers[b"sec-websocket-key"]
        accept_token = generate_accept_token(nonce)

        headers = [
            (b"Upgrade", b"WebSocket"),
            (b"Connection", b"Upgrade"),
            (b"Sec-WebSocket-Accept", accept_token),
        ]

        if event.subprotocol is not None:
            if event.subprotocol not in self._initiating_request.subprotocols:
                raise LocalProtocolError("unexpected subprotocol {}".format(
                    event.subprotocol))
            headers.append((b"Sec-WebSocket-Protocol", event.subprotocol))

        if event.extensions:
            accepts = handshake_extensions(self._initiating_request.extensions,
                                           event.extensions)
            if accepts:
                headers.append((b"Sec-WebSocket-Extensions", accepts))

        response = h11.InformationalResponse(status_code=101,
                                             headers=headers +
                                             event.extra_headers)
        self._connection = Connection(
            ConnectionType.CLIENT if self.client else ConnectionType.SERVER,
            event.extensions,
        )
        self._state = ConnectionState.OPEN
        return self._h11_connection.send(response)
コード例 #11
0
ファイル: h11.py プロジェクト: indra8981/test
    async def _handle_events(self) -> None:
        while True:
            if self.connection.they_are_waiting_for_100_continue:
                await self._send_h11_event(
                    h11.InformationalResponse(
                        status_code=100, headers=self.config.response_headers("h11")
                    )
                )
            if self.connection.our_state in {h11.DONE, h11.CLOSED, h11.MUST_CLOSE}:
                return

            try:
                event = self.connection.next_event()
            except h11.RemoteProtocolError:
                if self.connection.our_state in {h11.IDLE, h11.SEND_RESPONSE}:
                    await self._send_error_response(400)
                await self.send(Closed())
                break
            else:
                if isinstance(event, h11.Request):
                    await self._check_protocol(event)
                    await self._create_stream(event)
                elif isinstance(event, h11.Data):
                    await self.stream.handle(Body(stream_id=STREAM_ID, data=event.data))
                elif isinstance(event, h11.EndOfMessage):
                    await self.stream.handle(EndBody(stream_id=STREAM_ID))
                elif isinstance(event, Data):
                    # WebSocket pass through
                    await self.stream.handle(event)
                elif event is h11.PAUSED:
                    await self.send(Updated())
                    await self.can_read.clear()
                    await self.can_read.wait()
                elif isinstance(event, h11.ConnectionClosed) or event is h11.NEED_DATA:
                    break
コード例 #12
0
def _make_handshake(
    response_status,
    response_headers,
    subprotocols=None,
    extensions=None,
    auto_accept_key=True,
):
    client = WSConnection(CLIENT)
    server = h11.Connection(h11.SERVER)
    server.receive_data(
        client.send(
            Request(
                host="localhost",
                target="/",
                subprotocols=subprotocols or [],
                extensions=extensions or [],
            )
        )
    )
    request = server.next_event()
    if auto_accept_key:
        full_request_headers = normed_header_dict(request.headers)
        response_headers.append(
            (
                b"Sec-WebSocket-Accept",
                generate_accept_token(full_request_headers[b"sec-websocket-key"]),
            )
        )
    response = h11.InformationalResponse(
        status_code=response_status, headers=response_headers
    )
    client.receive_data(server.send(response))

    return list(client.events())
コード例 #13
0
def test_connection_send_state() -> None:
    client = WSConnection(CLIENT)
    assert client.state is ConnectionState.CONNECTING

    server = h11.Connection(h11.SERVER)
    server.receive_data(client.send(Request(
        host="localhost",
        target="/",
    )))
    headers = normed_header_dict(server.next_event().headers)
    response = h11.InformationalResponse(
        status_code=101,
        headers=[
            (b"connection", b"Upgrade"),
            (b"upgrade", b"WebSocket"),
            (
                b"Sec-WebSocket-Accept",
                generate_accept_token(headers[b"sec-websocket-key"]),
            ),
        ],
    )
    client.receive_data(server.send(response))
    assert len(list(client.events())) == 1
    assert client.state is ConnectionState.OPEN  # type: ignore # https://github.com/python/mypy/issues/9005

    with pytest.raises(LocalProtocolError) as excinfo:
        client.send(Request(host="localhost", target="/"))

    client.receive_data(b"foobar")
    assert len(list(client.events())) == 1
コード例 #14
0
 def handle_events(self) -> None:
     # Called on receipt of data or after recycling the connection
     while True:
         if self.connection.they_are_waiting_for_100_continue:
             self.send(
                 h11.InformationalResponse(status_code=100,
                                           headers=self.response_headers()))
         try:
             event = self.connection.next_event()
         except h11.RemoteProtocolError:
             self.send(self.error_response(400))
             self.send(h11.EndOfMessage())
             self.app_queue.put_nowait({"type": "http.disconnect"})
             self.close()
             break
         else:
             if isinstance(event, h11.Request):
                 self.stop_keep_alive_timeout()
                 try:
                     self.raise_if_upgrade(event,
                                           self.connection.trailing_data[0])
                 except H2CProtocolRequired as error:
                     self.send(
                         h11.InformationalResponse(
                             status_code=101,
                             headers=[(b"upgrade", b"h2c")] +
                             self.response_headers(),
                         ))
                     raise error
                 self.task = self.loop.create_task(
                     self.handle_request(event))
                 self.task.add_done_callback(self.recycle_or_close)
             elif isinstance(event, h11.EndOfMessage):
                 self.app_queue.put_nowait({
                     "type": "http.request",
                     "body": b"",
                     "more_body": False
                 })
             elif isinstance(event, h11.Data):
                 self.app_queue.put_nowait({
                     "type": "http.request",
                     "body": event.data,
                     "more_body": True
                 })
             elif (isinstance(event, h11.ConnectionClosed)
                   or event is h11.NEED_DATA or event is h11.PAUSED):
                 break
コード例 #15
0
    def handle_upgrade(self, event: h11.Request):
        upgrade_value = None
        for name, value in self.headers:
            if name == b"upgrade":
                upgrade_value = value.lower()
                break

        if upgrade_value == b"websocket" and self.ws_protocol_class:
            self.connections.discard(self)
            output = [event.method, b" ", event.target, b" HTTP/1.1\r\n"]
            for name, value in self.headers:
                output += [name, b": ", value, b"\r\n"]
            output.append(b"\r\n")
            protocol = self.ws_protocol_class(
                config=self.config,
                server_state=self.server_state,
                on_connection_lost=self.on_connection_lost
            )
            protocol.connection_made(self.transport)
            protocol.data_received(b"".join(output))
            self.transport.set_protocol(protocol)
        elif upgrade_value == b"h2c":
            self.connections.discard(self)
            self.transport.write(
                self.conn.send(
                    h11.InformationalResponse(
                        status_code=101,
                        headers=self.headers
                    )
                )
            )
            protocol = self.h2_protocol_class(
                config=self.config,
                server_state=self.server_state,
                on_connection_lost=self.on_connection_lost,
                _loop=self.loop
            )
            protocol.handle_upgrade_from_h11(self.transport, event, self.headers)
            self.transport.set_protocol(protocol)
        else:
            msg = "Unsupported upgrade request."
            self.logger.warning(msg)
            reason = STATUS_PHRASES[400]
            headers = [
                (b"content-type", b"text/plain; charset=utf-8"),
                (b"connection", b"close"),
            ]
            event = h11.Response(status_code=400, headers=headers, reason=reason)
            output = self.conn.send(event)
            self.transport.write(output)
            event = h11.Data(data=b"Unsupported upgrade request.")
            output = self.conn.send(event)
            self.transport.write(output)
            event = h11.EndOfMessage()
            output = self.conn.send(event)
            self.transport.write(output)
            self.transport.close()
コード例 #16
0
 async def _read(self):
     if self.conn.they_are_waiting_for_100_continue:
         go_ahead = h11.InformationalResponse(status_code=100)
         await self.writer.write(go_ahead)
     try:
         data = await self.reader.read(1000000)
     except ConnectionError:
         data = b''
     self.conn.receive_data(data)
コード例 #17
0
ファイル: connection.py プロジェクト: JeffBelgum/curious
 async def _read_from_peer(self):
     if self._conn.they_are_waiting_for_100_continue:
         go_ahead = h11.InformationalResponse(status_code=100, headers=self.basic_headers())
         await self.send_h11(go_ahead)
     try:
         data = await self.socket.recv(settings.MAX_RECV)
     except ConnectionError:
         data = b""
     self._conn.receive_data(data)
コード例 #18
0
ファイル: _server.py プロジェクト: mgrrx/aioros
 async def _read_from_peer(self) -> None:
     if self.conn.they_are_waiting_for_100_continue:
         go_ahead = h11.InformationalResponse(status_code=100,
                                              headers=self.basic_headers())
         await self.send(go_ahead)
     try:
         data = await self.stream.receive(MAX_RECV)
     except (ConnectionError, EndOfStream):
         data = b""
     self.conn.receive_data(data)
コード例 #19
0
 async def _read(self):
     if self.conn.they_are_waiting_for_100_continue:
         go_ahead = h11.InformationalResponse(
             status_code=100, headers=self.server.create_headers())
         await self.send(go_ahead)
     try:
         data = await self.sock.recv(self.server.max_recv)
     except ConnectionError:
         data = b''
     self.conn.receive_data(data)
コード例 #20
0
 async def _read_from_peer(self):
     if self.conn.they_are_waiting_for_100_continue:
         go_ahead = h11.InformationalResponse(status_code=100,
                                              headers=self.basic_headers())
         await self.send(go_ahead)
     try:
         data = await self.sock.recv(MAX_RECV)
     except ConnectionError:
         # They've stopped listening. Not much we can do about it here.
         data = b""
     self.conn.receive_data(data)
コード例 #21
0
ファイル: test_server.py プロジェクト: repo-forker/wsproto
def test_handshake() -> None:
    response, nonce = _make_handshake([])

    response.headers = sorted(response.headers)  # For test determinism
    assert response == h11.InformationalResponse(
        status_code=101,
        headers=[
            (b"connection", b"Upgrade"),
            (b"sec-websocket-accept", generate_accept_token(nonce)),
            (b"upgrade", b"WebSocket"),
        ],
    )
コード例 #22
0
    def accept(self, event, subprotocol=None):
        request = event.h11request
        request_headers = _normed_header_dict(request.headers)

        nonce = request_headers[b'sec-websocket-key']
        accept_token = self._generate_accept_token(nonce)

        headers = {
            b"Upgrade": b'WebSocket',
            b"Connection": b'Upgrade',
            b"Sec-WebSocket-Accept": accept_token,
        }

        if subprotocol is not None:
            if subprotocol not in event.proposed_subprotocols:
                raise ValueError(
                    "unexpected subprotocol {!r}".format(subprotocol))
            headers[b'Sec-WebSocket-Protocol'] = subprotocol

        extensions = request_headers.get(b'sec-websocket-extensions', None)
        accepts = {}
        if extensions is not None:
            offers = _split_comma_header(extensions)

            for offer in offers:
                offer = offer.decode('ascii')
                name = offer.split(';', 1)[0].strip()
                for extension in self.extensions:
                    if extension.name == name:
                        accept = extension.accept(self, offer)
                        if accept is True:
                            accepts[extension.name] = True
                        elif accept:
                            accepts[extension.name] = accept.encode('ascii')

        if accepts:
            extensions = []
            for name, params in accepts.items():
                if params is True:
                    extensions.append(name.encode('ascii'))
                else:
                    # py34 annoyance: doesn't support bytestring formatting
                    params = params.decode("ascii")
                    extensions.append(
                        ('%s; %s' % (name, params)).encode("ascii"))
            headers[b"Sec-WebSocket-Extensions"] = b', '.join(extensions)

        response = h11.InformationalResponse(status_code=101,
                                             headers=headers.items())
        self._outgoing += self._upgrade_connection.send(response)
        self._proto = FrameProtocol(self.client, self.extensions)
        self._state = ConnectionState.OPEN
コード例 #23
0
ファイル: h11.py プロジェクト: tharvik/quart
 def _handle_upgrade_request(self, headers: CIMultiDict, event: h11.Request) -> None:
     self._timeout_handle.cancel()
     connection_tokens = headers.get('connection', '').lower().split(',')
     if (
             any(token == 'upgrade' for token in connection_tokens) and
             headers.get('upgrade', '').lower() == 'websocket'
     ):
         raise WebsocketProtocolRequired(event)
     elif headers.get('upgrade', '').lower() == 'h2c':
         self._send(h11.InformationalResponse(
             status_code=101, headers=[('upgrade', 'h2c')] + self.response_headers(),
         ))
         raise H2CProtocolRequired(event)
     else:
         self._handle_error()
         self.close()
コード例 #24
0
ファイル: handshake_utils.py プロジェクト: theelous3/noio_ws
 def server_handshake(self, subprotocols=None, extensions=None, **kwargs):
     headers = {
         'upgrade': 'websocket',
         'connection': 'upgrade',
         'sec-websocket-accept': secondary_nonce_creator(self.nonce),
         'sec-websocket-version': '13'
     }
     if subprotocols:
         headers['sec-websocket-protocol'] = self._addon_header_str_ifier(
             self.subprotocols)
     if extensions:
         headers['sec-websocket-extensions'] = self._addon_header_str_ifier(
             self.extensions)
     if kwargs:
         headers.update(kwargs)
     return h11.InformationalResponse(status_code=101,
                                      reason='Switching Protocols',
                                      headers=headers.items())
コード例 #25
0
ファイル: connection.py プロジェクト: JeffBelgum/curious
    async def from_h11_connection(cls, h11_conn, upgrade_settings):
        """
        Take a h11 connection and complete the upgrade
        Returns an initiated h2 connection.
        """

        # Finish h11 part of the connection
        resp = h11.InformationalResponse(
            status_code=101,
            headers=[("Upgrade", "h2c")],
        )
        await h11_conn.send(resp)

        instance = cls(h11_conn.socket)
        instance._conn.initiate_upgrade_connection(settings_header=upgrade_settings)
        await instance.sendall()

        return instance
コード例 #26
0
    def accept(self, event):
        request = event.h11request
        request_headers = dict(request.headers)

        nonce = request_headers[b'sec-websocket-key']
        accept_token = self._generate_accept_token(nonce)

        headers = {
            b"Upgrade": b'WebSocket',
            b"Connection": b'Upgrade',
            b"Sec-WebSocket-Accept": accept_token,
            b"Sec-WebSocket-Version": self.version,
        }

        extensions = request_headers.get(b'sec-websocket-extensions', None)
        accepts = {}
        if extensions:
            offers = [e.strip() for e in extensions.split(b',')]

            for offer in offers:
                offer = offer.decode('ascii')
                name = offer.split(';', 1)[0].strip()
                for extension in self.extensions:
                    if extension.name == name:
                        accept = extension.accept(self, offer)
                        if accept is True:
                            accepts[extension.name] = True
                        elif accept:
                            accepts[extension.name] = accept.encode('ascii')

        if accepts:
            extensions = []
            for name, params in accepts.items():
                name = name.encode('ascii')
                if params is True:
                    extensions.append(name)
                else:
                    extensions.append(b'%s; %s' % (name, params))
            headers[b"Sec-WebSocket-Extensions"] = b', '.join(extensions)

        response = h11.InformationalResponse(status_code=101,
                                             headers=headers.items())
        self._outgoing += self._upgrade_connection.send(response)
        self._state = ConnectionState.OPEN
コード例 #27
0
ファイル: handshake.py プロジェクト: Y-Zhang-0/code
    def _accept(self, event: AcceptConnection) -> bytes:
        # _accept is always called after _process_connection_request.
        assert self._initiating_request is not None
        request_headers = normed_header_dict(
            self._initiating_request.extra_headers)

        nonce = request_headers[b"sec-websocket-key"]
        accept_token = generate_accept_token(nonce)

        headers = [
            (b"Upgrade", b"WebSocket"),
            (b"Connection", b"Upgrade"),
            (b"Sec-WebSocket-Accept", accept_token),
        ]

        if event.subprotocol is not None:
            if event.subprotocol not in self._initiating_request.subprotocols:
                raise LocalProtocolError(
                    f"unexpected subprotocol {event.subprotocol}")
            headers.append(
                (b"Sec-WebSocket-Protocol", event.subprotocol.encode("ascii")))

        if event.extensions:
            accepts = server_extensions_handshake(
                cast(Sequence[str], self._initiating_request.extensions),
                event.extensions,
            )
            if accepts:
                headers.append((b"Sec-WebSocket-Extensions", accepts))

        response = h11.InformationalResponse(status_code=101,
                                             headers=headers +
                                             event.extra_headers)
        self._connection = Connection(
            ConnectionType.CLIENT if self.client else ConnectionType.SERVER,
            event.extensions,
        )
        self._state = ConnectionState.OPEN
        return self._h11_connection.send(response)
コード例 #28
0
ファイル: h11.py プロジェクト: yunstanford/quart
 def _handle_upgrade_request(self, headers: CIMultiDict,
                             event: h11.Request) -> None:
     self._keep_alive_timeout_handle.cancel()
     connection_tokens = headers.get('connection', '').lower().split(',')
     if (any(token.strip() == 'upgrade' for token in connection_tokens)
             and headers.get('upgrade', '').lower() == 'websocket'
             and event.method.decode().upper() == 'GET'):
         raise WebsocketProtocolRequired(event)
     # h2c Upgrade requests with a body are a pain as the body must
     # be fully recieved in HTTP/1.1 before the upgrade response
     # and HTTP/2 takes over, so Quart ignores the upgrade and
     # responds in HTTP/1.1. Use a preflight OPTIONS request to
     # initiate the upgrade if really required (or just use h2).
     elif (headers.get('upgrade', '').lower() == 'h2c'
           and 'Content-Length' not in headers
           and 'Transfer-Encoding' not in headers):
         self._send(
             h11.InformationalResponse(
                 status_code=101,
                 headers=[('upgrade', 'h2c')] + self.response_headers(),
             ), )
         raise H2CProtocolRequired(event)
コード例 #29
0
    def maybe_upgrade_request(self, event: h11.Request) -> None:
        upgrade_value = ''
        connection_value = ''
        has_body = False
        for name, value in event.headers:
            sanitised_name = name.decode().lower()
            if sanitised_name == 'upgrade':
                upgrade_value = value.decode().strip()
            elif sanitised_name == 'connection':
                connection_value = value.decode().strip()
            elif sanitised_name == 'content-length':
                has_body = True
            elif sanitised_name == 'transfer-encoding':
                has_body = True

        connection_tokens = connection_value.lower().split(',')
        if (
                any(token.strip() == 'upgrade' for token in connection_tokens) and
                upgrade_value.lower() == 'websocket' and
                event.method.decode().upper() == 'GET'
        ):
            self.stop_keep_alive_timeout()
            raise WebsocketProtocolRequired(event)
        # h2c Upgrade requests with a body are a pain as the body must
        # be fully recieved in HTTP/1.1 before the upgrade response
        # and HTTP/2 takes over, so Hypercorn ignores the upgrade and
        # responds in HTTP/1.1. Use a preflight OPTIONS request to
        # initiate the upgrade if really required (or just use h2).
        elif upgrade_value.lower() == 'h2c' and not has_body:
            self.stop_keep_alive_timeout()
            self.send(
                h11.InformationalResponse(
                    status_code=101, headers=[(b'upgrade', b'h2c')] + self.response_headers(),
                ),
            )
            raise H2CProtocolRequired(event)
コード例 #30
0
 def handle_events(self) -> None:
     while True:
         if self.connection.they_are_waiting_for_100_continue:
             self.send(
                 h11.InformationalResponse(status_code=100, headers=self.response_headers()),
             )
         try:
             event = self.connection.next_event()
         except h11.RemoteProtocolError:
             self.handle_error()
             self.close()
             break
         else:
             if isinstance(event, h11.Request):
                 self.maybe_upgrade_request(event)  # Raises on upgrade
                 self.handle_request(event)
             elif isinstance(event, h11.EndOfMessage):
                 self.app_queue.put_nowait({
                     'type': 'http.request',
                     'body': b'',
                     'more_body': False,
                 })
             elif isinstance(event, h11.Data):
                 self.app_queue.put_nowait({
                     'type': 'http.request',
                     'body': event.data,
                     'more_body': True,
                 })
             elif (
                     isinstance(event, h11.ConnectionClosed)
                     or event is h11.NEED_DATA
                     or event is h11.PAUSED
             ):
                 break
     if self.connection.our_state is h11.MUST_CLOSE:
         self.close()