Safari forced-close workaround adds LuCI latency on Safari 27 and CriOS: controlled A/B results
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 48/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- c
- Ambito
- backend, networking
Direzione di ricerca
Read client.c at client_header_complete() and the user-agent parser, then inspect any existing parser and connection-behavior tests. Done means Safari with valid Version/27.0-or-newer is exempted while explicit close, HTTP/1.0, global close, and old IE POST behavior remain unchanged; parser results and current-master hardware validation should be reported separately.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
The blanket Safari user-agent workaround in client_header_complete() forces Connection: close even for current Safari and CriOS clients. A controlled off/on/off experiment on a WAS-110 shows substantial LuCI dashboard latency from this decision.
The hardware measurements used uhttpd 3abcc89103799aaa79870fffcd58ec4370815024, shipped in WAS-110 firmware v2.8.3_basic_7d89440. They did not use current master. However, the same unconditional Safari close assignment and Safari UA classification are still present in current master at 373145f72c884c36a2b16f7f47e74ffae06bd754.
Relevant code
case UH_UA_MSIE_OLD:
if (r->method != UH_HTTP_MSG_POST)
break;
/* fall through */
case UH_UA_SAFARI:
r->connection_close = true;
break;
The UA parser checks Chrome/ before classifying a UA containing Safari/ and Mac OS X as Safari. Chrome on this iPhone uses CriOS/, so it also reaches the Safari close workaround. The rule originated in 7635644 (2013); the precise historical Safari defect is not established by our investigation.
Test method
An isolated RAM-only rebuild of the shipped source revision added a process-local switch to skip only the Safari forced-close assignment. It preserved existing close decisions and ran on a separate HTTPS port with the same certificate, web root and Lua/TLS/ubus plugins. Production was never restarted or flashed.
Each browser used the same authenticated dashboard, test hostname/port, certificate, Wi-Fi path and cache across off/on/off modes. Phone measurements came from USB Web Inspector. The Chrome run used one continuous inspector connection after reconnecting between captures proved intermittently unreliable; failed inspector attempts were discarded, not counted as browser-load failures.
| Browser/mode | Dashboard load events | First GPON status responses |
|---|---|---|
| Safari 27, off | 4.541 / 4.157 / 4.077 s | 9.857 / 9.863 / 9.242 s |
| Safari 27, on | 2.133 / 0.415 / 1.376 s | 2.984 / 1.211 / 2.286 s |
| CriOS 153, off | 6.719 / 4.638 / 4.472 s | 11.946 / 9.722 / 10.241 s |
| CriOS 153, on | 2.278 / 0.403 / 0.388 s | 3.111 / 1.144 / 1.150 s |
The third off measurement in each row was taken after returning from on mode. The first on load followed a test-process restart; later on loads could reuse existing connections. Load events are distinct from completion of dashboard data, hence the separate GPON column. These are small samples on one phone, not performance guarantees.
Every captured off-mode response used Connection: close; every captured on-mode response used Keep-Alive. Each browser's 45-second on capture completed 73 HTTP 200/304 responses. Chrome's 45-second run reported no network errors or JavaScript exceptions. Safari had one unmatched cancellation during reload; similar unmatched cancellations occurred on some mode transitions, consistent with canceling previous-page polling. No failure was associated with a captured request in the completed runs. Pending polling at a capture boundary was not classified as failed.
Separate low-rate checks covered same-socket static/login/ETag requests, explicit Connection: close, HTTP/1.0, old IE POST close, and a 20-second idle timeout followed by reconnection. An initial If-Modified-Since test returned 200; date-based caching is not claimed as validated.
Actual browser versions
USB-reported OS: iOS 27.0, build 24A437.
Safari UA:
Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/27.0 Mobile/15E148 Safari/604.1
Chrome UA:
Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/153.0.8010.24 Mobile/15E148 Safari/604.1
Safari's embedded CPU OS token differs from the actual OS reported over USB. Safari/604.1 is not its product version, and a CriOS version is not a Safari/WebKit version.
Proposed next step
A conservative draft patch can retain the historical workaround for unknown/older clients while exempting Safari with a valid Version/27.0 or greater. Version 27.0 is the tested minimum; allowing newer versions is a compatibility policy, not a claim that they have been tested. Explicit close, HTTP/1.0/global close and old IE POST behavior must remain intact.
The CriOS experiment verifies benefit on Chrome 153.0.8010.24 + iOS 27.0. A separate reliable eligibility policy is still needed before enabling all CriOS clients: the Chrome application version alone does not establish its WebKit version. The initial Safari proposal therefore deliberately excludes CriOS and other alternative iOS-browser tokens, despite the positive Chrome experiment.
Current master also contains newer connection/framing fixes not present in the tested firmware, so current-master hardware validation remains necessary. The final version parser was not part of the hardware A/B; parser tests and hardware behavior must be reported separately.
Downstream report: https://github.com/djGrrr/8311-was-110-firmware-builder/issues/54
Downstream draft/backport materials: https://github.com/djGrrr/8311-was-110-firmware-builder/pull/55
All temporary test rules/listeners were removed; complete IPv4 filter listings matched before and after, and production retained its original PID/binary. No credentials, cookies, private hostnames or packet payloads are included here.
- Lingua principale
- C
- Stelle
- 39
- Fork
- 31
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di openwrt/uhttpd
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 24/100
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 56/100
Tutte le issue di openwrt/uhttpd
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
FujiNetWIFI/fujinet-config#379 ·
I maintainer di solito rispondono entro 1 giorno
-
Ship /Local/Applications, the Local domain's Applications folderForse già presa @pkgdemon l’ha presa oggi. Apertaarea:base enhancement
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 94/100
nextbsd/nextbsd-userland#612 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
zephyrproject-rtos/zephyr#125543 ·
I maintainer di solito rispondono entro 2 giorni
-
good first issue needs-triage
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
InauguralSystems/EigenScript#2347 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
colbymchenry/codegraph#3277 ·
I maintainer di solito rispondono entro 1 giorno