Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose contentEncoding in PerformanceResourceTiming #50115

Merged
merged 1 commit into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions navigation-timing/content-encoding.https.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="variant" , content="?pipe=gzip">
<title>contentEncoding in navigation timing</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="http://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<script>
async_test(function (t) {
var observer = new PerformanceObserver(
t.step_func(function (entryList) {
assert_equals(entryList.getEntries()[0].contentEncoding, "gzip",
"Expected contentEncoding to be gzip.");
observer.disconnect();
t.done();
})
);
observer.observe({ entryTypes: ["navigation"] });

}, "contentEncoding should be gzip.");
</script>
</head>

<body>
<h1>
Description</h1>
<p>
This test validates that when a html is compressed with gzip, navigation timing reports contentEncoding as gzip</p>
</body>

</html>
107 changes: 107 additions & 0 deletions resource-timing/content-encoding.https.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>contentEncoding in resource timing</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming" />
<script src="/common/get-host-info.sub.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/entry-invariants.js"></script>
<script src="resources/resource-loaders.js"></script>
<script>

const { ORIGIN, REMOTE_ORIGIN } = get_host_info();

const run_same_origin_test = (path, contentEncoding) => {
const url = new URL(path, ORIGIN);
attribute_test(
fetch, url,
entry => {
assert_equals(entry.contentEncoding, contentEncoding,
`run_same_origin_test failed, unexpected contentEncoding value.`);
});
}

run_same_origin_test("/resource-timing/resources/compressed-data.py?content_encoding=dcb", "dcb");
run_same_origin_test("/resource-timing/resources/compressed-data.py?content_encoding=dcz", "dcz");
run_same_origin_test("/resource-timing/resources/gzip_xml.py", "gzip");
run_same_origin_test("/resource-timing/resources/foo.text.br", "br");
run_same_origin_test("/resource-timing/resources/foo.text.gz", "gzip");
run_same_origin_test("/resource-timing/resources/foo.text.zst", "zstd");
run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=deflate", "deflate");
run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=gzip", "gzip");
run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=identity", "identity");
// Unrecognized content encoding value should be transformed to "unknown".
run_same_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=unrecognizedname", "unknown");


const run_cross_origin_test = (path) => {
const url = new URL(path, REMOTE_ORIGIN);
attribute_test(
load.xhr_async, url,
entry => {
assert_equals(entry.contentEncoding, "",
`run_cross_origin_test failed, contentEncoding should be empty.`);
});
}

run_cross_origin_test("/resource-timing/resources/compressed-data.py?content_encoding=dcb");
run_cross_origin_test("/resource-timing/resources/gzip_xml.py");
run_cross_origin_test("/resource-timing/resources/compressed-data.py?content_encoding=dcz");
run_cross_origin_test("/resource-timing/resources/foo.text.br");
run_cross_origin_test("/resource-timing/resources/foo.text.gz");
run_cross_origin_test("/resource-timing/resources/foo.text.zst");
run_cross_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=deflate");
run_cross_origin_test("/resource-timing/resources/compressed-js.py?content_encoding=gzip");

const run_cross_origin_allowed_test = (path, contentEncoding) => {
const url = new URL(path, REMOTE_ORIGIN);
url.searchParams.set("allow_origin", ORIGIN);
attribute_test(
load.xhr_async, url,
entry => {
assert_equals(entry.contentEncoding, contentEncoding,
`run_cross_origin_allowed_test failed, unexpected contentEncoding value.`);
});
}

run_cross_origin_allowed_test("/resource-timing/resources/compressed-data.py?content_encoding=dcb", "dcb");
run_cross_origin_allowed_test("/resource-timing/resources/compressed-data.py?content_encoding=dcz", "dcz");
run_cross_origin_allowed_test("/resource-timing/resources/gzip_xml.py", "gzip");
run_cross_origin_allowed_test("/resource-timing/resources/compressed-js.py?content_encoding=deflate", "deflate");
run_cross_origin_allowed_test("/resource-timing/resources/compressed-js.py?content_encoding=gzip", "gzip");

// Content-Encoding for iframes is empty when cross origin redirects are present.
const multiRedirect = new URL(`${ORIGIN}/resource-timing/resources/multi_redirect.py`);
multiRedirect.searchParams.append("page_origin", ORIGIN);
multiRedirect.searchParams.append("cross_origin", REMOTE_ORIGIN);
multiRedirect.searchParams.append("final_resource", "/resource-timing/resources/compressed-js.py?content_encoding=gzip");
attribute_test(load.iframe, multiRedirect, (entry) => {
assert_equals(entry.contentEncoding, "",
`content-encoding should be empty for iframes having cross origin redirects`);
});


// Content-Encoding for iframes is exposed for same origin redirects.
const redirectCORS = new URL(`${ORIGIN}/resource-timing/resources/redirect-cors.py`);
const dest = `${ORIGIN}/resource-timing/resources/compressed-js.py?content_encoding=gzip`;
redirectCORS.searchParams.append("location", dest)
attribute_test(load.iframe, redirectCORS, (entry) => {
assert_equals(entry.contentEncoding, "gzip",
`content-encoding should be exposed for iframes having only same origin redirects`);
});

