Bug 1761252 - Parse anchor attribute in Link-header r=necko-reviewers,dragana,kershaw

Differential Revision: https://phabricator.services.mozilla.com/D142442
This commit is contained in:
Manuel Bucher 2022-06-15 09:59:46 +00:00
parent 223d2198f9
commit 64e0803487
9 changed files with 99 additions and 36 deletions

View File

@ -3403,6 +3403,21 @@ void LinkHeader::Reset() {
mCrossOrigin.SetIsVoid(true);
}
nsresult LinkHeader::NewResolveHref(nsIURI** aOutURI, nsIURI* aBaseURI) const {
if (mAnchor.IsEmpty()) {
// use the base uri
return NS_NewURI(aOutURI, mHref, nullptr, aBaseURI);
}
// compute the anchored URI
nsCOMPtr<nsIURI> anchoredURI;
nsresult rv =
NS_NewURI(getter_AddRefs(anchoredURI), mAnchor, nullptr, aBaseURI);
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewURI(aOutURI, mHref, nullptr, anchoredURI);
}
bool LinkHeader::operator==(const LinkHeader& rhs) const {
return mHref == rhs.mHref && mRel == rhs.mRel && mTitle == rhs.mTitle &&
mIntegrity == rhs.mIntegrity && mSrcset == rhs.mSrcset &&

View File

@ -1012,6 +1012,9 @@ struct LinkHeader {
LinkHeader();
void Reset();
nsresult NewResolveHref(nsIURI** aOutURI, nsIURI* aBaseURI) const;
bool operator==(const LinkHeader& rhs) const;
};

View File

@ -162,8 +162,7 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
nsCOMPtr<nsIURI> uri;
// use the base uri
NS_ENSURE_SUCCESS_VOID(
NS_NewURI(getter_AddRefs(uri), aHeader.mHref, nullptr, aBaseURI));
NS_ENSURE_SUCCESS_VOID(aHeader.NewResolveHref(getter_AddRefs(uri), aBaseURI));
// Only make same origin preloads, the fromPrivateWindow is only read when
// reportError is enabled, so setting both to false is safe.

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<img src="http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?f5a05cb8-43e6-4868-bc0f-ca453ef87826" width="100px">
</body>
</html>

View File

@ -0,0 +1 @@
Cache-Control: no-cache

View File

@ -0,0 +1,2 @@
HTTP 103 Early Hints
Link: <netwerk/test/browser/early_hint_pixel.sjs?f5a05cb8-43e6-4868-bc0f-ca453ef87826>; rel=preload; as=image; anchor="/browser/"

View File

@ -44,6 +44,9 @@ support-files =
103_preload.html^headers^
no_103_preload.html
no_103_preload.html^headers^
103_preload_anchor.html^informationalResponse^
103_preload_anchor.html^headers^
103_preload_anchor.html
103_preload_and_404.html^informationalResponse^
103_preload_and_404.html^headers^
103_preload_and_404.html

View File

@ -333,10 +333,8 @@ add_task(async function test_103_iframe() {
Services.cache2.clear();
});
// - testName is just there to be printed during Asserts when failing
// - asset is the asset type, see early_hint_asset_html.sjs for possible values
// - hinted: when true, the server reponds with "103 Early Hints"-header
async function test_hint_asset(testName, asset, hinted) {
// Test that anchors are parsed
add_task(async function test_103_anchor() {
// reset the count
let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", "");
@ -345,14 +343,13 @@ async function test_hint_asset(testName, asset, hinted) {
{ headers }
);
let requestUrl = `http://example.com/browser/netwerk/test/browser/early_hint_asset_html.sjs?as=${asset}&hinted=${
hinted ? "1" : "0"
}`;
let anchorUri =
"http://example.com/browser/netwerk/test/browser/103_preload_anchor.html";
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: requestUrl,
url: anchorUri,
waitForLoad: true,
},
async function() {}
@ -364,31 +361,7 @@ async function test_hint_asset(testName, asset, hinted) {
await Assert.deepEqual(
gotRequestCount,
hinted ? { hinted: 1, normal: 0 } : { hinted: 0, normal: 1 },
`${testName} (${asset}): Unexpected amount of requests made`
{ hinted: 1, normal: 0 },
"test_103_anchor: Unexpected amount of requests made"
);
}
// preload css
add_task(async function test_103_asset_style() {
await test_hint_asset("test_103_asset_hinted", "style", true);
await test_hint_asset("test_103_asset_normal", "style", false);
});
// preload javascript
add_task(async function test_103_asset_javascript() {
await test_hint_asset("test_103_asset_hinted", "script", true);
await test_hint_asset("test_103_asset_normal", "script", false);
});
// preload fetch
add_task(async function test_103_asset_fetch() {
await test_hint_asset("test_103_asset_hinted", "fetch", true);
await test_hint_asset("test_103_asset_normal", "fetch", false);
});
// preload font
add_task(async function test_103_asset_font() {
await test_hint_asset("test_103_asset_hinted", "font", true);
await test_hint_asset("test_103_asset_normal", "font", false);
});

View File

@ -243,3 +243,64 @@ const SimpleParseTestData simple_parse_tests[] = {
INSTANTIATE_TEST_SUITE_P(TestLinkHeader, SimpleParseTest,
testing::ValuesIn(simple_parse_tests));
// Test anchor
struct AnchorTestData {
nsString baseURI;
// building the new anchor in combination with the baseURI
nsString anchor;
nsString href;
const char* resolved;
};
class AnchorTest : public ::testing::TestWithParam<AnchorTestData> {};
const AnchorTestData anchor_tests[] = {
{u"http://example.com/path/to/index.html"_ns, u""_ns, u"page.html"_ns,
"http://example.com/path/to/page.html"},
{u"http://example.com/path/to/index.html"_ns,
u"http://example.com/path/"_ns, u"page.html"_ns,
"http://example.com/path/page.html"},
{u"http://example.com/path/to/index.html"_ns,
u"http://example.com/path/"_ns, u"/page.html"_ns,
"http://example.com/page.html"},
{u"http://example.com/path/to/index.html"_ns, u".."_ns, u"page.html"_ns,
"http://example.com/path/page.html"},
{u"http://example.com/path/to/index.html"_ns, u".."_ns,
u"from/page.html"_ns, "http://example.com/path/from/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"/hello/"_ns,
u"page.html"_ns, "http://example.com/hello/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"/hello"_ns, u"page.html"_ns,
"http://example.com/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"#necko"_ns, u"page.html"_ns,
"http://example.com/path/to/page.html"},
{u"http://example.com/path/to/index.html"_ns, u"https://example.net/"_ns,
u"to/page.html"_ns, "https://example.net/to/page.html"},
};
LinkHeader LinkHeaderFromHrefAndAnchor(nsAString const& aHref,
nsAString const& aAnchor) {
LinkHeader l;
l.mHref = aHref;
l.mAnchor = aAnchor;
return l;
}
TEST_P(AnchorTest, Anchor) {
const AnchorTestData test = GetParam();
LinkHeader linkHeader = LinkHeaderFromHrefAndAnchor(test.href, test.anchor);
nsCOMPtr<nsIURI> baseURI;
ASSERT_TRUE(NS_SUCCEEDED(NS_NewURI(getter_AddRefs(baseURI), test.baseURI)));
nsCOMPtr<nsIURI> resolved;
ASSERT_TRUE(NS_SUCCEEDED(
linkHeader.NewResolveHref(getter_AddRefs(resolved), baseURI)));
ASSERT_STREQ(resolved->GetSpecOrDefault().get(), test.resolved);
}
INSTANTIATE_TEST_SUITE_P(TestLinkHeader, AnchorTest,
testing::ValuesIn(anchor_tests));