Skip to content

Commit

Permalink
Bug 1849864 - Don't recalculate the userAgent header if it has been m…
Browse files Browse the repository at this point in the history
…odified. r=tjr,jesup,necko-reviewers,devtools-reviewers

The userAgent header can be modified in several ways, such as using the
header field to set a custom userAgent header for a fetch request. We
want to preserve the custom header, so we shouldn't recalculate the
userAgent header if it's been overridden after the channel was created.
Otherwise, the custom header won't work.

Differential Revision: https://phabricator.services.mozilla.com/D197655
  • Loading branch information
artines1 committed Jan 16, 2024
1 parent 3ea9604 commit 18a9840
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ add_task(async function () {
await testClipboardContent(`await fetch("https://example.com/browser/devtools/client/netmonitor/test/sjs_simple-test-server.sjs", {
"credentials": "omit",
"headers": {
"User-Agent": "${navigator.userAgent}",
"Accept": "*/*",
"Accept-Language": "en-US",
"X-Custom-Header-1": "Custom value",
"X-Custom-Header-2": "8.8.8.8",
"X-Custom-Header-3": "Mon, 3 Mar 2014 11:11:11 GMT",
"User-Agent": "${navigator.userAgent}",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
Expand Down
1 change: 1 addition & 0 deletions netwerk/ipc/NeckoChannelParams.ipdlh
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ struct HttpChannelOpenArgs
uint8_t redirectionLimit;
nsString classicScriptHintCharset;
nsString documentCharacterSet;
bool isUserAgentHeaderModified;
};

struct HttpChannelConnectArgs
Expand Down
31 changes: 31 additions & 0 deletions netwerk/protocol/http/HttpBaseChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ HttpBaseChannel::HttpBaseChannel()
StoreAllRedirectsSameOrigin(true);
StoreAllRedirectsPassTimingAllowCheck(true);
StoreUpgradableToSecure(true);
StoreIsUserAgentHeaderModified(false);

this->mSelfAddr.inet = {};
this->mPeerAddr.inet = {};
Expand Down Expand Up @@ -1944,6 +1945,11 @@ HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
return NS_ERROR_INVALID_ARG;
}

// Mark that the User-Agent header has been modified.
if (nsHttp::ResolveAtom(aHeader) == nsHttp::User_Agent) {
StoreIsUserAgentHeaderModified(true);
}

return mRequestHead.SetHeader(aHeader, flatValue, aMerge);
}

Expand Down Expand Up @@ -1977,6 +1983,11 @@ HttpBaseChannel::SetEmptyRequestHeader(const nsACString& aHeader) {
return NS_ERROR_INVALID_ARG;
}

// Mark that the User-Agent header has been modified.
if (nsHttp::ResolveAtom(aHeader) == nsHttp::User_Agent) {
StoreIsUserAgentHeaderModified(true);
}

return mRequestHead.SetEmptyHeader(aHeader);
}

Expand Down Expand Up @@ -2092,6 +2103,19 @@ HttpBaseChannel::SetIsOCSP(bool value) {
return NS_OK;
}

NS_IMETHODIMP
HttpBaseChannel::GetIsUserAgentHeaderModified(bool* value) {
NS_ENSURE_ARG_POINTER(value);
*value = LoadIsUserAgentHeaderModified();
return NS_OK;
}

NS_IMETHODIMP
HttpBaseChannel::SetIsUserAgentHeaderModified(bool value) {
StoreIsUserAgentHeaderModified(value);
return NS_OK;
}

NS_IMETHODIMP
HttpBaseChannel::GetRedirectionLimit(uint32_t* value) {
NS_ENSURE_ARG_POINTER(value);
Expand Down Expand Up @@ -4967,6 +4991,13 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI,
}
}

// convery the IsUserAgentHeaderModified value.
if (httpInternal) {
rv = httpInternal->SetIsUserAgentHeaderModified(
LoadIsUserAgentHeaderModified());
MOZ_ASSERT(NS_SUCCEEDED(rv));
}

// share the request context - see bug 1236650
rv = httpChannel->SetRequestContextID(mRequestContextID);
MOZ_ASSERT(NS_SUCCEEDED(rv));
Expand Down
9 changes: 8 additions & 1 deletion netwerk/protocol/http/HttpBaseChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ class HttpBaseChannel : public nsHashPropertyBag,
NS_IMETHOD SetEarlyHintLinkType(uint32_t aEarlyHintLinkType) override;
NS_IMETHOD GetEarlyHintLinkType(uint32_t* aEarlyHintLinkType) override;

NS_IMETHOD SetIsUserAgentHeaderModified(bool value) override;
NS_IMETHOD GetIsUserAgentHeaderModified(bool* value) override;

NS_IMETHOD SetClassicScriptHintCharset(
const nsAString& aClassicScriptHintCharset) override;
NS_IMETHOD GetClassicScriptHintCharset(
Expand Down Expand Up @@ -956,7 +959,11 @@ class HttpBaseChannel : public nsHashPropertyBag,

// Indicate whether the response of this channel is coming from
// socket process.
(uint32_t, LoadedBySocketProcess, 1)
(uint32_t, LoadedBySocketProcess, 1),

// Indicates whether the user-agent header has been modifed since the channel
// was created.
(uint32_t, IsUserAgentHeaderModified, 1)
))
// clang-format on

Expand Down
12 changes: 12 additions & 0 deletions netwerk/protocol/http/HttpChannelChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2483,6 +2483,8 @@ nsresult HttpChannelChild::ContinueAsyncOpen() {

openArgs.classicScriptHintCharset() = mClassicScriptHintCharset;

openArgs.isUserAgentHeaderModified() = LoadIsUserAgentHeaderModified();

RefPtr<Document> doc;
mLoadInfo->GetLoadingDocument(getter_AddRefs(doc));

Expand Down Expand Up @@ -2565,6 +2567,11 @@ HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
if (!tuple) return NS_ERROR_OUT_OF_MEMORY;

// Mark that the User-Agent header has been modified.
if (nsHttp::ResolveAtom(aHeader) == nsHttp::User_Agent) {
StoreIsUserAgentHeaderModified(true);
}

tuple->mHeader = aHeader;
tuple->mValue = aValue;
tuple->mMerge = aMerge;
Expand All @@ -2581,6 +2588,11 @@ HttpChannelChild::SetEmptyRequestHeader(const nsACString& aHeader) {
RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
if (!tuple) return NS_ERROR_OUT_OF_MEMORY;

// Mark that the User-Agent header has been modified.
if (nsHttp::ResolveAtom(aHeader) == nsHttp::User_Agent) {
StoreIsUserAgentHeaderModified(true);
}

tuple->mHeader = aHeader;
tuple->mMerge = false;
tuple->mEmpty = true;
Expand Down
7 changes: 5 additions & 2 deletions netwerk/protocol/http/HttpChannelParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ bool HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) {
a.handleFetchEventStart(), a.handleFetchEventEnd(),
a.forceMainDocumentChannel(), a.navigationStartTimeStamp(),
a.earlyHintPreloaderId(), a.classicScriptHintCharset(),
a.documentCharacterSet());
a.documentCharacterSet(), a.isUserAgentHeaderModified());
}
case HttpChannelCreationArgs::THttpChannelConnectArgs: {
const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
Expand Down Expand Up @@ -444,7 +444,8 @@ bool HttpChannelParent::DoAsyncOpen(
const TimeStamp& aNavigationStartTimeStamp,
const uint64_t& aEarlyHintPreloaderId,
const nsAString& aClassicScriptHintCharset,
const nsAString& aDocumentCharacterSet) {
const nsAString& aDocumentCharacterSet,
const bool& aIsUserAgentHeaderModified) {
MOZ_ASSERT(aURI, "aURI should not be NULL");

if (aEarlyHintPreloaderId) {
Expand Down Expand Up @@ -577,6 +578,8 @@ bool HttpChannelParent::DoAsyncOpen(
}
}

httpChannel->SetIsUserAgentHeaderModified(aIsUserAgentHeaderModified);

RefPtr<ParentChannelListener> parentListener = new ParentChannelListener(
this, mBrowserParent ? mBrowserParent->GetBrowsingContext() : nullptr);

Expand Down
3 changes: 2 additions & 1 deletion netwerk/protocol/http/HttpChannelParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ class HttpChannelParent final : public nsIInterfaceRequestor,
const TimeStamp& aNavigationStartTimeStamp,
const uint64_t& aEarlyHintPreloaderId,
const nsAString& aClassicScriptHintCharset,
const nsAString& aDocumentCharacterSet);
const nsAString& aDocumentCharacterSet,
const bool& aIsUserAgentHeaderModified);

virtual mozilla::ipc::IPCResult RecvSetPriority(
const int16_t& priority) override;
Expand Down
25 changes: 17 additions & 8 deletions netwerk/protocol/http/nsHttpChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6133,14 +6133,23 @@ nsHttpChannel::AsyncOpen(nsIStreamListener* aListener) {

AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(this);

// Recalculate the userAgent header after the AntiTrackingInfo gets updated
// because we can only know whether the site is exempted from fingerprinting
// protection after we have the AntiTracking Info.
rv = mRequestHead.SetHeader(
nsHttp::User_Agent,
gHttpHandler->UserAgent(nsContentUtils::ShouldResistFingerprinting(
this, RFPTarget::HttpUserAgent)));
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Recalculate the default userAgent header after the AntiTrackingInfo gets
// updated because we can only know whether the site is exempted from
// fingerprinting protection after we have the AntiTracking Info.
//
// Note that we don't recalculate the header if it has been modified since the
// channel was created because we want to preserve the modified header.
if (!LoadIsUserAgentHeaderModified()) {
rv = mRequestHead.ClearHeader(nsHttp::User_Agent);
MOZ_ASSERT(NS_SUCCEEDED(rv));

rv = mRequestHead.SetHeader(
nsHttp::User_Agent,
gHttpHandler->UserAgent(nsContentUtils::ShouldResistFingerprinting(
this, RFPTarget::HttpUserAgent)),
false, nsHttpHeaderArray::eVarietyRequestDefault);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}

if (WaitingForTailUnblock()) {
// This channel is marked as Tail and is part of a request context
Expand Down
9 changes: 9 additions & 0 deletions netwerk/protocol/http/nsIHttpChannelInternal.idl
Original file line number Diff line number Diff line change
Expand Up @@ -510,4 +510,13 @@ interface nsIHttpChannelInternal : nsISupports
* 103 response.
*/
[must_use] attribute unsigned long earlyHintLinkType;

/**
* Indicates whether the User-Agent request header has been modified since
* the channel was created. This value will be used to decide if we need to
* recalculate the User-Agent header for fingerprinting protection. We won't
* recalculate the User-Agent header if it has been modified to preserve the
* overridden header value.
*/
[must_use] attribute boolean isUserAgentHeaderModified;
};

0 comments on commit 18a9840

Please sign in to comment.