Commit e97010147 for llama.cpp

commit e9701014703d251593b23ce1703db8a7299dad0f
Author: Pascal <admin@serveurperso.com>
Date:   Thu Nov 12 23:13:37 2026 +0100

    server: skip LAN address tests when the host cannot reach it [no ci] (#32166)

    The same-origin tests over the LAN address block forever on the Metal
    runners: the request to the host's own LAN address never returns and
    has no timeout, so the job runs until the 6h limit.

    get_lan_ip() now probes /health on that address with a short timeout
    and returns None when the host cannot reach it, which skips the test.
    The test requests themselves use the default request timeout so a
    hang fails the test instead of stalling the job.

diff --git a/tools/server/tests/unit/test_router.py b/tools/server/tests/unit/test_router.py
index e4e62086b..b5c6fcdae 100644
--- a/tools/server/tests/unit/test_router.py
+++ b/tools/server/tests/unit/test_router.py
@@ -934,24 +934,24 @@ def test_router_download_drops_stale_partials():
 def test_router_restricted_cors_same_origin_reaches_child():
     # same-origin request via LAN address must not be refused by the child
     global server
-    lan_ip = get_lan_ip()
-    if lan_ip is None:
-        pytest.skip("no non-loopback interface")  # ty: ignore[too-many-positional-arguments]
     server.cors_origins = "localhost"
     server.server_host = "0.0.0.0"
     server.start()
+    lan_ip = get_lan_ip(server)
+    if lan_ip is None:
+        pytest.skip("no LAN address reachable from this host")  # ty: ignore[too-many-positional-arguments]
     body = {
         "model": "ggml-org-dev/tinygemma3-GGUF:Q8_0",
         "max_tokens": 4,
         "messages": [{"role": "user", "content": "hello"}],
     }
-    res = requests.post(server.make_url("/chat/completions", host=lan_ip), json=body, headers={
+    res = server.make_request("POST", "/chat/completions", data=body, host=lan_ip, headers={
         "Origin": f"http://{lan_ip}:{server.server_port}",
         "Sec-Fetch-Site": "same-origin",
     })
-    assert res.status_code == 200, res.text
+    assert res.status_code == 200, res.body

-    res = requests.post(server.make_url("/chat/completions", host="127.0.0.1"), json=body, headers={"Origin": "http://evil.com"})
+    res = server.make_request("POST", "/chat/completions", data=body, host="127.0.0.1", headers={"Origin": "http://evil.com"})
     assert res.status_code == 403


diff --git a/tools/server/tests/unit/test_security.py b/tools/server/tests/unit/test_security.py
index ceec582ac..ef4e48fa8 100644
--- a/tools/server/tests/unit/test_security.py
+++ b/tools/server/tests/unit/test_security.py
@@ -170,16 +170,16 @@ def test_cors_origins_localhost_blocks_simple_requests(headers: dict, expected_s

 def test_cors_origins_localhost_allows_same_origin():
     global server
-    lan_ip = get_lan_ip()
-    if lan_ip is None:
-        pytest.skip("no non-loopback interface")  # ty: ignore[too-many-positional-arguments]
     server.api_key = None
     server.cors_origins = "localhost"
     server.server_host = "0.0.0.0"
     server.start()
+    lan_ip = get_lan_ip(server)
+    if lan_ip is None:
+        pytest.skip("no LAN address reachable from this host")  # ty: ignore[too-many-positional-arguments]
     # UI opened via LAN address: Origin matches Host
     url = server.make_url("/tokenize", host=lan_ip)
-    res = requests.post(url, data='{"content": "hello"}', headers={
+    res = requests.post(url, data='{"content": "hello"}', timeout=DEFAULT_REQUEST_TIMEOUT, headers={
         "Content-Type": "text/plain",
         "Origin": f"http://{lan_ip}:{server.server_port}",
     })
diff --git a/tools/server/tests/utils.py b/tools/server/tests/utils.py
index 71470c2b6..56c88b354 100644
--- a/tools/server/tests/utils.py
+++ b/tools/server/tests/utils.py
@@ -34,6 +34,9 @@ DEFAULT_HTTP_TIMEOUT = 600
 # per-request timeout, a hung server fails the test instead of stalling the CI for hours
 DEFAULT_REQUEST_TIMEOUT = 600

+# timeout of the reachability probe of the LAN address
+LAN_PROBE_TIMEOUT = 5
+

 class ServerResponse:
     headers: dict
@@ -805,7 +808,7 @@ def download_file(url: str, output_file_path: str | None = None) -> str:
     return output_file


-def get_lan_ip() -> str | None:
+def get_lan_ip(server: ServerProcess) -> str | None:
     # address of the interface that routes outside, no packet is sent
     import socket
     try:
@@ -814,7 +817,14 @@ def get_lan_ip() -> str | None:
             ip = s.getsockname()[0]
     except OSError:
         return None
-    return None if ip.startswith("127.") else ip
+    if ip.startswith("127."):
+        return None
+    # a host can fail to reach its own LAN address (firewall, VPN, system proxy)
+    try:
+        requests.get(server.make_url("/health", host=ip), timeout=LAN_PROBE_TIMEOUT)
+    except requests.exceptions.RequestException:
+        return None
+    return ip


 def is_slow_test_allowed():