Bug 1865394 - added urgency and incremental to request header in netmonitor. r=necko-reviewers,extension-reviewers,devtools-reviewers,valentin,robwu,bomsy

Differential Revision: https://phabricator.services.mozilla.com/D201265
This commit is contained in:
dylan 2024-03-13 17:03:22 +00:00
parent c1fffe2d9b
commit f01e37b32b
18 changed files with 93 additions and 34 deletions

View File

@ -47,6 +47,7 @@ add_task(async function () {
"Accept-Encoding: gzip, deflate",
"Connection: keep-alive",
"Upgrade-Insecure-Requests: 1",
"Priority: u=1",
"Pragma: no-cache",
"Cache-Control: no-cache",
].join("\n");

View File

@ -71,6 +71,7 @@ async function verifyHeaders(monitor) {
"Cookie",
"Host",
"Pragma",
"Priority",
"Sec-Fetch-Dest",
"Sec-Fetch-Mode",
"Sec-Fetch-Site",
@ -144,6 +145,7 @@ async function verifyRawHeaders(monitor) {
"Sec-Fetch-Dest",
"Sec-Fetch-Mode",
"Sec-Fetch-Site",
"Priority",
"Pragma",
"Cache-Control",
];

View File

@ -74,8 +74,8 @@ add_task(async function () {
// The Text-Encoding header is not consistently displayed, exclude it from
// the assertion. See Bug 1830053.
headers.filter(cell => cell.textContent != "TE").length,
25,
"There should be 25 header values displayed in this tabpanel."
26,
"There should be 26 header values displayed in this tabpanel."
);
const headersTable = tabpanel.querySelector(".accordion");

View File

@ -60,14 +60,23 @@ async function testResendRequest() {
"The resent request has the same url and query parameters and the first request"
);
// The priority header only appears when the urgency and incremental values
// are not both default values (u=3 and i=false). In this case the original
// request has no priority header and the resent request does, hence we subtract one.
is(
firstResend.originalResource.requestHeaders.headers.length,
firstResend.newResource.requestHeaders.headers.length,
firstResend.newResource.requestHeaders.headers.length - 1,
"The no of headers are the same"
);
// Because a resent request has a different purpose and principal it will
// also have a different CoS flag (meaning a different priority header).
// So we can't compare the original and resent request's priority and skip it.
firstResend.originalResource.requestHeaders.headers.forEach(
({ name, value }) => {
if (name === "Priority") {
return;
}
const foundHeader = firstResend.newResource.requestHeaders.headers.find(
header => header.name == name
);

View File

@ -137,8 +137,8 @@ add_task(async function () {
is(
tabpanel.querySelectorAll(".accordion .treeLabelCell").length,
23,
"There should be 23 header values displayed in this tabpanel."
24,
"There should be 24 header values displayed in this tabpanel."
);
const headersTable = tabpanel.querySelector(".accordion");

View File

@ -11568,6 +11568,12 @@
mirror: always
do_not_use_directly: true
# Whether to add urgency and incremental to request headers
- name: network.http.priority_header.enabled
type: bool
value: true
mirror: always
# The maximum allowed length for a referrer header - 4096 default.
# 0 means no limit.
- name: network.http.referer.referrerLengthLimit

View File

@ -42,7 +42,7 @@ Http3Stream::Http3Stream(nsAHttpTransaction* httpTransaction,
mTransactionBrowserId = trans->BrowserId();
}
SetPriority(cos.Flags());
mPriorityUrgency = nsHttpHandler::UrgencyFromCoSFlags(cos.Flags());
SetIncremental(cos.Incremental());
}
@ -80,31 +80,6 @@ bool Http3Stream::GetHeadersString(const char* buf, uint32_t avail,
return true;
}
void Http3Stream::SetPriority(uint32_t aCos) {
if (aCos & nsIClassOfService::UrgentStart) {
// coming from an user interaction => response should be the highest
// priority
mPriorityUrgency = 1;
} else if (aCos & nsIClassOfService::Leader) {
// main html document normal priority
mPriorityUrgency = 2;
} else if (aCos & nsIClassOfService::Unblocked) {
mPriorityUrgency = 3;
} else if (aCos & nsIClassOfService::Follower) {
mPriorityUrgency = 4;
} else if (aCos & nsIClassOfService::Speculative) {
mPriorityUrgency = 6;
} else if (aCos & nsIClassOfService::Background) {
// background tasks can be deprioritzed to the lowest priority
mPriorityUrgency = 6;
} else if (aCos & nsIClassOfService::Tail) {
mPriorityUrgency = 6;
} else {
// all others get a lower priority than the main html document
mPriorityUrgency = 4;
}
}
void Http3Stream::SetIncremental(bool incremental) {
mPriorityIncremental = incremental;
}

View File

@ -67,7 +67,6 @@ class Http3Stream final : public nsAHttpSegmentReader,
bool GetHeadersString(const char* buf, uint32_t avail, uint32_t* countUsed);
nsresult StartRequest();
void SetPriority(uint32_t aCos);
void SetIncremental(bool incremental);
/**

View File

@ -483,6 +483,25 @@ void nsHttpChannel::HandleContinueCancellingByURLClassifier(
ContinueCancellingByURLClassifier(aErrorCode);
}
void nsHttpChannel::SetPriorityHeader() {
uint8_t urgency = nsHttpHandler::UrgencyFromCoSFlags(mClassOfService.Flags());
bool incremental = mClassOfService.Incremental();
nsPrintfCString value(
"%s", urgency != 3 ? nsPrintfCString("u=%d", urgency).get() : "");
if (incremental) {
if (!value.IsEmpty()) {
value.Append(", ");
}
value.Append("i");
}
if (!value.IsEmpty()) {
SetRequestHeader("Priority"_ns, value, false);
}
}
nsresult nsHttpChannel::OnBeforeConnect() {
nsresult rv = NS_OK;
@ -1201,6 +1220,10 @@ nsresult nsHttpChannel::SetupTransaction() {
mozilla::MutexAutoLock lock(mRCWNLock);
if (StaticPrefs::network_http_priority_header_enabled()) {
SetPriorityHeader();
}
// If we're racing cache with network, conditional or byte range header
// could be added in OnCacheEntryCheck. We cannot send conditional request
// without having the entry, so we need to remove the headers here and

View File

@ -566,6 +566,8 @@ class nsHttpChannel final : public HttpBaseChannel,
// This method can only be called on the main thread.
void PerformBackgroundCacheRevalidationNow();
void SetPriorityHeader();
private:
nsCOMPtr<nsICancelable> mProxyRequest;

View File

@ -714,6 +714,34 @@ nsresult nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port,
return NS_GenerateHostPort(host, port, hostLine);
}
// static
uint8_t nsHttpHandler::UrgencyFromCoSFlags(uint32_t cos) {
uint8_t urgency;
if (cos & nsIClassOfService::UrgentStart) {
// coming from an user interaction => response should be the highest
// priority
urgency = 1;
} else if (cos & nsIClassOfService::Leader) {
// main html document normal priority
urgency = 2;
} else if (cos & nsIClassOfService::Unblocked) {
urgency = 3;
} else if (cos & nsIClassOfService::Follower) {
urgency = 4;
} else if (cos & nsIClassOfService::Speculative) {
urgency = 6;
} else if (cos & nsIClassOfService::Background) {
// background tasks can be deprioritzed to the lowest priority
urgency = 6;
} else if (cos & nsIClassOfService::Tail) {
urgency = 6;
} else {
// all others get a lower priority than the main html document
urgency = 4;
}
return urgency;
}
//-----------------------------------------------------------------------------
// nsHttpHandler <private>
//-----------------------------------------------------------------------------

View File

@ -429,6 +429,8 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
int32_t port,
nsACString& hostLine);
static uint8_t UrgencyFromCoSFlags(uint32_t cos);
SpdyInformation* SpdyInfo() { return &mSpdyInfo; }
bool IsH2MandatorySuiteEnabled() { return mH2MandatorySuiteEnabled; }

View File

@ -16,6 +16,7 @@ load("../unit/test_http3_prio_helpers.js");
if (!inChildProcess()) {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("network.http.http3.priority");
Services.prefs.clearUserPref("network.http.priority_header.enabled");
http3_clear_prefs();
});
}
@ -75,7 +76,7 @@ async function test_http3_prio_disabled(incremental) {
null
);
await test_flag_priority(
"disabled (background)",
"disabled (tail)",
Ci.nsIClassOfService.Tail,
null,
incremental,
@ -91,6 +92,7 @@ add_task(async function test_http3_prio_disabled_inc_true() {
// wrapper handles when testing as content process for pref change
if (!inChildProcess()) {
Services.prefs.setBoolPref("network.http.http3.priority", false);
Services.prefs.setBoolPref("network.http.priority_header.enabled", false);
}
await test_http3_prio_disabled(true);
});
@ -101,6 +103,7 @@ add_task(async function test_http3_prio_disabled_inc_false() {
// wrapper handles when testing as content process for pref change
if (!inChildProcess()) {
Services.prefs.setBoolPref("network.http.http3.priority", false);
Services.prefs.setBoolPref("network.http.priority_header.enabled", false);
}
await test_http3_prio_disabled(false);
});

View File

@ -16,6 +16,7 @@ load("../unit/test_http3_prio_helpers.js");
if (!inChildProcess()) {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("network.http.http3.priority");
Services.prefs.clearUserPref("network.http.priority_header.enabled");
http3_clear_prefs();
});
}
@ -82,7 +83,7 @@ async function test_http3_prio_enabled(incremental) {
incremental
);
await test_flag_priority(
"enabled (background)",
"enabled (tail)",
Ci.nsIClassOfService.Tail,
"u=6",
incremental,
@ -95,6 +96,7 @@ add_task(async function test_http3_prio_enabled_incremental_true() {
// wrapper handles when testing as content process for pref change
if (!inChildProcess()) {
Services.prefs.setBoolPref("network.http.http3.priority", true);
Services.prefs.setBoolPref("network.http.priority_header.enabled", true);
}
await test_http3_prio_enabled(true);
});
@ -103,6 +105,7 @@ add_task(async function test_http3_prio_enabled_incremental_false() {
// wrapper handles when testing as content process for pref change
if (!inChildProcess()) {
Services.prefs.setBoolPref("network.http.http3.priority", true);
Services.prefs.setBoolPref("network.http.priority_header.enabled", true);
}
await test_http3_prio_enabled(false);
});

View File

@ -4,6 +4,7 @@
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("network.http.http3.priority");
Services.prefs.clearUserPref("network.http.priority_header.enabled");
http3_clear_prefs();
});
@ -15,6 +16,7 @@ add_task(async function setup() {
async function run_test() {
// test priority urgency and incremental with priority disabled
Services.prefs.setBoolPref("network.http.http3.priority", false);
Services.prefs.setBoolPref("network.http.priority_header.enabled", false);
run_test_in_child("../unit/test_http3_prio_disabled.js");
run_next_test(); // only pumps next async task from this file
}

View File

@ -4,6 +4,7 @@
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("network.http.http3.priority");
Services.prefs.clearUserPref("network.http.priority_header.enabled");
http3_clear_prefs();
});
@ -15,6 +16,7 @@ add_task(async function setup() {
async function run_test() {
// test priority urgency and incremental with priority enabled
Services.prefs.setBoolPref("network.http.http3.priority", true);
Services.prefs.setBoolPref("network.http.priority_header.enabled", true);
run_test_in_child("../unit/test_http3_prio_enabled.js");
run_next_test(); // only pumps next async task from this file
}

View File

@ -578,6 +578,7 @@ add_task(async function test_get_no_headers() {
"sec-fetch-mode",
"sec-fetch-site",
"sec-fetch-user",
"priority",
];
let request = new RESTRequest(server.baseURI + "/resource");
await request.get();

View File

@ -29,6 +29,7 @@ server.registerPathHandler("/echoheaders", (req, res) => {
dropDefaultHeader("accept-language");
dropDefaultHeader("accept-encoding");
dropDefaultHeader("connection");
dropDefaultHeader("priority");
res.write(JSON.stringify(headers));
});