def event_to_child(self, event: events.Event) -> layer.CommandGenerator[None]: if self.tunnel_state is TunnelState.ESTABLISHING and not self.command_to_reply_to: self._event_queue.append(event) return for command in self.child_layer.handle_event(event): if isinstance(command, commands.ConnectionCommand ) and command.connection == self.conn: if isinstance(command, commands.SendData): yield from self.send_data(command.data) elif isinstance(command, commands.CloseConnection): if self.conn != self.tunnel_connection: if command.half_close: self.conn.state &= ~context.ConnectionState.CAN_WRITE else: self.conn.state = context.ConnectionState.CLOSED yield from self.send_close(command.half_close) elif isinstance(command, commands.OpenConnection): # create our own OpenConnection command object that blocks here. self.command_to_reply_to = command self.tunnel_state = TunnelState.ESTABLISHING err = yield commands.OpenConnection(self.tunnel_connection) if err: yield from self.event_to_child( events.OpenConnectionReply(command, err)) self.tunnel_state = TunnelState.CLOSED else: yield from self.start_handshake() else: # pragma: no cover raise AssertionError(f"Unexpected command: {command}") else: yield command
def handle_connect_regular(self): if not self.flow.response and self.context.options.connection_strategy == "eager": err = yield commands.OpenConnection(self.context.server) if err: self.flow.response = http.HTTPResponse.make( 502, f"Cannot connect to {human.format_address(self.context.server.address)}: {err}" ) self.child_layer = layer.NextLayer(self.context) yield from self.handle_connect_finish()
def start_server_tls(self) -> layer.CommandGenerator[Optional[str]]: """ We often need information from the upstream connection to establish TLS with the client. For example, we need to check if the client does ALPN or not. """ if not self.server_tls_available: return "No server TLS available." err = yield commands.OpenConnection(self.context.server) return err
def finish_start(self): if self.context.options.connection_strategy == "eager": err = yield commands.OpenConnection(self.context.server) if err: yield commands.CloseConnection(self.context.client) self._handle_event = self.done return self._handle_event = self.child_layer.handle_event yield from self.child_layer.handle_event(events.Start())
def start(self, _) -> layer.CommandGenerator[None]: if self.flow: yield TcpStartHook(self.flow) if not self.context.server.connected: err = yield commands.OpenConnection(self.context.server) if err: if self.flow: self.flow.error = flow.Error(str(err)) yield TcpErrorHook(self.flow) yield commands.CloseConnection(self.context.client) self._handle_event = self.done return self._handle_event = self.relay_messages
def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: err: Optional[str] if self.context.server.connected: err = None else: err = yield commands.OpenConnection(self.context.server) if not err: child_layer: layer.Layer if self.context.server.alpn == b"h2": child_layer = Http2Client(self.context) else: child_layer = Http1Client(self.context) self._handle_event = child_layer.handle_event yield from self._handle_event(event) yield RegisterHttpConnection(self.context.server, err)
def test_dataclasses(tconn): assert repr(commands.SendData(tconn, b"foo")) assert repr(commands.OpenConnection(tconn)) assert repr(commands.CloseConnection(tconn)) assert repr(commands.GetSocket(tconn)) assert repr(commands.Log("hello", "info"))