MarshallOfSound

#49226: fix: webRequest.onBeforeSendHeaders not being able to modify reserved headers

Merged
Created: Dec 16, 2025, 11:23:12 PM
Merged: Dec 19, 2025, 4:08:41 AM
3 comments
Target: main

Fix webRequest.onBeforeSendHeaders not being able to modify headers like Proxy-Authorization for requests made via the net module.

When using webRequest.onBeforeSendHeaders to inject headers like Proxy-Authorization into requests made via net.request or net.fetch, the request fails with net::ERR_INVALID_ARGUMENT. However, the same webRequest listener works correctly for renderer-initiated requests (e.g., fetch() from a BrowserWindow). The network service validates headers and headers starting with Proxy- are rejected by AreRequestHeadersSafe() in CorsURLLoaderFactory::IsValidRequest().

For renderer requests, this isn't a problem because:

  1. The initial request passes validation (no Proxy-Authorization header yet)
  2. Header modifications via webRequest happen through the TrustedHeaderClient callback, which occurs after validation
  3. Modified headers are passed directly to the network layer, bypassing re-validation

For net module requests, the TrustedHeaderClient path was not being used because network_service_request_id was always 0. This caused header modifications to go through the FollowRedirect() path instead, which re-validates headers with AreRequestHeadersSafe() and rejects Proxy-* headers.

The condition that gates TrustedHeaderClient usage (in proxying_url_loader_factory.cc):

current_request_uses_header_client_ =
    factory_->url_loader_header_client_receiver_.is_bound() &&
    (for_cors_preflight_ || network_service_request_id_ != 0) &&
    has_any_extra_headers_listeners_;

Solution

Set a non-zero request ID for net module requests using Chromium's GlobalRequestID::MakeBrowserInitiated(). This generates unique negative request IDs (-2, -3, -4, ...) that are distinct from renderer request IDs (positive numbers). This is the same mechanism Chromium uses internally for other browser-initiated requests.

Setting Proxy-Authorization directly in the net.fetch options will still fail, as the header would be present in the initial request before validation. The header must be injected via webRequest.onBeforeSendHeaders to use the TrustedHeaderClient path.

Notes: Requests sent via net are now capable of having their headers modified to use reserved headers via webRequest

Backports

39-x-y
In-flight
PR Number
#49242
Waiting to be merged
40-x-y
In-flight
PR Number
#49241
Waiting to be merged

Semver Impact

Major
Breaking changes
Minor
New features
Patch
Bug fixes
None
Docs, tests, etc.

Semantic Versioning helps users understand the impact of updates:

  • Major (X.y.z): Breaking changes that may require code modifications
  • Minor (x.Y.z): New features that maintain backward compatibility
  • Patch (x.y.Z): Bug fixes that don't change the API
  • None: Changes that don't affect using facing parts of Electron