Determine whether a connection error is a redirect that can be followed. Return the new URI if it's a valid redirect. Else, return an exception.
(self, exc: Exception)
| 471 | return connection |
| 472 | |
| 473 | def process_redirect(self, exc: Exception) -> Exception | str: |
| 474 | """ |
| 475 | Determine whether a connection error is a redirect that can be followed. |
| 476 | |
| 477 | Return the new URI if it's a valid redirect. Else, return an exception. |
| 478 | |
| 479 | """ |
| 480 | if not ( |
| 481 | isinstance(exc, InvalidStatus) |
| 482 | and exc.response.status_code |
| 483 | in [ |
| 484 | 300, # Multiple Choices |
| 485 | 301, # Moved Permanently |
| 486 | 302, # Found |
| 487 | 303, # See Other |
| 488 | 307, # Temporary Redirect |
| 489 | 308, # Permanent Redirect |
| 490 | ] |
| 491 | and "Location" in exc.response.headers |
| 492 | ): |
| 493 | return exc |
| 494 | |
| 495 | old_ws_uri = parse_uri(self.uri) |
| 496 | new_uri = urllib.parse.urljoin(self.uri, exc.response.headers["Location"]) |
| 497 | new_ws_uri = parse_uri(new_uri) |
| 498 | |
| 499 | # If connect() received a socket, it is closed and cannot be reused. |
| 500 | if self.connection_kwargs.get("sock") is not None: |
| 501 | return ValueError( |
| 502 | f"cannot follow redirect to {new_uri} with a preexisting socket" |
| 503 | ) |
| 504 | |
| 505 | # TLS downgrade is forbidden. |
| 506 | if old_ws_uri.secure and not new_ws_uri.secure: |
| 507 | return SecurityError(f"cannot follow redirect to non-secure URI {new_uri}") |
| 508 | |
| 509 | # Apply restrictions to cross-origin redirects. |
| 510 | if ( |
| 511 | old_ws_uri.secure != new_ws_uri.secure |
| 512 | or old_ws_uri.host != new_ws_uri.host |
| 513 | or old_ws_uri.port != new_ws_uri.port |
| 514 | ): |
| 515 | # Cross-origin redirects on Unix sockets don't quite make sense. |
| 516 | if self.connection_kwargs.get("unix", False): |
| 517 | return ValueError( |
| 518 | f"cannot follow cross-origin redirect to {new_uri} " |
| 519 | f"with a Unix socket" |
| 520 | ) |
| 521 | |
| 522 | # Cross-origin redirects when host and port are overridden are ill-defined. |
| 523 | if ( |
| 524 | self.connection_kwargs.get("host") is not None |
| 525 | or self.connection_kwargs.get("port") is not None |
| 526 | ): |
| 527 | return ValueError( |
| 528 | f"cannot follow cross-origin redirect to {new_uri} " |
| 529 | f"with an explicit host or port" |
| 530 | ) |
no test coverage detected