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, ...@@ -101,6 +101,8 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
return side_data_blob_; return side_data_blob_;
} }
bool IsMadeFromReadableStream() const { return made_from_readable_stream_; }
void Trace(Visitor*) const override; void Trace(Visitor*) const override;
private: private:
......
...@@ -648,6 +648,21 @@ Request* Request::CreateRequestWithRequestOrString( ...@@ -648,6 +648,21 @@ Request* Request::CreateRequestWithRequestOrString(
return nullptr; 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|. // "Set |r|'s request's body to |temporaryBody|.
if (temporary_body) if (temporary_body)
r->request_->SetBuffer(temporary_body); r->request_->SetBuffer(temporary_body);
......
...@@ -7,7 +7,7 @@ var {BASE_ORIGIN, OTHER_ORIGIN} = get_fetch_test_options(); ...@@ -7,7 +7,7 @@ var {BASE_ORIGIN, OTHER_ORIGIN} = get_fetch_test_options();
function fetch_echo(stream) { function fetch_echo(stream) {
return fetch( return fetch(
'/serviceworker/resources/fetch-echo-body.php', '/serviceworker/resources/fetch-echo-body.php',
{method: 'POST', body: stream}); {method: 'POST', body: stream, mode: 'same-origin'});
} }
function fetch_echo_body(stream) { function fetch_echo_body(stream) {
...@@ -126,10 +126,43 @@ promise_test(async () => { ...@@ -126,10 +126,43 @@ promise_test(async () => {
promise_test(async (t) => { promise_test(async (t) => {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
fetch('/serviceworker/resources/fetch-access-control.php?AuthFail', { fetch(
method: 'POST', '/serviceworker/resources/fetch-access-control.php?AuthFail',
body: create_foo_stream(), {method: 'POST', body: create_foo_stream(), mode: 'same-origin'}));
}));
}, 'Upload streaming with 401 Unauthorized response should fail.'); }, '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(),
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(); done();
<?php <?php
require_once '../../resources/portabilityLayer.php';
header('X-ServiceWorker-ServerHeader: SetInTheServer'); header('X-ServiceWorker-ServerHeader: SetInTheServer');
$prefix = ''; $prefix = '';
...@@ -10,6 +11,8 @@ $prefix = ''; ...@@ -10,6 +11,8 @@ $prefix = '';
// PACRMethod/Headers parameter, if set, in preflight. // PACRMethod/Headers parameter, if set, in preflight.
// The special value 'missing' for PACRHeaders can be used to // The special value 'missing' for PACRHeaders can be used to
// test for the absence of ACRHeaders on the preflight request. // 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'])) { if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && isset($_GET['PreflightTest'])) {
$prefix = 'P'; $prefix = 'P';
...@@ -37,8 +40,21 @@ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && isset($_GET['PreflightTest'])) { ...@@ -37,8 +40,21 @@ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && isset($_GET['PreflightTest'])) {
exit; exit;
} }
header("HTTP/1.1 {$_GET['PreflightTest']}"); 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'])) { if (isset($_GET[$prefix . 'ACAOrigin'])) {
$origins = explode(',', $_GET[$prefix . 'ACAOrigin']); $origins = explode(',', $_GET[$prefix . 'ACAOrigin']);
for ($i = 0; $i < sizeof($origins); ++$i) for ($i = 0; $i < sizeof($origins); ++$i)
...@@ -125,7 +141,8 @@ $arr = array('jsonpResult' => 'success', ...@@ -125,7 +141,8 @@ $arr = array('jsonpResult' => 'success',
'post' => $_POST, 'post' => $_POST,
'username' => $username, 'username' => $username,
'password' => $password, 'password' => $password,
'cookie' => $cookie); 'cookie' => $cookie,
'did_preflight' => $did_preflight);
$json = json_encode($arr); $json = json_encode($arr);
echo "report( $json );"; 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