Commit e08b8456 authored by Dominic Farolino's avatar Dominic Farolino Committed by Commit Bot

Add temporary fetch() UseCounters

This CL addresses crbug.com/1072350 by adding two UseCounters:

 - One to count requests whose
    - method != ("GET" || "HEAD")
    - mode == kNoCors
    - response is opaque
 - Another to count requests that meet the same criteria as above, but
   have experienced at least one redirect.

This CL also adds tests to ensure that the UseCounter is counted
properly:

  Tests:
    - Not enough conditions are met for the UseCounter:
       - No conditions met: (GET, "cors", basic)
       - One condition met: (POST, "cors" basic)
       - One condition met: (GET, "no-cors" basic)
       - One condition met: (GET, "no-cors", opaqueredirect)
       - Two condition met: (POST, "no-cors", basic)
       - Two condition met: (GET, "no-cors", opaque)
    - All conditions are met:
       - (POST, "no-cors", opaque): Cross-origin, no redirect
         - Should count first counter, but not second
       - (POST, "no-cors", opaque): Cross-origin Redirect involved
         - Should count both UseCounters

R=kinuko@chromium.org, ricea@chromium.org, yhirano@chromium.org

Bug: 1072350
Change-Id: I13331a8ca51a9cdd684ddb8b88f3232117426320
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2242205
Commit-Queue: Dominic Farolino <dom@chromium.org>
Reviewed-by: default avatarHiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#778021}
parent 9fc5be27
......@@ -2650,6 +2650,8 @@ enum WebFeature {
kRubyTextWithNonDefaultTextAlign = 3313,
kHTMLMetaElementReferrerPolicyOutsideHead = 3314,
kHTMLMetaElementReferrerPolicyMultipleTokens = 3315,
kFetchAPINonGetOrHeadOpaqueResponse = 3316,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect = 3317,
// Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots.
......
......@@ -407,6 +407,20 @@ void FetchManager::Loader::DidReceiveResponse(
}
}
// TODO(crbug.com/1072350): Remove this once enough data is collected.
if (fetch_request_data_->Method() != http_names::kGET &&
fetch_request_data_->Method() != http_names::kGET &&
fetch_request_data_->Mode() == network::mojom::RequestMode::kNoCors &&
tainting == FetchRequestData::kOpaqueTainting) {
UseCounter::Count(execution_context_,
WebFeature::kFetchAPINonGetOrHeadOpaqueResponse);
if (url_list_.size() > 1) {
UseCounter::Count(
execution_context_,
WebFeature::kFetchAPINonGetOrHeadOpaqueResponseWithRedirect);
}
}
place_holder_body_ = MakeGarbageCollected<PlaceHolderBytesConsumer>();
FetchResponseData* response_data = FetchResponseData::CreateWithBuffer(
BodyStreamBuffer::Create(script_state, place_holder_body_, signal_));
......
<!doctype html>
<head>
<meta name="timeout" content="long"></meta>
<script src = "/resources/get-host-info.js?pipe=sub"></script>
<script src = "/resources/testharness.js"></script>
<script src = "/resources/testharnessreport.js"></script>
<script src = "/serviceworker/resources/test-helpers.js"></script>
<script src = "/fetch/resources/fetch-test-options.js"></script>
<script src = "/fetch/resources/fetch-test-helpers.js"></script>
</head>
<body>
<script>
// The tests in this file are solely used for for the UseCounters associated
// with crbug.com/1072350.
const {BASE_ORIGIN, OTHER_ORIGIN} = get_fetch_test_options();
const kFetchAPINonGetOrHeadOpaqueResponse = 3316,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect = 3317;
const cross_origin_url = OTHER_ORIGIN + '/fetch/resources/fetch-status.php?status=200';
// These test that the UseCounters are not incorrectly counted.
// No conditions met: (GET, "cors", basic)
promise_test(t => {
return fetch("/fetch/resources/fetch-status.php?status=200",
{method: 'GET', mode: 'cors'})
.then(response => {
assert_equals(response.type, 'basic');
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
});
}, "Requests whose method=GET, mode=cors, and response type=basic do not " +
"count the UseCounters");
// One condition met: (POST, "cors" basic)
promise_test(t => {
return fetch("/fetch/resources/fetch-status.php?status=200",
{method: 'POST', mode: 'cors'})
.then(response => {
assert_equals(response.type, 'basic');
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
});
}, "Requests whose method=POST, mode=cors, and response type=basic do not " +
"count the UseCounters");
// One condition met: (GET, "no-cors" basic)
promise_test(t => {
return fetch("/fetch/resources/fetch-status.php?status=200",
{method: 'GET', mode: 'no-cors'})
.then(response => {
assert_equals(response.type, 'basic');
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
});
}, "Requests whose method=GET, mode=no-cors, and response type=basic do not " +
"count the UseCounters");
// One condition met: (GET, "no-cors", opaqueredirect) - {redirect: 'manual'}
promise_test(t => {
const redirect_target_url =
BASE_ORIGIN + '/fetch/resources/fetch-status.php?status=200';
const redirect_original_url =
BASE_ORIGIN + '/serviceworker/resources/redirect.php?Redirect=' +
redirect_target_url;
return fetch(redirect_original_url,
{method: 'GET', mode: 'no-cors', redirect: 'manual'})
.then(response => {
assert_equals(response.type, 'opaqueredirect');
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
});
}, "Requests whose method=GET, mode=no-cors, and response " +
"type=opaqueredirect do not count the UseCounters");
// Two conditions met: (POST, "no-cors", basic)
promise_test(t => {
return fetch('/fetch/resources/fetch-status.php?status=200',
{method: 'POST', mode: 'no-cors'})
.then(response => {
assert_equals(response.type, 'basic');
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
});
}, "Requests whose method=POST, mode=no-cors, and response type=basic do not " +
"count the UseCounters");
// Two conditions met: (GET, "no-cors", opaque)
promise_test(t => {
return fetch(cross_origin_url, {method: 'GET', mode: 'no-cors'})
.then(response => {
assert_equals(response.type, 'opaque');
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
});
}, "Requests whose method=GET, mode=no-cors, and response type=opaque do not " +
"count the UseCounters");
// These test that the UseCounters are being correctly counted.
promise_test(t => {
return fetch(cross_origin_url, {method: 'POST', mode: 'no-cors'})
.then(response => {
assert_equals(response.type, 'opaque');
assert_true(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_false(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
internals.clearUseCounter(document, kFetchAPINonGetOrHeadOpaqueResponse);
});
}, "Requests whose method=POST, mode=no-cors, and response type=opaque " +
"counts one of the UseCounters");
promise_test(t => {
const redirect_target_url =
OTHER_ORIGIN + '/fetch/resources/fetch-status.php?status=200';
const redirect_original_url =
OTHER_ORIGIN + '/serviceworker/resources/redirect.php?Redirect=' +
redirect_target_url;
return fetch(redirect_original_url, {method: 'POST', mode: 'no-cors'})
.then(response => {
assert_equals(response.type, 'opaque');
assert_true(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_true(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
internals.clearUseCounter(document,
kFetchAPINonGetOrHeadOpaqueResponse);
internals.clearUseCounter(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect);
});
}, "Requests whose method=POST, mode=no-cors, and response type=opaque an " +
"experiences a cross-origin => cross-origin redirect counts both UseCounters");
promise_test(t => {
const redirect_target_url =
OTHER_ORIGIN + '/fetch/resources/fetch-status.php?status=200';
const redirect_original_url =
OTHER_ORIGIN + '/serviceworker/resources/redirect.php?Redirect=' +
redirect_target_url;
return fetch(redirect_original_url, {method: 'POST', mode: 'no-cors'})
.then(response => {
assert_equals(response.type, 'opaque');
assert_true(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponse));
assert_true(internals.isUseCounted(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect));
internals.clearUseCounter(document,
kFetchAPINonGetOrHeadOpaqueResponse);
internals.clearUseCounter(document,
kFetchAPINonGetOrHeadOpaqueResponseWithRedirect);
});
}, "Requests whose method=POST, mode=no-cors, and response type=opaque an " +
"experiences a same-origin => cross-origin redirect counts both UseCounters");
done();
</script>
</body>
......@@ -27707,6 +27707,8 @@ Called by update_use_counter_feature_enum.py.-->
<int value="3313" label="RubyTextWithNonDefaultTextAlign"/>
<int value="3314" label="HTMLMetaElementReferrerPolicyOutsideHead"/>
<int value="3315" label="HTMLMetaElementReferrerPolicyMultipleTokens"/>
<int value="3316" label="FetchAPINonGetOrHeadOpaqueResponse"/>
<int value="3317" label="FetchAPINonGetOrHeadOpaqueResponseWithRedirect"/>
</enum>
<enum name="FeaturePolicyAllowlistType">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment