ConnectionEvent: We have received b"GET /\r\n\r\n" from the client. HttpEvent: We have received request headers HttpCommand: Send request headers to X ConnectionCommand: Send b"GET /\r\n\r\n" to server. ConnectionEvent -> HttpEvent -> HttpCommand -> ConnectionCommand
| 919 | |
| 920 | |
| 921 | class HttpLayer(layer.Layer): |
| 922 | """ |
| 923 | ConnectionEvent: We have received b"GET /\r\n\r\n" from the client. |
| 924 | HttpEvent: We have received request headers |
| 925 | HttpCommand: Send request headers to X |
| 926 | ConnectionCommand: Send b"GET /\r\n\r\n" to server. |
| 927 | |
| 928 | ConnectionEvent -> HttpEvent -> HttpCommand -> ConnectionCommand |
| 929 | """ |
| 930 | |
| 931 | mode: HTTPMode |
| 932 | command_sources: dict[commands.Command, layer.Layer] |
| 933 | streams: dict[int, HttpStream] |
| 934 | connections: dict[Connection, layer.Layer] |
| 935 | waiting_for_establishment: collections.defaultdict[ |
| 936 | Connection, list[GetHttpConnection] |
| 937 | ] |
| 938 | |
| 939 | def __init__(self, context: Context, mode: HTTPMode): |
| 940 | super().__init__(context) |
| 941 | self.mode = mode |
| 942 | |
| 943 | self.waiting_for_establishment = collections.defaultdict(list) |
| 944 | self.streams = {} |
| 945 | self.command_sources = {} |
| 946 | self.connections = {} |
| 947 | |
| 948 | def __repr__(self): |
| 949 | return f"HttpLayer({self.mode.name}, conns: {len(self.connections)})" |
| 950 | |
| 951 | def _handle_event(self, event: events.Event): |
| 952 | if isinstance(event, events.Start): |
| 953 | http_conn: HttpConnection |
| 954 | if is_h3_alpn(self.context.client.alpn): |
| 955 | http_conn = Http3Server(self.context.fork()) |
| 956 | elif self.context.client.alpn == b"h2": |
| 957 | http_conn = Http2Server(self.context.fork()) |
| 958 | else: |
| 959 | http_conn = Http1Server(self.context.fork()) |
| 960 | |
| 961 | # may have been set by client playback. |
| 962 | self.connections.setdefault(self.context.client, http_conn) |
| 963 | yield from self.event_to_child(self.connections[self.context.client], event) |
| 964 | if self.mode is HTTPMode.upstream: |
| 965 | proxy_mode = self.context.client.proxy_mode |
| 966 | assert isinstance(proxy_mode, UpstreamMode) |
| 967 | self.context.server.via = (proxy_mode.scheme, proxy_mode.address) |
| 968 | elif isinstance(event, events.CommandCompleted): |
| 969 | stream = self.command_sources.pop(event.command) |
| 970 | yield from self.event_to_child(stream, event) |
| 971 | elif isinstance(event, events.MessageInjected): |
| 972 | # For injected messages we pass the HTTP stacks entirely and directly address the stream. |
| 973 | try: |
| 974 | conn = self.connections[event.flow.server_conn] |
| 975 | except KeyError: |
| 976 | # We have a miss for the server connection, which means we're looking at a connection object |
| 977 | # that is tunneled over another connection (for example: over an upstream HTTP proxy). |
| 978 | # We now take the stream associated with the client connection. That won't work for HTTP/2, |
no outgoing calls
no test coverage detected
searching dependent graphs…