Safari forced-close workaround adds LuCI latency on Safari 27 and CriOS: controlled A/B results
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 48/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- c
- Área
- backend, networking
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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.
- Lenguaje dominante
- C
- Estrellas
- 39
- Forks
- 31
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de openwrt/uhttpd
-
Dificultad 4/5 3-5 días Aptitud para principiantes 24/100
-
Dificultad 4/5 3-5 días Aptitud para principiantes 56/100
Todos los issues de openwrt/uhttpd
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
FujiNetWIFI/fujinet-config#379 ·
Los mantenedores suelen responder en 1 día
-
Ship /Local/Applications, the Local domain's Applications folderPosiblemente ocupada @pkgdemon la tomó hoy. Abiertoarea:base enhancement
Dificultad 1/5 Menos de una hora Aptitud para principiantes 94/100
nextbsd/nextbsd-userland#612 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
zephyrproject-rtos/zephyr#125543 ·
Los mantenedores suelen responder en 2 días
-
good first issue needs-triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
InauguralSystems/EigenScript#2347 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
colbymchenry/codegraph#3277 ·
Los mantenedores suelen responder en 1 día