Commit 79011db8 authored by Marijn Kruisselbrink's avatar Marijn Kruisselbrink Committed by Commit Bot

[FS] Require a leading . in accepted extensions.

Implements the changes from https://github.com/WICG/native-file-system/pull/219.

Change-Id: Ic785f0362b5c73a843145c5384f063cf24770b7b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2360597
Commit-Queue: Victor Costan <pwnall@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799617}
parent bc60f1b7
...@@ -583,9 +583,9 @@ IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, AcceptsOptions) { ...@@ -583,9 +583,9 @@ IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, AcceptsOptions) {
auto result = auto result =
EvalJs(shell(), EvalJs(shell(),
"self.showOpenFilePicker({types: [" "self.showOpenFilePicker({types: ["
" {description: 'foo', accept: {'text/custom': ['txt', 'Js']}}," " {description: 'foo', accept: {'text/custom': ['.txt', '.Js']}},"
" {accept: {'image/jpeg': []}}," " {accept: {'image/jpeg': []}},"
" {accept: {'image/svg+xml': 'svg'}}," " {accept: {'image/svg+xml': '.svg'}},"
"]})"); "]})");
EXPECT_TRUE(result.error.find("aborted") != std::string::npos) EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
<< result.error; << result.error;
......
...@@ -71,6 +71,18 @@ constexpr bool IsHTTPWhitespace(UChar chr) { ...@@ -71,6 +71,18 @@ constexpr bool IsHTTPWhitespace(UChar chr) {
return chr == ' ' || chr == '\n' || chr == '\t' || chr == '\r'; return chr == ' ' || chr == '\n' || chr == '\t' || chr == '\r';
} }
bool AddExtension(const String& extension,
Vector<String>& extensions,
ExceptionState& exception_state) {
if (!extension.StartsWith(".")) {
exception_state.ThrowTypeError("Extension '" + extension +
"' must start with '.'.");
return false;
}
extensions.push_back(extension.Substring(1));
return true;
}
Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts( Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts(
const HeapVector<Member<FilePickerAcceptType>>& types, const HeapVector<Member<FilePickerAcceptType>>& types,
ExceptionState& exception_state) { ExceptionState& exception_state) {
...@@ -102,10 +114,16 @@ Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts( ...@@ -102,10 +114,16 @@ Vector<mojom::blink::ChooseFileSystemEntryAcceptsOptionPtr> ConvertAccepts(
} }
mimeTypes.push_back(type); mimeTypes.push_back(type);
if (a.second.IsUSVString()) if (a.second.IsUSVString()) {
extensions.push_back(a.second.GetAsUSVString()); if (!AddExtension(a.second.GetAsUSVString(), extensions,
else exception_state))
extensions.AppendVector(a.second.GetAsUSVStringSequence()); return {};
} else {
for (const auto& extension : a.second.GetAsUSVStringSequence()) {
if (!AddExtension(extension, extensions, exception_state))
return {};
}
}
} }
result.emplace_back( result.emplace_back(
blink::mojom::blink::ChooseFileSystemEntryAcceptsOption::New( blink::mojom::blink::ChooseFileSystemEntryAcceptsOption::New(
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
'show a file picker.<br />Please select native-file-system/resources/data/testfile.txt'); 'show a file picker.<br />Please select native-file-system/resources/data/testfile.txt');
const files = await self.showOpenFilePicker({ const files = await self.showOpenFilePicker({
multiple: false, types: [ multiple: false, types: [
{ description: 'Text files', accept: { ' text/plain ': ['txt'] } }, { description: 'Text files', accept: { ' text/plain ': ['.txt'] } },
{ description: 'Images', accept: { ' image/* ': ['jpg', 'jpeg', 'png'] } }, { description: 'Images', accept: { ' image/* ': ['.jpg', '.jpeg', '.png'] } },
], ],
}); });
assert_true(Array.isArray(files)); assert_true(Array.isArray(files));
......
...@@ -27,47 +27,47 @@ function define_file_picker_error_tests(showPickerMethod) { ...@@ -27,47 +27,47 @@ function define_file_picker_error_tests(showPickerMethod) {
promise_test(async t => { promise_test(async t => {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]({types: [{accept: {'': ['foo']}}]})); self[showPickerMethod]({types: [{accept: {'': ['.foo']}}]}));
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]({types: [{accept: {' ': ['foo']}}]})); self[showPickerMethod]({types: [{accept: {' ': ['.foo']}}]}));
}, showPickerMethod + ': MIME type can\'t be an empty string.'); }, showPickerMethod + ': MIME type can\'t be an empty string.');
promise_test(async t => { promise_test(async t => {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]({types: [{accept: {'image': ['foo']}}]})); self[showPickerMethod]({types: [{accept: {'image': ['.foo']}}]}));
}, showPickerMethod + ': MIME type must have subtype.'); }, showPickerMethod + ': MIME type must have subtype.');
promise_test(async t => { promise_test(async t => {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]({types: [{accept: {' /plain': ['foo']}}]})); self[showPickerMethod]({types: [{accept: {' /plain': ['.foo']}}]}));
}, showPickerMethod + ': MIME type can\'t have empty type.'); }, showPickerMethod + ': MIME type can\'t have empty type.');
promise_test(async t => { promise_test(async t => {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]({types: [{accept: {'image/ ': ['foo']}}]})); self[showPickerMethod]({types: [{accept: {'image/ ': ['.foo']}}]}));
}, showPickerMethod + ': MIME type can\'t have empty subtype.'); }, showPickerMethod + ': MIME type can\'t have empty subtype.');
promise_test(async t => { promise_test(async t => {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]( self[showPickerMethod](
{types: [{accept: {'text/plain;charset=utf8': ['txt']}}]})); {types: [{accept: {'text/plain;charset=utf8': ['.txt']}}]}));
}, showPickerMethod + ': MIME type can\'t have parameters.'); }, showPickerMethod + ': MIME type can\'t have parameters.');
promise_test(async t => { promise_test(async t => {
await promise_rejects_js(t, TypeError, self[showPickerMethod]({ await promise_rejects_js(t, TypeError, self[showPickerMethod]({
types: [{accept: {'text>foo/plain': ['txt']}}] types: [{accept: {'text>foo/plain': ['.txt']}}]
})); }));
}, showPickerMethod + ': MIME type can\'t have invalid characters in type.'); }, showPickerMethod + ': MIME type can\'t have invalid characters in type.');
promise_test(async t => { promise_test(async t => {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]({types: [{accept: {'text / plain': ['txt']}}]})); self[showPickerMethod]({types: [{accept: {'text / plain': ['.txt']}}]}));
}, showPickerMethod + ': MIME type can\'t have whitespace in the middle.'); }, showPickerMethod + ': MIME type can\'t have whitespace in the middle.');
promise_test( promise_test(
...@@ -75,8 +75,14 @@ function define_file_picker_error_tests(showPickerMethod) { ...@@ -75,8 +75,14 @@ function define_file_picker_error_tests(showPickerMethod) {
await promise_rejects_js( await promise_rejects_js(
t, TypeError, t, TypeError,
self[showPickerMethod]( self[showPickerMethod](
{types: [{accept: {'text/plain>foo': ['txt']}}]})); {types: [{accept: {'text/plain>foo': ['.txt']}}]}));
}, },
showPickerMethod + showPickerMethod +
': MIME type can\'t have invalid characters in subtype.'); ': MIME type can\'t have invalid characters in subtype.');
}
\ No newline at end of file promise_test(async t => {
await promise_rejects_js(t, TypeError, self[showPickerMethod]({
types: [{accept: {'text/plain': ['.txt', 'txt']}}]
}));
}, showPickerMethod + ': extension has to start with ".".');
}
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
'show a file picker.<br />Please make a copy of native-file-system/resources/data/testfile.txt in a writable directory and pick that file'); 'show a file picker.<br />Please make a copy of native-file-system/resources/data/testfile.txt in a writable directory and pick that file');
const file = await self.showSaveFilePicker({ const file = await self.showSaveFilePicker({
multiple: false, types: [ multiple: false, types: [
{ description: 'Text files', accept: { 'text/plain': ['txt'] } }, { description: 'Text files', accept: { 'text/plain': ['.txt'] } },
], ],
}); });
assert_true(file instanceof FileSystemHandle); assert_true(file instanceof FileSystemHandle);
......
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