mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-18 17:33:30 -05:00
fix: retry a file list the network cut short
This commit is contained in:
1 parent
cf596c92b6
commit
02fcb54d9d
4 files changed
+51
-9
No files matched your search
+1
-1
@@ -8,7 +8,7 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "546d190d17449d7b25bcf981bd396645c194364f363a2d315380a043ca101e38"
|
||||
$defaultInstallSha256 = "e57aa03a8f581b6bf02cb1d3161af6da19719425383790da0ed5f761afaf436c"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+20
-7
@@ -1257,18 +1257,31 @@ def normalize_platform(name: str) -> str:
|
||||
def _read_limited_json(
|
||||
response: http.client.HTTPResponse, limit: int, label: str
|
||||
) -> object:
|
||||
"""Read a bounded UTF-8 JSON response."""
|
||||
"""Read a bounded UTF-8 JSON response.
|
||||
|
||||
A body shorter than its Content-Length is a dropped connection, raised
|
||||
as one so the caller retries: parsed, the cut read as an invalid file
|
||||
list and the run ended without the network advice.
|
||||
"""
|
||||
raw_length = response.headers.get("Content-Length") if response.headers else None
|
||||
expected: int | None = None
|
||||
if raw_length:
|
||||
try:
|
||||
if int(raw_length) > limit:
|
||||
raise ValueError(f"{label} exceeds {limit} bytes")
|
||||
except ValueError as exc:
|
||||
if "exceeds" in str(exc):
|
||||
raise
|
||||
payload = response.read(limit + 1)
|
||||
expected = int(raw_length)
|
||||
except ValueError:
|
||||
expected = None
|
||||
if expected is not None and expected > limit:
|
||||
raise ValueError(f"{label} exceeds {limit} bytes")
|
||||
try:
|
||||
payload = response.read(limit + 1)
|
||||
except http.client.IncompleteRead as exc:
|
||||
raise ConnectionError(
|
||||
f"{label} cut after {len(exc.partial)} bytes"
|
||||
) from exc
|
||||
if len(payload) > limit:
|
||||
raise ValueError(f"{label} exceeds {limit} bytes")
|
||||
if expected is not None and len(payload) < expected:
|
||||
raise ConnectionError(f"{label} cut after {len(payload)} of {expected} bytes")
|
||||
try:
|
||||
return json.loads(payload.decode("utf-8"))
|
||||
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ esac
|
||||
TEMP_INSTALLER=""
|
||||
TEMP_DIRECTORY=""
|
||||
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
DEFAULT_INSTALL_SHA256="546d190d17449d7b25bcf981bd396645c194364f363a2d315380a043ca101e38"
|
||||
DEFAULT_INSTALL_SHA256="e57aa03a8f581b6bf02cb1d3161af6da19719425383790da0ed5f761afaf436c"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -2446,5 +2446,34 @@ class QuitMeansNoAtTheLastQuestion(unittest.TestCase):
|
||||
self.assertIs(install._confirm("? "), expected)
|
||||
|
||||
|
||||
|
||||
class ACutFileListIsRetried(unittest.TestCase):
|
||||
"""Wi-Fi dropped mid install/batocera.json: the short body parsed as an
|
||||
invalid file list, no retry, no network advice."""
|
||||
|
||||
class _Response(io.BytesIO):
|
||||
def __init__(self, body: bytes, length: int):
|
||||
super().__init__(body)
|
||||
self.headers = {"Content-Length": str(length)}
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
return False
|
||||
|
||||
def test_the_second_attempt_succeeds(self):
|
||||
full = json.dumps({"a": 1}).encode()
|
||||
answers = iter([self._Response(full[:4], len(full)), self._Response(full, len(full))])
|
||||
with unittest.mock.patch.object(install.urllib.request, "urlopen",
|
||||
lambda *a, **k: next(answers)), \
|
||||
unittest.mock.patch.object(install.time, "sleep"):
|
||||
self.assertEqual(install._fetch_json("https://x/y.json", 1000, "manifest"), {"a": 1})
|
||||
|
||||
def test_a_short_body_is_a_connection_error(self):
|
||||
with self.assertRaises(ConnectionError):
|
||||
install._read_limited_json(self._Response(b'{"a"', 10), 1000, "manifest")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user