XHR adapter: avoid main-thread jank from synchronous document.cookie reads (use cookieStore where available)
Background
axios reads the XSRF cookie via document.cookie inside lib/helpers/cookies.js, called from lib/helpers/resolveConfig.js. document.cookie access is synchronous and main-thread-blocking; under contention it can show up as a real jank source in browser performance traces. The whatwg/html issue tracking this is whatwg/html#11658, and the Cookie Store API is the asynchronous alternative when available.
#7040 (now closed) was a first pass at this. The motivation was sound but the implementation had several blockers (regressed CVE fixes through a stale base, double cookie-value encoding, non-standard-env fallback dropped, broad XHR re-indent, opt-in flag rather than auto-detection). See the close comment on that PR for the detail.
What we want
A jank-avoiding read path for the XSRF cookie that:
- Is XHR-only. The
fetchadapter is alreadyasync; switching its config-resolution to cookieStore adds a microtask without saving jank. The change should be confined to where it actually helps. - Is automatic, not opt-in. No new public config option. Detect
window.cookieStoreat runtime; use it for XSRF reads when present, fall back to the existingdocument.cookiepath when not. - Round-trips cookie values correctly.
cookieStore.getreturns the raw value; do notdecodeURIComponentit.cookieStore.setaccepts the raw value; do notencodeURIComponentit. Encoding is adocument.cookie-specific quirk. - Preserves existing security hardening. The
own(key)prototype-pollution guard from GHSA-q8qp-cvcw-x6jj and the strictwithXSRFToken === true || == nullcheck from GHSA-xx6v-rp6x-q39c must stay intact in any restructure ofresolveConfig.js. Same for theencodeUTF8helper that replacedunescape(encodeURIComponent(...)). - Preserves the non-standard-env no-op.
cookies.jsreturns a{write(){}, read(){return null}, remove(){}}shim in Web Worker / React Native envs. Any new export must keep that fallback.
Implementation notes / constraints
- The XHR adapter currently does
const _config = resolveConfig(config)synchronously insidedispatchXhrRequest. The smallest change is to makedispatchXhrRequestasync(or doresolveConfig(config).then(...)) without re-indenting the entire body. resolveConfigreturning a Promise needs to be a controlled change: any other internal caller that assumes sync should be checked. Quick scan:lib/adapters/fetch.js,lib/adapters/xhr.js, possibly tests.- Tests should mock
window.cookieStoreexplicitly to verify the async branch actually runs (existing approach asserted viadocument.cookie, which co-stores with cookieStore and didn't differentiate). - Behaviour in browsers without cookieStore (Safari at the time of writing being the conspicuous one) must be unchanged.
Out of scope
- Any general async-resolution work beyond XSRF cookie reads.
- Changes to the fetch adapter.
- New public config options.
References
- Closed PR: #7040
- Cookie Store API: https://cookiestore.spec.whatwg.org/
- whatwg/html issue: https://github.com/whatwg/html/issues/11658
- Related security advisories that must remain intact: GHSA-q8qp-cvcw-x6jj, GHSA-xx6v-rp6x-q39c
Source: axios/axios