MCPcopy Index your code
hub / github.com/mitmproxy/mitmproxy / Http1Client

Class Http1Client

mitmproxy/proxy/layers/http/_http1.py:339–462  ·  view source on GitHub ↗

A simple HTTP/1 client with no pipelining support.

Source from the content-addressed store, hash-verified

337
338
339class Http1Client(Http1Connection):
340 """A simple HTTP/1 client with no pipelining support."""
341
342 ReceiveProtocolError = ResponseProtocolError
343 ReceiveData = ResponseData
344 ReceiveEndOfMessage = ResponseEndOfMessage
345
346 def __init__(self, context: Context):
347 super().__init__(context, context.server)
348
349 def send(self, event: HttpEvent) -> layer.CommandGenerator[None]:
350 if isinstance(event, RequestProtocolError):
351 yield commands.CloseConnection(self.conn)
352 return
353
354 if self.stream_id is None:
355 assert isinstance(event, RequestHeaders)
356 self.stream_id = event.stream_id
357 self.request = event.request
358 assert self.stream_id == event.stream_id
359
360 if isinstance(event, RequestHeaders):
361 request = event.request
362 if request.is_http2 or request.is_http3:
363 # Convert to an HTTP/1 request.
364 request = (
365 request.copy()
366 ) # (we could probably be a bit more efficient here.)
367 request.http_version = "HTTP/1.1"
368 if "Host" not in request.headers and request.authority:
369 request.headers.insert(0, "Host", request.authority)
370 request.authority = ""
371 cookie_headers = request.headers.get_all("Cookie")
372 if len(cookie_headers) > 1:
373 # Only HTTP/2 supports multiple cookie headers, HTTP/1.x does not.
374 # see: https://www.rfc-editor.org/rfc/rfc6265#section-5.4
375 # https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2.5
376 request.headers["Cookie"] = "; ".join(cookie_headers)
377 raw = http1.assemble_request_head(request)
378 yield commands.SendData(self.conn, raw)
379 elif isinstance(event, RequestData):
380 assert self.request
381 if "chunked" in self.request.headers.get("transfer-encoding", "").lower():
382 raw = b"%x\r\n%s\r\n" % (len(event.data), event.data)
383 else:
384 raw = event.data
385 if raw:
386 yield commands.SendData(self.conn, raw)
387 elif isinstance(event, RequestEndOfMessage):
388 assert self.request
389 if "chunked" in self.request.headers.get("transfer-encoding", "").lower():
390 yield commands.SendData(self.conn, b"0\r\n\r\n")
391 elif http1.expected_http_body_size(self.request, self.response) == -1:
392 yield commands.CloseTcpConnection(self.conn, half_close=True)
393 yield from self.mark_done(request=True)
394 else:
395 raise AssertionError(f"Unexpected event: {event}")
396

Callers 6

test_simpleMethod · 0.90
test_connectMethod · 0.90
test_upgradeMethod · 0.90
test_upgrade_deniedMethod · 0.90
_handle_eventMethod · 0.85
_handle_eventMethod · 0.85

Calls

no outgoing calls

Tested by 4

test_simpleMethod · 0.72
test_connectMethod · 0.72
test_upgradeMethod · 0.72
test_upgrade_deniedMethod · 0.72

Used in the wild real call sites across dependent graphs

searching dependent graphs…