Skip to content

fix(ui): rank Accept-Language tags by q-value instead of substring scan - #2084

Closed
AmirF194 wants to merge 1 commit into
DeusData:mainfrom
AmirF194:fix/1829-accept-language-qvalue
Closed

AmirF194 wants to merge 1 commit into
DeusData:mainfrom
AmirF194:fix/1829-accept-language-qvalue

Conversation

@AmirF194

@AmirF194 AmirF194 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

detect_ui_lang() (src/ui/http_server.c) picks the /api/ui-config language with strstr(accept_language, "zh"), so any Chinese tag anywhere in the header serves the Chinese UI, regardless of position or q-value. A bilingual browser list whose top preference is English (en-US;q=0.9,zh;q=0.5) still gets Chinese.

Per RFC 9110 12.5.4, the fix parses each tag's q-value (default 1.0), treats q=0 as explicitly unacceptable (12.5.1), and returns the highest-ranked tag whose base language is zh or en, keeping the first occurrence on a tie. This mirrors the UI bundle's own JT() fallback parser (quoted in the issue), which already does this correctly as a client-side fallback when the endpoint is unreachable.

Checklist

  • Every commit is signed off (git commit -s)
  • Tests pass locally (scripts/test.sh --suites httpd)
  • Lint passes on the changed files
  • New behavior is covered by a test (reproduce-first for bug fixes)

Verification

  • The two new tests assert "lang":"en" and get "lang":"zh" on plain main; both pass on this branch. Ran both ways in a clean ubuntu:24.04 container. Full httpd suite: 66 passed, 1 skipped (pre-existing, Windows-only) on both sides.
  • detect_ui_lang has a single call site (handle_ui_config); no other reader needed updating.
  • cppcheck and clang-format --dry-run on the two changed files: same output before and after this change, so nothing new here.
  • I have not run this on Windows or macOS; the code has no OS-specific branches, so I'd expect it to behave the same there.

Fixes #1829

detect_ui_lang() (src/ui/http_server.c) picked the UI language with
strstr(accept_language, "zh"), so any Chinese tag anywhere in the header
served the Chinese UI regardless of position or q-value. A bilingual
header whose top preference is English (e.g. en-US;q=0.9,zh;q=0.5) still
got Chinese.

Per RFC 9110 12.5.4, parse each tag's q-value (default 1.0), treat q=0 as
explicitly unacceptable (12.5.1), and return the highest-ranked tag whose
base language is zh or en, keeping the first occurrence on a tie. This
mirrors the UI bundle's own JT() fallback parser, quoted in the issue,
which already implements this correctly as a client-side fallback.

Fixes DeusData#1829

Signed-off-by: Amir Fathi <amirfathi.me@gmail.com>
@AmirF194
AmirF194 requested a review from DeusData as a code owner September 7, 2026 05:06
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@DeusData DeusData added bug Something isn't working ux/behavior Display bugs, docs, adoption UX priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. labels Sep 9, 2026
@DeusData

DeusData commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Thank you for contributing the Accept-Language quality-value handling and HTTP-server tests. This is queued as a UI behavior fix. We need more time to review the parsing and fallback cases before giving a decision.

The review queue is currently full, so detailed feedback may take a little time. We are working through it carefully and appreciate the work you have put into supporting the project. Thank you for your patience.

@AmirF194

Copy link
Copy Markdown
Contributor Author

The macOS test-tsan failure is a pre-existing flake in daemon_runtime, unrelated to this diff (which only touches http_server.c); the sibling ubuntu-arm TSAN leg is green. Anything else you'd want changed here?

@DeusData

Copy link
Copy Markdown
Owner

Thank you for the quality-value implementation and for asking about next steps. Current detect_ui_lang still uses a substring check for zh, so the HTTP-side problem remains on main. This PR is relevant to #553 and #1829, including q=0, supported-language matching and deterministic ties. I have no additional contributor request from this triage; the next step is maintainer review, not another routine rebase.

@DeusData

Copy link
Copy Markdown
Owner

You were right, and I want to confirm it rather than leave you waiting on an unexplained red.

Your 2026-09-14 diagnosis — that the macOS test-tsan failure is a pre-existing daemon_runtime flake unrelated to a diff touching only http_server.c — checks out. I re-ran the failed job against the identical commit and base, changing nothing but the runner, and it came back 35 success, 0 failures. Same code, different result, which is the definition of a flake and not a verdict on your work.

The signature is now recorded on our side so the next person who hits it does not have to re-derive it:

tests/test_daemon_runtime.c:2726  ASSERT(capacity_rejected)
daemon_runtime_connection_cap_covers_slow_hello_and_stopping_is_terminal
on test-tsan (macos-14)

I am also not treating a green rerun as the end of it. A required check that passes on retry is a lottery, not a fixed test, so that flake is logged as a defect of ours to attribute properly — production race versus test-side timing — rather than something to shrug at. That work is on us, not on you, and it will not block this PR.

Separately, the review note left on 2026-09-19 about detect_ui_lang still using a substring check for zh is the open item here. That one is a real question about scope, and it is yours to answer when you have time — no rush from me, and apologies that you were left chasing a red that was never yours.

@AmirF194

Copy link
Copy Markdown
Contributor Author

Appreciate you tracking down the tsan flake signature so nobody has to re-derive it.

On detect_ui_lang: this PR's diff already replaces the substring check with the RFC 9110 q-value ranking (12.5.1, q=0 excluded, ties broken deterministically), covered by the two new httpd tests. Nothing else queued on that path, the substring check only survives on main until this merges.

@DeusData

Copy link
Copy Markdown
Owner

@AmirF194 — you are right: your diff already replaces the substring scan, and my 19 September note read as if it did not. That was my misreading, not an open item on your side. Thank you for answering it patiently.

I am nevertheless going to close this, and you deserve the real reason rather than a vague one: we are relaunching the UI soon, and this change would be redundant the moment that lands. The current graph UI and the server code that serves it — detect_ui_lang lives in src/ui/http_server.c and exists only to pick the language that UI is served in — are being replaced as a whole rather than evolved. Anything merged into that surface today has a very short life, and I would rather say so now than merge it and have it quietly disappear. I should have told you this on the 19th instead of sending you around another loop; I am sorry for that.

What I want you to know about the work itself:

  • It is correct. Ranking by q-value with a default of 1.0, excluding q=0, breaking ties by order, and matching zh/en only on a tag boundary (len == 2 || entry[2] == '-') is what RFC 9110 asks for, and the old strstr(…, "zh") would indeed have picked Chinese for Accept-Language: en, zh;q=0.1. Your two httpd tests pin exactly those cases.
  • The requirement carries forward. "Negotiate the UI language by q-value, never by substring" goes into the new UI's requirements as written.
  • The red check on 14 September was never yours. You diagnosed the macOS TSan failure as a pre-existing daemon_runtime flake from a diff that only touches http_server.c, and you were right; it is recorded on our side with its signature.

You have several other PRs in this queue that are not on a disappearing surface — #2089, #2181, #2170 and #2085 among them — and those are being reviewed and landed on their merits. #2089 is next on my list tonight. Thank you for the steady stream of careful, well-tested fixes; it is noticed.

@DeusData DeusData closed this Sep 21, 2026
@AmirF194
AmirF194 deleted the fix/1829-accept-language-qvalue branch September 21, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. ux/behavior Display bugs, docs, adoption UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/api/ui-config ignores Accept-Language ordering and q-values — returns zh if Chinese appears anywhere in the list

2 participants