</script>
</head>

<body>
<h1>
Description</h1>
<p>
This test validates contentEncoding in resource timing.</p>
</body>

</html>
33 changes: 33 additions & 0 deletions resource-timing/resources/compressed-data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
def main(request, response):
response.headers.set(b"Content-Type", b"text/plain")

# `dcb_data` and `dcz_data` are generated using the following commands:
#
# $ echo "This is a test dictionary." > /tmp/dict
# $ echo -n "This is compressed test data using a test dictionary" \
# > /tmp/data
#
# $ echo -en '\xffDCB' > /tmp/out.dcb
# $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcb
# $ brotli --stdout -D /tmp/dict /tmp/data >> /tmp/out.dcb
# $ xxd -p /tmp/out.dcb | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
dcb_data = b"\xff\x44\x43\x42\x53\x96\x9b\xcf\x5e\x96\x0e\x0e\xdb\xf0\xa4\xbd\xde\x6b\x0b\x3e\x93\x81\xe1\x56\xde\x7f\x5b\x91\xce\x83\x91\x62\x42\x70\xf4\x16\xa1\x98\x01\x80\x62\xa4\x4c\x1d\xdf\x12\x84\x8c\xae\xc2\xca\x60\x22\x07\x6e\x81\x05\x14\xc9\xb7\xc3\x44\x8e\xbc\x16\xe0\x15\x0e\xec\xc1\xee\x34\x33\x3e\x0d"
# $ echo -en '\x5e\x2a\x4d\x18\x20\x00\x00\x00' > /tmp/out.dcz
# $ openssl dgst -sha256 -binary /tmp/dict >> /tmp/out.dcz
# $ zstd -D /tmp/dict -f -o /tmp/tmp.zstd /tmp/data
# $ cat /tmp/tmp.zstd >> /tmp/out.dcz
# $ xxd -p /tmp/out.dcz | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
dcz_data = b"\x5e\x2a\x4d\x18\x20\x00\x00\x00\x53\x96\x9b\xcf\x5e\x96\x0e\x0e\xdb\xf0\xa4\xbd\xde\x6b\x0b\x3e\x93\x81\xe1\x56\xde\x7f\x5b\x91\xce\x83\x91\x62\x42\x70\xf4\x16\x28\xb5\x2f\xfd\x24\x34\xf5\x00\x00\x98\x63\x6f\x6d\x70\x72\x65\x73\x73\x65\x64\x61\x74\x61\x20\x75\x73\x69\x6e\x67\x03\x00\x59\xf9\x73\x54\x46\x27\x26\x10\x9e\x99\xf2\xbc"

if b'content_encoding' in request.GET:
content_encoding = request.GET.first(b"content_encoding")
response.headers.set(b"Content-Encoding", content_encoding)
if content_encoding == b"dcb":
# Send the pre compressed file
response.content = dcb_data
if content_encoding == b"dcz":
# Send the pre compressed file
response.content = dcz_data

if b'allow_origin' in request.GET:
response.headers.set(b'access-control-allow-origin', request.GET.first(b'allow_origin'))
29 changes: 29 additions & 0 deletions resource-timing/resources/compressed-js.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os.path
import zlib
import gzip

def read(file):
path = os.path.join(os.path.dirname(__file__), file)
return open(path, u"rb").read()

def main(request, response):
response.headers.set(b"Content-Type", b"text/javascript")

if b'allow_origin' in request.GET:
response.headers.set(
b'access-control-allow-origin',
request.GET.first(b'allow_origin'))

if b'content_encoding' in request.GET:
content_encoding = request.GET.first(b"content_encoding")
response.headers.set(b"Content-Encoding", content_encoding)
if content_encoding == b"deflate":
response.content = zlib.compress(read(u"./dummy.js"))
if content_encoding == b"gzip":
response.content = gzip.compress(read(u"./dummy.js"))
if content_encoding == b"identity":
# Uncompressed
response.content = read(u"./dummy.js")
if content_encoding == b"unrecognizedname":
# Just return something
response.content = gzip.compress(read(u"./dummy.js"))
1 change: 1 addition & 0 deletions resource-timing/resources/dummy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// A dummy js file to be compressed and transferred.
Binary file added resource-timing/resources/foo.text.br
Binary file not shown.
2 changes: 2 additions & 0 deletions resource-timing/resources/foo.text.br.headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Content-type: text/plain
Content-Encoding: br
Binary file added resource-timing/resources/foo.text.gz
Binary file not shown.
2 changes: 2 additions & 0 deletions resource-timing/resources/foo.text.gz.headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Content-type: text/plain
Content-Encoding: gzip
Binary file added resource-timing/resources/foo.text.zst
Binary file not shown.
2 changes: 2 additions & 0 deletions resource-timing/resources/foo.text.zst.headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Content-type: text/plain
Content-Encoding: zstd
3 changes: 3 additions & 0 deletions resource-timing/resources/gzip_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ def main(request, response):
(b"Content-Encoding", b"gzip"),
(b"Content-Length", len(output))]

if b'allow_origin' in request.GET:
headers.append((b'access-control-allow-origin', request.GET.first(b'allow_origin')))

return headers, output
Loading