Skip to content

Commit

Permalink
Add response status code to Resource Timing
Browse files Browse the repository at this point in the history
This CL introduces a responseStatus field to Performance Resource Timing object.
This field is behind a Runtime Enabled Flag.
Resource Timing PR : w3c/resource-timing#335
Fetch PR : whatwg/fetch#1468

Bug:1343293
Change-Id: I60d1b6ba00f055481ca526a490144d88ddaf881b
  • Loading branch information
abinpaul1 authored and chromium-wpt-export-bot committed Aug 30, 2022
1 parent 527425c commit 4fa5a46
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 10 deletions.
45 changes: 36 additions & 9 deletions resource-timing/resources/resource-loaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@ const load = {
return url.href;
},

// Returns a promise that settles once the given path has been fetched as an
// image resource.
image: path => {
image_with_attrs: async (path, attribute_map) => {
return new Promise(resolve => {
const img = new Image();
if (attribute_map instanceof Object) {
for (const [key, value] of Object.entries(attribute_map)) {
img[key] = value;
}
}
img.onload = img.onerror = resolve;
img.src = load.cache_bust(path);
});
},

// Returns a promise that settles once the given path has been fetched as an
// image resource.
image: path => {
return load.image_with_attrs(path, undefined);
},

// Returns a promise that settles once the given path has been fetched as a
// font resource.
font: path => {
Expand All @@ -37,10 +46,13 @@ const load = {
});
},

// Returns a promise that settles once the given path has been fetched as a
// stylesheet resource.
stylesheet: async path => {
stylesheet_with_attrs: async (path, attribute_map) => {
const link = document.createElement("link");
if (attribute_map instanceof Object) {
for (const [key, value] of Object.entries(attribute_map)) {
link[key] = value;
}
}
link.rel = "stylesheet";
link.type = "text/css";
link.href = load.cache_bust(path);
Expand All @@ -54,6 +66,12 @@ const load = {
document.head.removeChild(link);
},

// Returns a promise that settles once the given path has been fetched as a
// stylesheet resource.
stylesheet: async path => {
return load.stylesheet_with_attrs(path, undefined);
},

iframe_with_attrs: async (path, attribute_map, validator) => {
const frame = document.createElement("iframe");
if (attribute_map instanceof Object) {
Expand All @@ -79,10 +97,13 @@ const load = {
return load.iframe_with_attrs(path, undefined, validator);
},

// Returns a promise that settles once the given path has been fetched as a
// script.
script: async path => {
script_with_attrs: async (path, attribute_map) => {
const script = document.createElement("script");
if (attribute_map instanceof Object) {
for (const [key, value] of Object.entries(attribute_map)) {
script[key] = value;
}
}
const loaded = new Promise(resolve => {
script.onload = script.onerror = resolve;
});
Expand All @@ -92,6 +113,12 @@ const load = {
document.body.removeChild(script);
},

// Returns a promise that settles once the given path has been fetched as a
// script.
script: async path => {
return load.script_with_attrs(path, undefined);
},

// Returns a promise that settles once the given path has been fetched as an
// object.
object: async (path, type) => {
Expand Down
2 changes: 2 additions & 0 deletions resource-timing/resources/status-code.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ def main(request, response):
response.status = (status, b"");
if b'tao_value' in request.GET:
response.headers.set(b'timing-allow-origin', request.GET.first(b'tao_value'))
if b'allow_origin' in request.GET:
response.headers.set(b'access-control-allow-origin', request.GET.first(b'allow_origin'))

110 changes: 110 additions & 0 deletions resource-timing/response-status-code.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>This test validates the response status of resources.</title>
<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming"/>
<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 src="/common/get-host-info.sub.js"></script>
</head>
<body>
<script>
const {ORIGIN, REMOTE_ORIGIN} = get_host_info();
const status_codes = [
200, 203,
400, 401, 403, 404,
500, 501, 502, 503,
];

// Response status for same origin resources is exposed
const run_test = (loader, status) => {
let path = `/resource-timing/resources/status-code.py?status=${status}`;
const url = new URL(path, ORIGIN);
attribute_test(
loader, url,
entry => {
assert_equals(entry.responseStatus, status,
`response status for ${entry.name} should be ${status}`);
});
}

let resource_loaders = [
load.font,
load.image,
load.script,
load.stylesheet,
load.xhr_sync,
load.xhr_async,
load.iframe
];

resource_loaders.forEach(loader => {
status_codes.forEach(status => run_test(
loader, status
));
});


// Response status is exposed for cors request for cross-origin resources
const run_test_cross_origin_allow_origin = (loader_with_attr,status) => {
let path = `/resource-timing/resources/status-code.py?status=${status}&allow_origin=${ORIGIN}`;
const url = new URL(path, REMOTE_ORIGIN);
loader_with_crossOrigin_attr = async url => {
return loader_with_attr(url, {"crossOrigin": "anonymous"});
}
attribute_test(
loader_with_crossOrigin_attr, url,
entry => {
assert_equals(entry.responseStatus, status,
`response status for ${entry.name} should be ${status}`);
});
}

resource_loaders = [
load.image_with_attrs,
load.script_with_attrs,
load.stylesheet_with_attrs
];

resource_loaders.forEach(loader => {
status_codes.forEach(status => run_test_cross_origin_allow_origin(
loader, status
));
});


// Response status is 0 when a no-cors request is made for cross origin
// fonts, images, scripts, stylesheets.
// Response status is 0 when request's mode is "navigate" and response's
// URL's origin is not same origin with request's origin. So response
// status is not exposed for cross origin iframes.
const run_test_cross_origin = (loader, status) => {
let path = `/resource-timing/resources/status-code.py?status=${status}`;
const url = new URL(path, REMOTE_ORIGIN);
attribute_test(
loader, url,
entry => {
assert_equals(entry.responseStatus, 0,
`response status for ${entry.name} should be 0`);
});
}

resource_loaders = [
load.font,
load.image,
load.script,
load.stylesheet,
load.iframe
];

resource_loaders.forEach(loader => {
status_codes.forEach(status => run_test_cross_origin(
loader, status
));
});

</script>
</body>
</html>
3 changes: 2 additions & 1 deletion resource-timing/tojson.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
'transferSize',
'encodedBodySize',
'decodedBodySize',
'renderBlockingStatus'
'renderBlockingStatus',
'responseStatus',
];
for (const key of performanceResourceTimingKeys) {
try {
Expand Down

0 comments on commit 4fa5a46

Please sign in to comment.