Safari forced-close workaround adds LuCI latency on Safari 27 and CriOS: controlled A/B results

Đang mở
#42 2 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
c
Lĩnh vực
backend, networking

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.

Ngôn ngữ chính
C
Star
39
Fork
31
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của openwrt/uhttpd

Tất cả issue của openwrt/uhttpd

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.