Commit cd43f8fd authored by Yoichi Osato's avatar Yoichi Osato Committed by Commit Bot

[fetch] Upload streaming should always trigger CORS preflight

This CL implements a part of
https://fetch.spec.whatwg.org/#dom-request:
"
37: If body is non-null and body’s source is null, then:
 1. If r’s request’s mode is neither "same-origin" nor "cors", then
  throw a TypeError.
 2. Set r’s request’s use-CORS-preflight flag.
"

Bug: 688906
Change-Id: Ie8bb1ba8ae9a3e4dca69d73b9de4078791d5f39d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2235132Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Commit-Queue: Yoichi Osato <yoichio@chromium.org>
Cr-Commit-Position: refs/heads/master@{#780238}
parent 3cd8a7b8
......@@ -101,6 +101,8 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
return side_data_blob_;
}
bool IsMadeFromReadableStream() const { return made_from_readable_stream_; }
void Trace(Visitor*) const override;
private:
......
......@@ -648,6 +648,21 @@ Request* Request::CreateRequestWithRequestOrString(
return nullptr;
}
// If body is non-null and body’s source is null, then:
if (temporary_body && temporary_body->IsMadeFromReadableStream()) {
// If r’s request’s mode is neither "same-origin" nor "cors", then throw a
// TypeError.
if (request->Mode() != network::mojom::RequestMode::kSameOrigin &&
request->Mode() != network::mojom::RequestMode::kCors) {
exception_state.ThrowTypeError(
"If request is made from ReadableStream, mode should be"
"\"same-origin\" or \"cors\"");
return nullptr;
}
// Set r’s request’s use-CORS-preflight flag.
request->SetMode(network::mojom::RequestMode::kCorsWithForcedPreflight);
}
// "Set |r|'s request's body to |temporaryBody|.
if (temporary_body)
r->request_->SetBuffer(temporary_body);
......
......@@ -7,7 +7,7 @@ var {BASE_ORIGIN, OTHER_ORIGIN} = get_fetch_test_options();
function fetch_echo(stream) {
return fetch(
'/serviceworker/resources/fetch-echo-body.php',
{method: 'POST', body: stream});
{method: 'POST', body: stream, mode: 'same-origin'});
}
function fetch_echo_body(stream) {
......@@ -126,10 +126,43 @@ promise_test(async () => {
promise_test(async (t) => {
await promise_rejects_js(
t, TypeError,
fetch('/serviceworker/resources/fetch-access-control.php?AuthFail', {
fetch(
'/serviceworker/resources/fetch-access-control.php?AuthFail',
{method: 'POST', body: create_foo_stream(), mode: 'same-origin'}));
}, 'Upload streaming with 401 Unauthorized response should fail.');
function report(content) {
return content;
}
promise_test(async () => {
const request_url = OTHER_ORIGIN +
'/serviceworker/resources/fetch-access-control.php?' +
`ACAOrigin=*&PACAOrigin=*` +
`&PACAHeaders=*&ACAHeaders=*&PreflightTest` +
`&PACMAge=600&Token=${Date.now()}`
const response_text = await fetch(request_url, {
method: 'POST',
body: 'content a',
mode: 'cors'
}).then(r => r.text());
const report_json = eval(response_text);
assert_false(report_json['did_preflight'], 'Should not trigger preflight');
}, 'Uploading text w/o header does not trigger preflight');
promise_test(async () => {
const request_url = OTHER_ORIGIN +
'/serviceworker/resources/fetch-access-control.php?' +
`ACAOrigin=*&PACAOrigin=*` +
`&PACAHeaders=*&ACAHeaders=*&PreflightTest` +
`&PACMAge=600&Token=${Date.now()}`
const response_text = await fetch(request_url, {
method: 'POST',
body: create_foo_stream(),
}));
}, 'Upload streaming with 401 Unauthorized response should fail.');
mode: 'cors',
}).then(r => r.text());
const report_json = eval(response_text);
assert_true(report_json['did_preflight'], 'Should preflight');
}, 'Uploading stream always trigger preflight');
done();
<?php
require_once '../../resources/portabilityLayer.php';
header('X-ServiceWorker-ServerHeader: SetInTheServer');
$prefix = '';
......@@ -10,6 +11,8 @@ $prefix = '';
// PACRMethod/Headers parameter, if set, in preflight.
// The special value 'missing' for PACRHeaders can be used to
// test for the absence of ACRHeaders on the preflight request.
clearstatcache();
$tmp_file = isset($_GET['Token']) ? (sys_get_temp_dir() . "/" . $_GET['Token']) : 'undefined';
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && isset($_GET['PreflightTest'])) {
$prefix = 'P';
......@@ -37,8 +40,21 @@ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && isset($_GET['PreflightTest'])) {
exit;
}
header("HTTP/1.1 {$_GET['PreflightTest']}");
if (isset($_GET['Token'])) {
touch($tmp_file);
}
}
$did_preflight = false;
if ($_SERVER['REQUEST_METHOD'] != 'OPTIONS' && file_exists($tmp_file)) {
$did_preflight = true;
unlink($tmp_file);
}
if (isset($_GET['PACMAge']))
header('Access-Control-Max-Age: ' . $_GET['PACMAge']);
if (isset($_GET[$prefix . 'ACAOrigin'])) {
$origins = explode(',', $_GET[$prefix . 'ACAOrigin']);
for ($i = 0; $i < sizeof($origins); ++$i)
......@@ -125,7 +141,8 @@ $arr = array('jsonpResult' => 'success',
'post' => $_POST,
'username' => $username,
'password' => $password,
'cookie' => $cookie);
'cookie' => $cookie,
'did_preflight' => $did_preflight);
$json = json_encode($arr);
echo "report( $json );";
?>
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