Example #1
0
 def patched_receive_handshake_data(
     self, data
 ) -> layer.CommandGenerator[typing.Tuple[bool, typing.Optional[str]]]:
     self.buf += data
     response_head = self.buf.maybe_extract_lines()
     if response_head:
         response_head = [bytes(x) for x in response_head]
         try:
             response = http1.read_response_head(response_head)
         except ValueError:
             return True, None
         challenge_message = extract_proxy_authenticate_msg(
             response_head)
         if 200 <= response.status_code < 300:
             if self.buf:
                 yield from self.receive_data(data)
                 del self.buf
             return True, None
         else:
             if not challenge_message:
                 return True, None
             proxy_authorization = self.ntlm_context.get_ntlm_challenge_response_message(
                 challenge_message)
             self.flow = build_connect_flow(
                 self.context,
                 ("Proxy-Authorization", proxy_authorization))
             raw = http1.assemble_request(self.flow.request)
             yield commands.SendData(self.tunnel_connection, raw)
             return False, None
     else:
         return False, None
Example #2
0
 def receive_handshake_data(
         self,
         data: bytes) -> layer.CommandGenerator[Tuple[bool, Optional[str]]]:
     if not self.send_connect:
         return (yield from super().receive_handshake_data(data))
     self.buf += data
     response_head = self.buf.maybe_extract_lines()
     if response_head:
         response_head = [
             bytes(x) for x in response_head
         ]  # TODO: Make url.parse compatible with bytearrays
         try:
             response = http1.read_response_head(response_head)
         except ValueError as e:
             yield commands.Log(
                 f"{human.format_address(self.tunnel_connection.address)}: {e}"
             )
             return False, str(e)
         if 200 <= response.status_code < 300:
             if self.buf:
                 yield from self.receive_data(bytes(self.buf))
                 del self.buf
             return True, None
         else:
             raw_resp = b"\n".join(response_head)
             yield commands.Log(
                 f"{human.format_address(self.tunnel_connection.address)}: {raw_resp!r}",
                 level="debug")
             return False, f"{response.status_code} {response.reason}"
     else:
         return False, None
Example #3
0
    def read_headers(
            self,
            event: events.ConnectionEvent) -> layer.CommandGenerator[None]:
        if isinstance(event, events.DataReceived):
            if not self.request:
                # we just received some data for an unknown request.
                yield commands.Log(
                    f"Unexpected data from server: {bytes(self.buf)!r}")
                yield commands.CloseConnection(self.conn)
                return
            assert self.stream_id

            response_head = self.buf.maybe_extract_lines()
            if response_head:
                response_head = [
                    bytes(x) for x in response_head
                ]  # TODO: Make url.parse compatible with bytearrays
                try:
                    self.response = http1.read_response_head(response_head)
                    if self.context.options.validate_inbound_headers:
                        http1.validate_headers(self.response.headers)
                    expected_size = http1.expected_http_body_size(
                        self.request, self.response)
                except ValueError as e:
                    yield commands.CloseConnection(self.conn)
                    yield ReceiveHttp(
                        ResponseProtocolError(
                            self.stream_id,
                            f"Cannot parse HTTP response: {e}"))
                    return
                yield ReceiveHttp(
                    ResponseHeaders(self.stream_id, self.response,
                                    expected_size == 0))
                self.body_reader = make_body_reader(expected_size)

                self.state = self.read_body
                yield from self.state(event)
            else:
                pass  # FIXME: protect against header size DoS
        elif isinstance(event, events.ConnectionClosed):
            if self.conn.state & ConnectionState.CAN_WRITE:
                yield commands.CloseConnection(self.conn)
            if self.stream_id:
                if self.buf:
                    yield ReceiveHttp(
                        ResponseProtocolError(
                            self.stream_id,
                            f"unexpected server response: {bytes(self.buf)!r}")
                    )
                else:
                    # The server has closed the connection to prevent us from continuing.
                    # We need to signal that to the stream.
                    # https://tools.ietf.org/html/rfc7231#section-6.5.11
                    yield ReceiveHttp(
                        ResponseProtocolError(self.stream_id,
                                              "server closed connection"))
            else:
                return
        else:
            raise AssertionError(f"Unexpected event: {event}")
Example #4
0
    def test_stream_chunked(self):
        connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        connection.connect(("127.0.0.1", self.proxy.port))
        fconn = connection.makefile("rb")
        spec = '200:h"Transfer-Encoding"="chunked":r:b"4\\r\\nthis\\r\\n11\\r\\nisatest__reachhex\\r\\n0\\r\\n\\r\\n"'
        connection.send(b"GET %s/p/%s HTTP/1.1\r\n" %
                        (self.server.urlbase.encode(), spec.encode()))
        connection.send(b"\r\n")

        resp = http1.read_response_head(fconn)

        assert resp.headers["Transfer-Encoding"] == 'chunked'
        assert resp.status_code == 200

        chunks = list(http1.read_body(fconn, None))
        assert chunks == [b"this", b"isatest__reachhex"]

        connection.close()
Example #5
0
    def test_stream_chunked(self):
        connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        connection.connect(("127.0.0.1", self.proxy.port))
        fconn = connection.makefile("rb")
        spec = '200:h"Transfer-Encoding"="chunked":r:b"4\\r\\nthis\\r\\n11\\r\\nisatest__reachhex\\r\\n0\\r\\n\\r\\n"'
        connection.send(
            b"GET %s/p/%s HTTP/1.1\r\n" %
            (self.server.urlbase.encode(), spec.encode()))
        connection.send(b"\r\n")

        resp = http1.read_response_head(fconn)

        assert resp.headers["Transfer-Encoding"] == 'chunked'
        assert resp.status_code == 200

        chunks = list(http1.read_body(fconn, None))
        assert chunks == [b"this", b"isatest__reachhex"]

        connection.close()
Example #6
0
 def read_response_headers(self):
     resp = http1.read_response_head(self.server_conn.rfile)
     return http.HTTPResponse.wrap(resp)
Example #7
0
 def read_response_headers(self):
     return http1.read_response_head(self.server_conn.rfile)
Example #8
0
 def read_response_headers(self):
     resp = http1.read_response_head(self.server_conn.rfile)
     return http.HTTPResponse.wrap(resp)