| 251 | # https://github.com/python/cpython/commit/0d4026432591d43185568dd31cef6a034c4b9261 |
| 252 | # and https://github.com/python/cpython/commit/6fbc61070fda2ffb8889e77e3b24bca4249ab4d1 |
| 253 | def _tunnel(self) -> None: |
| 254 | _MAXLINE = http.client._MAXLINE # type: ignore[attr-defined] |
| 255 | connect = b"CONNECT %s:%d HTTP/1.0\r\n" % ( # type: ignore[str-format] |
| 256 | self._wrap_ipv6(self._tunnel_host.encode("ascii")), # type: ignore[union-attr] |
| 257 | self._tunnel_port, |
| 258 | ) |
| 259 | headers = [connect] |
| 260 | for header, value in self._tunnel_headers.items(): # type: ignore[attr-defined] |
| 261 | headers.append(f"{header}: {value}\r\n".encode("latin-1")) |
| 262 | headers.append(b"\r\n") |
| 263 | # Making a single send() call instead of one per line encourages |
| 264 | # the host OS to use a more optimal packet size instead of |
| 265 | # potentially emitting a series of small packets. |
| 266 | self.send(b"".join(headers)) |
| 267 | del headers |
| 268 | |
| 269 | response = self.response_class(self.sock, method=self._method) # type: ignore[attr-defined] |
| 270 | try: |
| 271 | (version, code, message) = response._read_status() # type: ignore[attr-defined] |
| 272 | |
| 273 | if code != http.HTTPStatus.OK: |
| 274 | self.close() |
| 275 | raise OSError( |
| 276 | f"Tunnel connection failed: {code} {message.strip()}" |
| 277 | ) |
| 278 | while True: |
| 279 | line = response.fp.readline(_MAXLINE + 1) |
| 280 | if len(line) > _MAXLINE: |
| 281 | raise http.client.LineTooLong("header line") |
| 282 | if not line: |
| 283 | # for sites which EOF without sending a trailer |
| 284 | break |
| 285 | if line in (b"\r\n", b"\n", b""): |
| 286 | break |
| 287 | |
| 288 | if self.debuglevel > 0: |
| 289 | print("header:", line.decode()) |
| 290 | finally: |
| 291 | response.close() |
| 292 | |
| 293 | elif (3, 12) <= sys.version_info < (3, 12, 3): |
| 294 | # `_tunnel` copied from 3.12.11 backporting |