(
url: str,
*,
max_bytes: int,
max_redirects: int = 5,
timeout: tuple[float, float] = DEFAULT_FETCH_TIMEOUT,
)
| 97 | |
| 98 | |
| 99 | def fetch_public_http_resource( |
| 100 | url: str, |
| 101 | *, |
| 102 | max_bytes: int, |
| 103 | max_redirects: int = 5, |
| 104 | timeout: tuple[float, float] = DEFAULT_FETCH_TIMEOUT, |
| 105 | ) -> HttpFetchResult: |
| 106 | current_url = url |
| 107 | session = requests.Session() |
| 108 | session.trust_env = False |
| 109 | |
| 110 | for redirect_count in range(max_redirects + 1): |
| 111 | validate_public_http_url(current_url) |
| 112 | |
| 113 | try: |
| 114 | with session.get( |
| 115 | current_url, |
| 116 | stream=True, |
| 117 | allow_redirects=False, |
| 118 | headers=_build_request_headers(), |
| 119 | timeout=timeout, |
| 120 | ) as response: |
| 121 | if 300 <= response.status_code < 400: |
| 122 | location = response.headers.get("Location") |
| 123 | if not location: |
| 124 | raise ValueError( |
| 125 | f"Remote URL redirect is missing a Location header: {current_url}" |
| 126 | ) |
| 127 | if redirect_count >= max_redirects: |
| 128 | raise ValueError( |
| 129 | f"Remote URL exceeded redirect limit ({max_redirects}): {url}" |
| 130 | ) |
| 131 | current_url = urljoin(current_url, location) |
| 132 | continue |
| 133 | |
| 134 | if response.status_code >= 400: |
| 135 | raise ValueError( |
| 136 | f"Remote URL returned HTTP {response.status_code}: {current_url}" |
| 137 | ) |
| 138 | |
| 139 | content_length = response.headers.get("Content-Length") |
| 140 | if content_length: |
| 141 | try: |
| 142 | declared_length = int(content_length) |
| 143 | except ValueError: |
| 144 | declared_length = None |
| 145 | if declared_length is not None and declared_length > max_bytes: |
| 146 | raise ValueError( |
| 147 | f"Remote document exceeds max size {max_bytes} bytes: {current_url}" |
| 148 | ) |
| 149 | |
| 150 | body = bytearray() |
| 151 | for chunk in response.iter_content(chunk_size=64 * 1024): |
| 152 | if not chunk: |
| 153 | continue |
| 154 | body.extend(chunk) |
| 155 | if len(body) > max_bytes: |
| 156 | raise ValueError( |
nothing calls this directly
no test coverage detected