diff options
author | costan@gmail.com <costan@gmail.com@bbb929c8-8fbe-4397-9dbb-9b2b20218538> | 2013-11-15 13:24:42 +0000 |
---|---|---|
committer | costan@gmail.com <costan@gmail.com@bbb929c8-8fbe-4397-9dbb-9b2b20218538> | 2013-11-15 13:24:42 +0000 |
commit | 83dc38cd16e7cc8dec3d0f9224a8d4a2e453459f (patch) | |
tree | a4b52e7b1a6c1709431a6745dfb2371711311b4a | |
parent | 4a2309898062a594325174ab56c5018cf1be2c95 (diff) | |
download | chromium_src-83dc38cd16e7cc8dec3d0f9224a8d4a2e453459f.zip chromium_src-83dc38cd16e7cc8dec3d0f9224a8d4a2e453459f.tar.gz chromium_src-83dc38cd16e7cc8dec3d0f9224a8d4a2e453459f.tar.bz2 |
Implement File constructor.
The feature is behind the FileConstructor RuntimeEnabledFeature with
status=experimental.
BUG=164933
Review URL: https://codereview.chromium.org/57483002
git-svn-id: svn://svn.chromium.org/blink/trunk@162116 bbb929c8-8fbe-4397-9dbb-9b2b20218538
39 files changed, 1362 insertions, 453 deletions
diff --git a/third_party/WebKit/LayoutTests/fast/files/blob-constructor-expected.txt b/third_party/WebKit/LayoutTests/fast/files/blob-constructor-expected.txt index 35e7b05..8d65661 100644 --- a/third_party/WebKit/LayoutTests/fast/files/blob-constructor-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/files/blob-constructor-expected.txt @@ -24,13 +24,13 @@ PASS (new Blob([document])).size is 21 PASS (new Blob([toStringingObj])).size is 8 PASS new Blob([throwingObj]) threw exception Error. PASS (new Blob([], {unknownKey:'value'})) instanceof window.Blob is true -PASS new Blob([], {endings:'illegalValue'}) threw exception TypeError: Failed to construct 'Blob': The 2nd argument's "endings" property must be either "transparent" or "native".. +PASS new Blob([], {endings:'illegalValue'}) threw exception TypeError: Failed to construct 'Blob': The "endings" property must be either "transparent" or "native".. PASS new Blob([], {endings:throwingObj}) threw exception Error. PASS new Blob([], {type:throwingObj}) threw exception Error. -PASS new Blob([], {type:'helloĆ®'}) threw exception SyntaxError: Failed to construct 'Blob': The 2nd argument's "type" property must consist of ASCII characters.. +PASS new Blob([], {type:'helloĆ®'}) threw exception SyntaxError: Failed to construct 'Blob': The "type" property must consist of ASCII characters.. PASS new Blob([], {endings:throwingObj1, type:throwingObj2}) threw exception Error 1. PASS new Blob([], {type:throwingObj2, endings:throwingObj1}) threw exception Error 1. -PASS new Blob([], {type:throwingObj2, endings:'illegal'}) threw exception TypeError: Failed to construct 'Blob': The 2nd argument's "endings" property must be either "transparent" or "native".. +PASS new Blob([], {type:throwingObj2, endings:'illegal'}) threw exception TypeError: Failed to construct 'Blob': The "endings" property must be either "transparent" or "native".. PASS (new Blob([], null)) instanceof window.Blob threw exception TypeError: Failed to construct 'Blob': The 2nd argument is not of type Object.. PASS (new Blob([], undefined)) instanceof window.Blob threw exception TypeError: Failed to construct 'Blob': The 2nd argument is not of type Object.. PASS (new Blob([], 123)) instanceof window.Blob threw exception TypeError: Failed to construct 'Blob': The 2nd argument is not of type Object.. @@ -43,7 +43,7 @@ PASS (new Blob([], function () {})) instanceof window.Blob is true PASS (new Blob([], {type:'text/html'})).type is 'text/html' PASS (new Blob([], {type:'text/html'})).size is 0 PASS (new Blob([], {type:'text/plain;charset=UTF-8'})).type is 'text/plain;charset=utf-8' -FAIL window.Blob.length should be 2. Was 0. +PASS window.Blob.length is 0 PASS new Blob([new DataView(new ArrayBuffer(100))]).size is 100 PASS new Blob([new Uint8Array(100)]).size is 100 PASS new Blob([new Uint8ClampedArray(100)]).size is 100 @@ -73,7 +73,7 @@ PASS new Blob({length: 0}).size is 0 PASS new Blob({length: 1, 0: 'string'}).size is 6 PASS new Blob({length: 2, 0: new Uint8Array(100), 1: new Int16Array(100)}).size is 300 PASS new Blob({length: 1, 0: 'string'}, {type: 'text/html'}).type is 'text/html' -PASS new Blob({length: 0}, {endings:'illegal'}) threw exception TypeError: Failed to construct 'Blob': The 2nd argument's "endings" property must be either "transparent" or "native".. +PASS new Blob({length: 0}, {endings:'illegal'}) threw exception TypeError: Failed to construct 'Blob': The "endings" property must be either "transparent" or "native".. PASS new Blob(throwingSequence) threw exception Error: Misbehaving property. PASS successfullyParsed is true diff --git a/third_party/WebKit/LayoutTests/fast/files/blob-constructor.html b/third_party/WebKit/LayoutTests/fast/files/blob-constructor.html index 08e22a9..f5c125f 100644 --- a/third_party/WebKit/LayoutTests/fast/files/blob-constructor.html +++ b/third_party/WebKit/LayoutTests/fast/files/blob-constructor.html @@ -1,9 +1,119 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> +<!DOCTYPE html> + <script src="../../resources/js-test.js"></script> -</head> -<body> -<script src="script-tests/blob-constructor.js"></script> -</body> -</html> +<script> +description("Test the Blob constructor."); + +// Test the different ways you can construct a Blob. +shouldBeTrue("(new Blob()) instanceof window.Blob"); +shouldBeTrue("(new Blob([])) instanceof window.Blob"); +shouldBeTrue("(new Blob(['hello'])) instanceof window.Blob"); +shouldBeTrue("(new Blob(['hello'], {})) instanceof window.Blob"); +shouldBeTrue("(new Blob(['hello'], {type:'text/html'})) instanceof window.Blob"); +shouldBeTrue("(new Blob(['hello'], {type:'text/html', endings:'native'})) instanceof window.Blob"); +shouldBeTrue("(new Blob(['hello'], {type:'text/html', endings:'transparent'})) instanceof window.Blob"); + +// Test invalid blob parts. +shouldThrow("new Blob('hello')", '"TypeError: Failed to construct \'Blob\': The 1st argument is neither an array, nor does it have indexed properties."'); +shouldThrow("new Blob(0)", '"TypeError: Failed to construct \'Blob\': The 1st argument is neither an array, nor does it have indexed properties."'); + +// Test valid blob parts. +shouldBeTrue("(new Blob([])) instanceof window.Blob"); +shouldBeTrue("(new Blob(['stringPrimitive'])) instanceof window.Blob"); +shouldBeTrue("(new Blob([String('stringObject')])) instanceof window.Blob"); +shouldBeTrue("(new Blob([new Blob])) instanceof window.Blob"); +shouldBeTrue("(new Blob([new Blob([new Blob])])) instanceof window.Blob"); + +// Test some conversions to string in the parts array. +shouldBe("(new Blob([12])).size", "2"); +shouldBe("(new Blob([[]])).size", "0"); // [].toString() is the empty string +shouldBe("(new Blob([{}])).size", "15");; // {}.toString() is the string "[object Object]" +shouldBe("(new Blob([document])).size", "21"); // document.toString() is the string "[object HTMLDocument]" + +var toStringingObj = { toString: function() { return "A string"; } }; +shouldBe("(new Blob([toStringingObj])).size", "8"); + +var throwingObj = { toString: function() { throw "Error"; } }; +shouldThrow("new Blob([throwingObj])", "'Error'"); + +// Test some invalid property bags. +shouldBeTrue("(new Blob([], {unknownKey:'value'})) instanceof window.Blob"); // Ignore invalid keys +shouldThrow("new Blob([], {endings:'illegalValue'})", "'TypeError: Failed to construct \\'Blob\\': The \"endings\" property must be either \"transparent\" or \"native\".'"); +shouldThrow("new Blob([], {endings:throwingObj})", "'Error'"); +shouldThrow("new Blob([], {type:throwingObj})", "'Error'"); +shouldThrow("new Blob([], {type:'hello\u00EE'})", "'SyntaxError: Failed to construct \\'Blob\\': The \"type\" property must consist of ASCII characters.'"); + +// Test that order of property bag evaluation is lexigraphical +var throwingObj1 = { toString: function() { throw "Error 1"; } }; +var throwingObj2 = { toString: function() { throw "Error 2"; } }; +shouldThrow("new Blob([], {endings:throwingObj1, type:throwingObj2})", "'Error 1'"); +shouldThrow("new Blob([], {type:throwingObj2, endings:throwingObj1})", "'Error 1'"); +shouldThrow("new Blob([], {type:throwingObj2, endings:'illegal'})", "'TypeError: Failed to construct \\'Blob\\': The \"endings\" property must be either \"transparent\" or \"native\".'"); + +// Test various non-object literals being used as property bags. +shouldThrow("(new Blob([], null)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); +shouldThrow("(new Blob([], undefined)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); +shouldThrow("(new Blob([], 123)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); +shouldThrow("(new Blob([], 123.4)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); +shouldThrow("(new Blob([], true)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); +shouldThrow("(new Blob([], 'abc')) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); +shouldBeTrue("(new Blob([], [])) instanceof window.Blob"); +shouldBeTrue("(new Blob([], /abc/)) instanceof window.Blob"); +shouldBeTrue("(new Blob([], function () {})) instanceof window.Blob"); + +// Test that the type/size is correctly added to the Blob +shouldBe("(new Blob([], {type:'text/html'})).type", "'text/html'"); +shouldBe("(new Blob([], {type:'text/html'})).size", "0"); +shouldBe("(new Blob([], {type:'text/plain;charset=UTF-8'})).type", "'text/plain;charset=utf-8'"); + +// Test the number of expected arguments in the Blob constructor. +shouldBe("window.Blob.length", "0"); + +// Test ArrayBufferView parameters. +shouldBe("new Blob([new DataView(new ArrayBuffer(100))]).size", "100"); +shouldBe("new Blob([new Uint8Array(100)]).size", "100"); +shouldBe("new Blob([new Uint8ClampedArray(100)]).size", "100"); +shouldBe("new Blob([new Uint16Array(100)]).size", "200"); +shouldBe("new Blob([new Uint32Array(100)]).size", "400"); +shouldBe("new Blob([new Int8Array(100)]).size", "100"); +shouldBe("new Blob([new Int16Array(100)]).size", "200"); +shouldBe("new Blob([new Int32Array(100)]).size", "400"); +shouldBe("new Blob([new Float32Array(100)]).size", "400"); +shouldBe("new Blob([new Float64Array(100)]).size", "800"); +shouldBe("new Blob([new Float64Array(100), new Int32Array(100), new Uint8Array(100), new DataView(new ArrayBuffer(100))]).size", "1400"); +shouldBe("new Blob([new Blob([new Int32Array(100)]), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))]).size", "1000"); + +// Test ArrayBuffer parameters. +shouldBe("new Blob([(new DataView(new ArrayBuffer(100))).buffer]).size", "100"); +shouldBe("new Blob([(new Uint8Array(100)).buffer]).size", "100"); +shouldBe("new Blob([(new Uint8ClampedArray(100)).buffer]).size", "100"); +shouldBe("new Blob([(new Uint16Array(100)).buffer]).size", "200"); +shouldBe("new Blob([(new Uint32Array(100)).buffer]).size", "400"); +shouldBe("new Blob([(new Int8Array(100)).buffer]).size", "100"); +shouldBe("new Blob([(new Int16Array(100)).buffer]).size", "200"); +shouldBe("new Blob([(new Int32Array(100)).buffer]).size", "400"); +shouldBe("new Blob([(new Float32Array(100)).buffer]).size", "400"); +shouldBe("new Blob([(new Float64Array(100)).buffer]).size", "800"); +shouldBe("new Blob([(new Float64Array(100)).buffer, (new Int32Array(100)).buffer, (new Uint8Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size", "1400"); +shouldBe("new Blob([new Blob([(new Int32Array(100)).buffer]), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size", "1000"); + +// Test passing blob parts in sequences. +shouldBeTrue("new Blob({length: 0}) instanceof window.Blob"); +shouldBe("new Blob({length: 0}).size", "0"); +shouldBe("new Blob({length: 1, 0: 'string'}).size", "6"); +shouldBe("new Blob({length: 2, 0: new Uint8Array(100), 1: new Int16Array(100)}).size", "300"); +shouldBe("new Blob({length: 1, 0: 'string'}, {type: 'text/html'}).type", "'text/html'"); +shouldThrow("new Blob({length: 0}, {endings:'illegal'})", "'TypeError: Failed to construct \\'Blob\\': The \"endings\" property must be either \"transparent\" or \"native\".'"); + +// Test passing blog parts in a sequence-like object that throws on property access. +var throwingSequence = {length: 4, 0: 'hello', 3: 'world'}; +Object.defineProperty(throwingSequence, "1", { + get: function() { throw new Error("Misbehaving property"); }, + enumerable: true, configurable: true +}); +Object.defineProperty(throwingSequence, "2", { + get: function() { throw new Error("This should not be thrown"); }, + enumerable: true, configurable: true +}); +shouldThrow("new Blob(throwingSequence)", "'Error: Misbehaving property'"); +</script> diff --git a/third_party/WebKit/LayoutTests/fast/files/blob-parts-slice-test-expected.txt b/third_party/WebKit/LayoutTests/fast/files/blob-parts-slice-test-expected.txt new file mode 100644 index 0000000..87727d8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/files/blob-parts-slice-test-expected.txt @@ -0,0 +1,117 @@ +Test the Blob.slice() behavior for Blobs made of multiple parts. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +Blob .slice(2, 3) +PASS blobContents is "2" +File .slice(2, 3) +PASS fileContents is "2" +Blob .slice(2, 12) +PASS blobContents is "23456789" +File .slice(2, 12) +PASS fileContents is "23456789" +Blob .slice(2, 2) +PASS blobContents is "" +File .slice(2, 2) +PASS fileContents is "" +Blob .slice(2, 1) +PASS blobContents is "" +File .slice(2, 1) +PASS fileContents is "" +Blob .slice(2, -12) +PASS blobContents is "" +File .slice(2, -12) +PASS fileContents is "" +Blob .slice(2, 2147483647) +PASS blobContents is "23456789" +File .slice(2, 2147483647) +PASS fileContents is "23456789" +Blob .slice(2, -2147483648) +PASS blobContents is "" +File .slice(2, -2147483648) +PASS fileContents is "" +Blob .slice(2, 9223372036854775000) +PASS blobContents is "23456789" +File .slice(2, 9223372036854775000) +PASS fileContents is "23456789" +Blob .slice(2, -9223372036854775000) +PASS blobContents is "" +File .slice(2, -9223372036854775000) +PASS fileContents is "" +Blob .slice(-2, -1) +PASS blobContents is "8" +File .slice(-2, -1) +PASS fileContents is "8" +Blob .slice(-2, -2) +PASS blobContents is "" +File .slice(-2, -2) +PASS fileContents is "" +Blob .slice(-2, -3) +PASS blobContents is "" +File .slice(-2, -3) +PASS fileContents is "" +Blob .slice(-2, -12) +PASS blobContents is "" +File .slice(-2, -12) +PASS fileContents is "" +Blob .slice(-2, 2147483647) +PASS blobContents is "89" +File .slice(-2, 2147483647) +PASS fileContents is "89" +Blob .slice(-2, -2147483648) +PASS blobContents is "" +File .slice(-2, -2147483648) +PASS fileContents is "" +Blob .slice(-2, 9223372036854775000) +PASS blobContents is "89" +File .slice(-2, 9223372036854775000) +PASS fileContents is "89" +Blob .slice(-2, -9223372036854775000) +PASS blobContents is "" +File .slice(-2, -9223372036854775000) +PASS fileContents is "" +Blob .slice(0) +PASS blobContents is "0123456789" +File .slice(0) +PASS fileContents is "0123456789" +Blob .slice(2) +PASS blobContents is "23456789" +File .slice(2) +PASS fileContents is "23456789" +Blob .slice(-2) +PASS blobContents is "89" +File .slice(-2) +PASS fileContents is "89" +Blob .slice(12) +PASS blobContents is "" +File .slice(12) +PASS fileContents is "" +Blob .slice(-12) +PASS blobContents is "0123456789" +File .slice(-12) +PASS fileContents is "0123456789" +Blob .slice(2147483647) +PASS blobContents is "" +File .slice(2147483647) +PASS fileContents is "" +Blob .slice(-2147483648) +PASS blobContents is "0123456789" +File .slice(-2147483648) +PASS fileContents is "0123456789" +Blob .slice(9223372036854775000) +PASS blobContents is "" +File .slice(9223372036854775000) +PASS fileContents is "" +Blob .slice(-9223372036854775000) +PASS blobContents is "0123456789" +File .slice(-9223372036854775000) +PASS fileContents is "0123456789" +Blob .slice() +PASS blobContents is "0123456789" +File .slice() +PASS fileContents is "0123456789" +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/third_party/WebKit/LayoutTests/fast/files/blob-parts-slice-test.html b/third_party/WebKit/LayoutTests/fast/files/blob-parts-slice-test.html new file mode 100644 index 0000000..9f2f47b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/files/blob-parts-slice-test.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../../resources/js-test.js"></script> +<script src="resources/blob-slice-common.js"></script> +<script> +description("Test the Blob.slice() behavior for Blobs made of multiple parts."); + +var sliceTestCases = [ + [2, 3, "2"], + [2, 12, "23456789"], + [2, 2, ""], + [2, 1, ""], + [2, -12, ""], + [2, 2147483647, "23456789"], + [2, -2147483648, ""], + [2, 9223372036854775000, "23456789"], + [2, -9223372036854775000, ""], + [-2, -1, "8"], + [-2, -2, ""], + [-2, -3, ""], + [-2, -12, ""], + [-2, 2147483647, "89"], + [-2, -2147483648, ""], + [-2, 9223372036854775000, "89"], + [-2, -9223372036854775000, ""], + [0, null, "0123456789"], + [2, null, "23456789"], + [-2, null, "89"], + [12, null, ""], + [-12, null, "0123456789"], + [2147483647, null, ""], + [-2147483648, null, "0123456789"], + [9223372036854775000, null, ""], + [-9223372036854775000, null, "0123456789"], + [null, null, "0123456789"], +]; + +function runTests() +{ + blob = new Blob(["0", new File(["12"], "slice-piece.txt"), + new Blob(["345"]), "6789"]); + file = new File(["0", new File(["12"], "slice-piece.txt"), + new Blob(["345"]), "6789"], "slice-text.txt"); + + runNextTest(); +} + +window.jsTestIsAsync = true; +</script> +</head> +<body onload="runTests()"> +<pre id='console'></pre> +</body> +</html> diff --git a/third_party/WebKit/LayoutTests/fast/files/blob-slice-test-expected.txt b/third_party/WebKit/LayoutTests/fast/files/blob-slice-test-expected.txt index 0f274d3..2f12c4f 100644 --- a/third_party/WebKit/LayoutTests/fast/files/blob-slice-test-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/files/blob-slice-test-expected.txt @@ -1,28 +1,117 @@ -Slicing from 2 to 3: 2 -Slicing from 2 to 12: 23456789 -Slicing from 2 to 2: -Slicing from 2 to 1: -Slicing from 2 to -12: -Slicing from 2 to 2147483647: 23456789 -Slicing from 2 to -2147483648: -Slicing from 2 to 9223372036854775000: 23456789 -Slicing from 2 to -9223372036854775000: -Slicing from -2 to -1: 8 -Slicing from -2 to -2: -Slicing from -2 to -3: -Slicing from -2 to -12: -Slicing from -2 to 2147483647: 89 -Slicing from -2 to -2147483648: -Slicing from -2 to 9223372036854775000: 89 -Slicing from -2 to -9223372036854775000: -Slicing from 0: 0123456789 -Slicing from 2: 23456789 -Slicing from -2: 89 -Slicing from 12: -Slicing from -12: 0123456789 -Slicing from 2147483647: -Slicing from -2147483648: 0123456789 -Slicing from 9223372036854775000: -Slicing from -9223372036854775000: 0123456789 -Slicing without parameters: 0123456789 +Test Blob.slice(). + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +Blob .slice(2, 3) +PASS blobContents is "2" +File .slice(2, 3) +PASS fileContents is "2" +Blob .slice(2, 12) +PASS blobContents is "23456789" +File .slice(2, 12) +PASS fileContents is "23456789" +Blob .slice(2, 2) +PASS blobContents is "" +File .slice(2, 2) +PASS fileContents is "" +Blob .slice(2, 1) +PASS blobContents is "" +File .slice(2, 1) +PASS fileContents is "" +Blob .slice(2, -12) +PASS blobContents is "" +File .slice(2, -12) +PASS fileContents is "" +Blob .slice(2, 2147483647) +PASS blobContents is "23456789" +File .slice(2, 2147483647) +PASS fileContents is "23456789" +Blob .slice(2, -2147483648) +PASS blobContents is "" +File .slice(2, -2147483648) +PASS fileContents is "" +Blob .slice(2, 9223372036854775000) +PASS blobContents is "23456789" +File .slice(2, 9223372036854775000) +PASS fileContents is "23456789" +Blob .slice(2, -9223372036854775000) +PASS blobContents is "" +File .slice(2, -9223372036854775000) +PASS fileContents is "" +Blob .slice(-2, -1) +PASS blobContents is "8" +File .slice(-2, -1) +PASS fileContents is "8" +Blob .slice(-2, -2) +PASS blobContents is "" +File .slice(-2, -2) +PASS fileContents is "" +Blob .slice(-2, -3) +PASS blobContents is "" +File .slice(-2, -3) +PASS fileContents is "" +Blob .slice(-2, -12) +PASS blobContents is "" +File .slice(-2, -12) +PASS fileContents is "" +Blob .slice(-2, 2147483647) +PASS blobContents is "89" +File .slice(-2, 2147483647) +PASS fileContents is "89" +Blob .slice(-2, -2147483648) +PASS blobContents is "" +File .slice(-2, -2147483648) +PASS fileContents is "" +Blob .slice(-2, 9223372036854775000) +PASS blobContents is "89" +File .slice(-2, 9223372036854775000) +PASS fileContents is "89" +Blob .slice(-2, -9223372036854775000) +PASS blobContents is "" +File .slice(-2, -9223372036854775000) +PASS fileContents is "" +Blob .slice(0) +PASS blobContents is "0123456789" +File .slice(0) +PASS fileContents is "0123456789" +Blob .slice(2) +PASS blobContents is "23456789" +File .slice(2) +PASS fileContents is "23456789" +Blob .slice(-2) +PASS blobContents is "89" +File .slice(-2) +PASS fileContents is "89" +Blob .slice(12) +PASS blobContents is "" +File .slice(12) +PASS fileContents is "" +Blob .slice(-12) +PASS blobContents is "0123456789" +File .slice(-12) +PASS fileContents is "0123456789" +Blob .slice(2147483647) +PASS blobContents is "" +File .slice(2147483647) +PASS fileContents is "" +Blob .slice(-2147483648) +PASS blobContents is "0123456789" +File .slice(-2147483648) +PASS fileContents is "0123456789" +Blob .slice(9223372036854775000) +PASS blobContents is "" +File .slice(9223372036854775000) +PASS fileContents is "" +Blob .slice(-9223372036854775000) +PASS blobContents is "0123456789" +File .slice(-9223372036854775000) +PASS fileContents is "0123456789" +Blob .slice() +PASS blobContents is "0123456789" +File .slice() +PASS fileContents is "0123456789" +PASS successfullyParsed is true + +TEST COMPLETE diff --git a/third_party/WebKit/LayoutTests/fast/files/blob-slice-test.html b/third_party/WebKit/LayoutTests/fast/files/blob-slice-test.html index 06fec6e..e6a2989 100644 --- a/third_party/WebKit/LayoutTests/fast/files/blob-slice-test.html +++ b/third_party/WebKit/LayoutTests/fast/files/blob-slice-test.html @@ -1,96 +1,50 @@ <!DOCTYPE html> <html> <head> +<script src="../../resources/js-test.js"></script> +<script src="resources/blob-slice-common.js"></script> <script> -var blob; -var testIndex = 0; -var sliceParams = [ - [2, 3], - [2, 12], - [2, 2], - [2, 1], - [2, -12], - [2, 2147483647], - [2, -2147483648], - [2, 9223372036854775000], - [2, -9223372036854775000], - [-2, -1], - [-2, -2], - [-2, -3], - [-2, -12], - [-2, 2147483647], - [-2, -2147483648], - [-2, 9223372036854775000], - [-2, -9223372036854775000], - [0], - [2], - [-2], - [12], - [-12], - [2147483647], - [-2147483648], - [9223372036854775000], - [-9223372036854775000], - [], -]; - -function log(message) -{ - document.getElementById('console').appendChild(document.createTextNode(message + "\n")); -} - -function testSlicing(start, end) -{ - var subBlob; - var reader = new FileReader(); - var message = "Slicing "; - if (start == undefined && end == undefined) { - message += "without parameters"; - subBlob = blob.slice(); - } else if (end == undefined) { - message += "from " + start; - subBlob = blob.slice(start); - } else { - message += "from " + start + " to " + end; - subBlob = blob.slice(start, end); - } - message += ": "; - reader.onload = function(event) { - log(message + event.target.result); - runNextTest(); - }; - reader.onerror = function(event) { - log(message + "error " + event.target.error.code); - runNextTest(); - }; - reader.readAsText(subBlob); -} - -function runNextTest() -{ - if (testIndex >= sliceParams.length) { - if (window.testRunner) - testRunner.notifyDone(); - return; - } +description("Test Blob.slice()."); - var start = sliceParams[testIndex][0]; - var end = sliceParams[testIndex][1]; - testIndex++; - testSlicing(start, end); -} +var sliceTestCases = [ + [2, 3, "2"], + [2, 12, "23456789"], + [2, 2, ""], + [2, 1, ""], + [2, -12, ""], + [2, 2147483647, "23456789"], + [2, -2147483648, ""], + [2, 9223372036854775000, "23456789"], + [2, -9223372036854775000, ""], + [-2, -1, "8"], + [-2, -2, ""], + [-2, -3, ""], + [-2, -12, ""], + [-2, 2147483647, "89"], + [-2, -2147483648, ""], + [-2, 9223372036854775000, "89"], + [-2, -9223372036854775000, ""], + [0, null, "0123456789"], + [2, null, "23456789"], + [-2, null, "89"], + [12, null, ""], + [-12, null, "0123456789"], + [2147483647, null, ""], + [-2147483648, null, "0123456789"], + [9223372036854775000, null, ""], + [-9223372036854775000, null, "0123456789"], + [null, null, "0123456789"], +]; function runTests() { blob = new Blob(["0123456789"]); + file = new File(["0123456789"], "slice-test.txt"); runNextTest(); } -if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); -} +window.jsTestIsAsync = true; </script> </head> <body onload="runTests()"> diff --git a/third_party/WebKit/LayoutTests/fast/files/file-constructor-expected.txt b/third_party/WebKit/LayoutTests/fast/files/file-constructor-expected.txt new file mode 100644 index 0000000..2c4bf48 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/files/file-constructor-expected.txt @@ -0,0 +1,100 @@ +Test the File constructor. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS (new File([], 'world.html')) instanceof window.File is true +PASS (new File(['hello'], 'world.html')) instanceof window.File is true +PASS (new File(['hello'], 'world.html', {})) instanceof window.File is true +PASS (new File(['hello'], 'world.html', {type:'text/html'})) instanceof window.File is true +PASS (new File(['hello'], 'world.html', {type:'text/html', endings:'native'})) instanceof window.File is true +PASS (new File(['hello'], 'world.html', {type:'text/html', endings:'transparent'})) instanceof window.File is true +PASS (new File([], 'world.html')) instanceof window.File is true +PASS (new File()) threw exception TypeError: File constructor requires at least two arguments. +PASS (new File([])) threw exception TypeError: File constructor requires at least two arguments. +PASS (new File([], null)) instanceof window.File is true +PASS (new File([], 1)) instanceof window.File is true +PASS (new File([], '')) instanceof window.File is true +PASS (new File([], document)) instanceof window.File is true +PASS new File('hello', 'world.html') threw exception TypeError: Failed to construct 'File': The 1st argument is neither an array, nor does it have indexed properties.. +PASS new File(0, 'world.html') threw exception TypeError: Failed to construct 'File': The 1st argument is neither an array, nor does it have indexed properties.. +PASS (new File([], 'world.html')) instanceof window.File is true +PASS (new File(['stringPrimitive'], 'world.html')) instanceof window.File is true +PASS (new File([String('stringObject')], 'world.html')) instanceof window.File is true +PASS (new File([new Blob], 'world.html')) instanceof window.File is true +PASS (new File([new Blob([new Blob])], 'world.html')) instanceof window.File is true +PASS (new Blob([new File([], 'world.txt')])) instanceof window.Blob is true +PASS (new Blob([new Blob([new File([new Blob], 'world.txt')])])) instanceof window.Blob is true +PASS (new File([new File([], 'world.txt')], 'world.html')) instanceof window.File is true +PASS (new File([new Blob([new File([new Blob], 'world.txt')])], 'world.html')) instanceof window.File is true +PASS (new File([12], 'world.html')).size is 2 +PASS (new File([[]], 'world.html')).size is 0 +PASS (new File([{}], 'world.html')).size is 15 +PASS (new File([document], 'world.html')).size is 21 +PASS (new File([toStringingObj], 'world.html')).size is 8 +PASS new File([throwingObj], 'world.html') threw exception Error. +PASS (new File([], null)).name is 'null' +PASS (new File([], 12)).name is '12' +PASS (new File([], '')).name is '' +PASS (new File([], {})).name is '[object Object]' +PASS (new File([], document)).name is '[object HTMLDocument]' +PASS (new File([], toStringingObj)).name is 'A string' +PASS (new File([], throwingObj)).name threw exception Error. +PASS (new File([], 'world.html', {unknownKey:'value'})) instanceof window.File is true +PASS new File([], 'world.html', {endings:'illegalValue'}) threw exception TypeError: Failed to construct 'File': The "endings" property must be either "transparent" or "native".. +PASS new File([], 'world.html', {endings:throwingObj}) threw exception Error. +PASS new File([], 'world.html', {type:throwingObj}) threw exception Error. +PASS new File([], 'world.html', {type:'helloĆ®'}) threw exception SyntaxError: Failed to construct 'File': The "type" property must consist of ASCII characters.. +PASS (new File([], 'world.html', null)) instanceof window.File threw exception TypeError: Failed to construct 'File': The 3rd argument is not of type Object.. +PASS (new File([], 'world.html', undefined)) instanceof window.File threw exception TypeError: Failed to construct 'File': The 3rd argument is not of type Object.. +PASS (new File([], 'world.html', 123)) instanceof window.File threw exception TypeError: Failed to construct 'File': The 3rd argument is not of type Object.. +PASS (new File([], 'world.html', 123.4)) instanceof window.File threw exception TypeError: Failed to construct 'File': The 3rd argument is not of type Object.. +PASS (new File([], 'world.html', true)) instanceof window.File threw exception TypeError: Failed to construct 'File': The 3rd argument is not of type Object.. +PASS (new File([], 'world.html', 'abc')) instanceof window.File threw exception TypeError: Failed to construct 'File': The 3rd argument is not of type Object.. +PASS (new File([], 'world.html', [])) instanceof window.File is true +PASS (new File([], 'world.html', /abc/)) instanceof window.File is true +PASS (new File([], 'world.html', function () {})) instanceof window.File is true +PASS (new File([], 'world.html', {type:'text/html'})).name is 'world.html' +PASS (new File([], 'world.html', {type:'text/html'})).type is 'text/html' +PASS (new File([], 'world.html', {type:'text/html'})).size is 0 +PASS (new File([], 'world.html', {type:'text/plain;charset=UTF-8'})).type is 'text/plain;charset=utf-8' +PASS window.File.length is 2 +PASS new File([new DataView(new ArrayBuffer(100))], 'world.html').size is 100 +PASS new File([new Uint8Array(100)], 'world.html').size is 100 +PASS new File([new Uint8ClampedArray(100)], 'world.html').size is 100 +PASS new File([new Uint16Array(100)], 'world.html').size is 200 +PASS new File([new Uint32Array(100)], 'world.html').size is 400 +PASS new File([new Int8Array(100)], 'world.html').size is 100 +PASS new File([new Int16Array(100)], 'world.html').size is 200 +PASS new File([new Int32Array(100)], 'world.html').size is 400 +PASS new File([new Float32Array(100)], 'world.html').size is 400 +PASS new File([new Float64Array(100)], 'world.html').size is 800 +PASS new File([new Float64Array(100), new Int32Array(100), new Uint8Array(100), new DataView(new ArrayBuffer(100))], 'world.html').size is 1400 +PASS new File([new Blob([new Int32Array(100)]), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))], 'world.html').size is 1000 +PASS new File([new Blob([new Int32Array(100)]), new File([new Uint16Array(100)], 'world.txt'), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))], 'world.html').size is 1200 +PASS new File([(new DataView(new ArrayBuffer(100))).buffer], 'world.html').size is 100 +PASS new File([(new Uint8Array(100)).buffer], 'world.html').size is 100 +PASS new File([(new Uint8ClampedArray(100)).buffer], 'world.html').size is 100 +PASS new File([(new Uint16Array(100)).buffer], 'world.html').size is 200 +PASS new File([(new Uint32Array(100)).buffer], 'world.html').size is 400 +PASS new File([(new Int8Array(100)).buffer], 'world.html').size is 100 +PASS new File([(new Int16Array(100)).buffer], 'world.html').size is 200 +PASS new File([(new Int32Array(100)).buffer], 'world.html').size is 400 +PASS new File([(new Float32Array(100)).buffer], 'world.html').size is 400 +PASS new File([(new Float64Array(100)).buffer], 'world.html').size is 800 +PASS new File([(new Float64Array(100)).buffer, (new Int32Array(100)).buffer, (new Uint8Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer], 'world.html').size is 1400 +PASS new File([new Blob([(new Int32Array(100)).buffer]), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer], 'world.html').size is 1000 +PASS new File([new Blob([(new Int32Array(100)).buffer]), new File([new Uint16Array(100).buffer], 'world.txt'), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer], 'world.html').size is 1200 +PASS new Blob([new Blob([new Int32Array(100)]), new File([new Uint16Array(100)], 'world.txt'), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))]).size is 1200 +PASS new Blob([new Blob([(new Int32Array(100)).buffer]), new File([new Uint16Array(100).buffer], 'world.txt'), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size is 1200 +PASS new File({length: 0}, 'world.txt') instanceof window.File is true +PASS new File({length: 0}, 'world.txt').size is 0 +PASS new File({length: 1, 0: 'string'}, 'world.txt').size is 6 +PASS new File({length: 2, 0: new Uint8Array(100), 1: new Int16Array(100)}, 'world.txt').size is 300 +PASS new File({length: 1, 0: 'string'}, 'world.txt', {type: 'text/html'}).type is 'text/html' +PASS new File({length: 0}, 'world.txt', {endings:'illegal'}) threw exception TypeError: Failed to construct 'File': The "endings" property must be either "transparent" or "native".. +PASS new File(throwingSequence, 'world.txt') threw exception Error: Misbehaving property. +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/third_party/WebKit/LayoutTests/fast/files/file-constructor.html b/third_party/WebKit/LayoutTests/fast/files/file-constructor.html new file mode 100644 index 0000000..f615864 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/files/file-constructor.html @@ -0,0 +1,146 @@ +<!DOCTYPE html> + +<script src="../../resources/js-test.js"></script> +<script> +description("Test the File constructor."); + +// Test the different ways you can construct a File. +shouldBeTrue("(new File([], 'world.html')) instanceof window.File"); +shouldBeTrue("(new File(['hello'], 'world.html')) instanceof window.File"); +shouldBeTrue("(new File(['hello'], 'world.html', {})) instanceof window.File"); +shouldBeTrue("(new File(['hello'], 'world.html', {type:'text/html'})) instanceof window.File"); +shouldBeTrue("(new File(['hello'], 'world.html', {type:'text/html', endings:'native'})) instanceof window.File"); +shouldBeTrue("(new File(['hello'], 'world.html', {type:'text/html', endings:'transparent'})) instanceof window.File"); + +// Test that File inherits from File. +shouldBeTrue("(new File([], 'world.html')) instanceof window.File") + +// Verify that the file name argument is required. +shouldThrow("(new File())", "'TypeError: File constructor requires at least two arguments'"); +shouldThrow("(new File([]))", "'TypeError: File constructor requires at least two arguments'"); + +// Test valid file names. +shouldBeTrue("(new File([], null)) instanceof window.File"); +shouldBeTrue("(new File([], 1)) instanceof window.File"); +shouldBeTrue("(new File([], '')) instanceof window.File"); +shouldBeTrue("(new File([], document)) instanceof window.File"); + +// Test invalid blob parts. +shouldThrow("new File('hello', 'world.html')", '"TypeError: Failed to construct \'File\': The 1st argument is neither an array, nor does it have indexed properties."'); +shouldThrow("new File(0, 'world.html')", '"TypeError: Failed to construct \'File\': The 1st argument is neither an array, nor does it have indexed properties."'); + +// Test valid blob parts. +shouldBeTrue("(new File([], 'world.html')) instanceof window.File"); +shouldBeTrue("(new File(['stringPrimitive'], 'world.html')) instanceof window.File"); +shouldBeTrue("(new File([String('stringObject')], 'world.html')) instanceof window.File"); +shouldBeTrue("(new File([new Blob], 'world.html')) instanceof window.File"); +shouldBeTrue("(new File([new Blob([new Blob])], 'world.html')) instanceof window.File"); + +// Test File instances used as blob parts. +shouldBeTrue("(new Blob([new File([], 'world.txt')])) instanceof window.Blob"); +shouldBeTrue("(new Blob([new Blob([new File([new Blob], 'world.txt')])])) instanceof window.Blob"); +shouldBeTrue("(new File([new File([], 'world.txt')], 'world.html')) instanceof window.File"); +shouldBeTrue("(new File([new Blob([new File([new Blob], 'world.txt')])], 'world.html')) instanceof window.File"); + +// Test some conversions to string in the parts array. +shouldBe("(new File([12], 'world.html')).size", "2"); +shouldBe("(new File([[]], 'world.html')).size", "0"); // [].toString() is the empty string +shouldBe("(new File([{}], 'world.html')).size", "15");; // {}.toString() is the string "[object Object]" +shouldBe("(new File([document], 'world.html')).size", "21"); // document.toString() is the string "[object HTMLDocument]" + +var toStringingObj = { toString: function() { return "A string"; } }; +shouldBe("(new File([toStringingObj], 'world.html')).size", "8"); + +var throwingObj = { toString: function() { throw "Error"; } }; +shouldThrow("new File([throwingObj], 'world.html')", "'Error'"); + +// Test some conversions to string in the file name. +shouldBe("(new File([], null)).name", "'null'"); +shouldBe("(new File([], 12)).name", "'12'"); +shouldBe("(new File([], '')).name", "''"); +shouldBe("(new File([], {})).name", "'[object Object]'"); +shouldBe("(new File([], document)).name", "'[object HTMLDocument]'"); +shouldBe("(new File([], toStringingObj)).name", "'A string'"); +shouldThrow("(new File([], throwingObj)).name", "'Error'"); + +// Test some invalid property bags. +shouldBeTrue("(new File([], 'world.html', {unknownKey:'value'})) instanceof window.File"); // Ignore invalid keys +shouldThrow("new File([], 'world.html', {endings:'illegalValue'})", "'TypeError: Failed to construct \\'File\\': The \"endings\" property must be either \"transparent\" or \"native\".'"); +shouldThrow("new File([], 'world.html', {endings:throwingObj})", "'Error'"); +shouldThrow("new File([], 'world.html', {type:throwingObj})", "'Error'"); +shouldThrow("new File([], 'world.html', {type:'hello\u00EE'})", "'SyntaxError: Failed to construct \\'File\\': The \"type\" property must consist of ASCII characters.'"); + +// Test various non-object literals being used as property bags. +shouldThrow("(new File([], 'world.html', null)) instanceof window.File", "'TypeError: Failed to construct \\'File\\': The 3rd argument is not of type Object.'"); +shouldThrow("(new File([], 'world.html', undefined)) instanceof window.File", "'TypeError: Failed to construct \\'File\\': The 3rd argument is not of type Object.'"); +shouldThrow("(new File([], 'world.html', 123)) instanceof window.File", "'TypeError: Failed to construct \\'File\\': The 3rd argument is not of type Object.'"); +shouldThrow("(new File([], 'world.html', 123.4)) instanceof window.File", "'TypeError: Failed to construct \\'File\\': The 3rd argument is not of type Object.'"); +shouldThrow("(new File([], 'world.html', true)) instanceof window.File", "'TypeError: Failed to construct \\'File\\': The 3rd argument is not of type Object.'"); +shouldThrow("(new File([], 'world.html', 'abc')) instanceof window.File", "'TypeError: Failed to construct \\'File\\': The 3rd argument is not of type Object.'"); +shouldBeTrue("(new File([], 'world.html', [])) instanceof window.File"); +shouldBeTrue("(new File([], 'world.html', /abc/)) instanceof window.File"); +shouldBeTrue("(new File([], 'world.html', function () {})) instanceof window.File"); + +// Test that the name/type/size are correctly added to the File. +shouldBe("(new File([], 'world.html', {type:'text/html'})).name", "'world.html'"); +shouldBe("(new File([], 'world.html', {type:'text/html'})).type", "'text/html'"); +shouldBe("(new File([], 'world.html', {type:'text/html'})).size", "0"); +shouldBe("(new File([], 'world.html', {type:'text/plain;charset=UTF-8'})).type", "'text/plain;charset=utf-8'"); + +// Test the number of expected arguments in the File constructor. +shouldBe("window.File.length", "2"); + +// Test ArrayBufferView parameters. +shouldBe("new File([new DataView(new ArrayBuffer(100))], 'world.html').size", "100"); +shouldBe("new File([new Uint8Array(100)], 'world.html').size", "100"); +shouldBe("new File([new Uint8ClampedArray(100)], 'world.html').size", "100"); +shouldBe("new File([new Uint16Array(100)], 'world.html').size", "200"); +shouldBe("new File([new Uint32Array(100)], 'world.html').size", "400"); +shouldBe("new File([new Int8Array(100)], 'world.html').size", "100"); +shouldBe("new File([new Int16Array(100)], 'world.html').size", "200"); +shouldBe("new File([new Int32Array(100)], 'world.html').size", "400"); +shouldBe("new File([new Float32Array(100)], 'world.html').size", "400"); +shouldBe("new File([new Float64Array(100)], 'world.html').size", "800"); +shouldBe("new File([new Float64Array(100), new Int32Array(100), new Uint8Array(100), new DataView(new ArrayBuffer(100))], 'world.html').size", "1400"); +shouldBe("new File([new Blob([new Int32Array(100)]), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))], 'world.html').size", "1000"); +shouldBe("new File([new Blob([new Int32Array(100)]), new File([new Uint16Array(100)], 'world.txt'), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))], 'world.html').size", "1200"); + +// Test ArrayBuffer parameters. +shouldBe("new File([(new DataView(new ArrayBuffer(100))).buffer], 'world.html').size", "100"); +shouldBe("new File([(new Uint8Array(100)).buffer], 'world.html').size", "100"); +shouldBe("new File([(new Uint8ClampedArray(100)).buffer], 'world.html').size", "100"); +shouldBe("new File([(new Uint16Array(100)).buffer], 'world.html').size", "200"); +shouldBe("new File([(new Uint32Array(100)).buffer], 'world.html').size", "400"); +shouldBe("new File([(new Int8Array(100)).buffer], 'world.html').size", "100"); +shouldBe("new File([(new Int16Array(100)).buffer], 'world.html').size", "200"); +shouldBe("new File([(new Int32Array(100)).buffer], 'world.html').size", "400"); +shouldBe("new File([(new Float32Array(100)).buffer], 'world.html').size", "400"); +shouldBe("new File([(new Float64Array(100)).buffer], 'world.html').size", "800"); +shouldBe("new File([(new Float64Array(100)).buffer, (new Int32Array(100)).buffer, (new Uint8Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer], 'world.html').size", "1400"); +shouldBe("new File([new Blob([(new Int32Array(100)).buffer]), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer], 'world.html').size", "1000"); +shouldBe("new File([new Blob([(new Int32Array(100)).buffer]), new File([new Uint16Array(100).buffer], 'world.txt'), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer], 'world.html').size", "1200"); + +// Test building Blobs with ArrayBuffer / ArrayBufferView parts enclosed in files. +shouldBe("new Blob([new Blob([new Int32Array(100)]), new File([new Uint16Array(100)], 'world.txt'), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))]).size", "1200"); +shouldBe("new Blob([new Blob([(new Int32Array(100)).buffer]), new File([new Uint16Array(100).buffer], 'world.txt'), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size", "1200"); + +// Test passing blob parts in sequences. +shouldBeTrue("new File({length: 0}, 'world.txt') instanceof window.File"); +shouldBe("new File({length: 0}, 'world.txt').size", "0"); +shouldBe("new File({length: 1, 0: 'string'}, 'world.txt').size", "6"); +shouldBe("new File({length: 2, 0: new Uint8Array(100), 1: new Int16Array(100)}, 'world.txt').size", "300"); +shouldBe("new File({length: 1, 0: 'string'}, 'world.txt', {type: 'text/html'}).type", "'text/html'"); +shouldThrow("new File({length: 0}, 'world.txt', {endings:'illegal'})", "'TypeError: Failed to construct \\'File\\': The \"endings\" property must be either \"transparent\" or \"native\".'"); + +// Test passing blog parts in a sequence-like object that throws on property access. +var throwingSequence = {length: 4, 0: 'hello', 3: 'world'}; +Object.defineProperty(throwingSequence, "1", { + get: function() { throw new Error("Misbehaving property"); }, + enumerable: true, configurable: true +}); +Object.defineProperty(throwingSequence, "2", { + get: function() { throw new Error("This should not be thrown"); }, + enumerable: true, configurable: true +}); +shouldThrow("new File(throwingSequence, 'world.txt')", "'Error: Misbehaving property'"); +</script> diff --git a/third_party/WebKit/LayoutTests/fast/files/resources/blob-slice-common.js b/third_party/WebKit/LayoutTests/fast/files/resources/blob-slice-common.js new file mode 100644 index 0000000..ba7a251 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/files/resources/blob-slice-common.js @@ -0,0 +1,49 @@ +var blob, file; // Populated by runTests() in individual tests. +var sliceParams = []; // Populated by individual tests. +var testIndex = 0; + +function testSlicing(start, end, expectedResult, blob, doneCallback) +{ + var blobClass = blob.constructor.name; + var sliced; + var reader = new FileReader(); + var message = ".slice"; + if (start === null && end === null) { + message += "()"; + sliced = blob.slice(); + } else if (end == undefined) { + message += "(" + start + ")"; + sliced = blob.slice(start); + } else { + message += "(" + start + ", " + end + ")"; + sliced = blob.slice(start, end); + } + reader.onloadend = function(event) { + var error = event.target.error; + if (error) { + testFailed("File read error " + message + error); + doneCallback(); + return; + } + var blobContentsVar = blobClass.toLowerCase() + "Contents"; + window[blobContentsVar] = event.target.result; + shouldBeEqualToString(blobContentsVar, expectedResult); + doneCallback(); + }; + debug(blobClass + " " + message); + reader.readAsText(sliced); +} + +function runNextTest() +{ + if (testIndex >= sliceTestCases.length) { + finishJSTest(); + return; + } + + var testCase = sliceTestCases[testIndex]; + testIndex++; + testSlicing(testCase[0], testCase[1], testCase[2], blob, function() { + testSlicing(testCase[0], testCase[1], testCase[2], file, runNextTest); + }); +} diff --git a/third_party/WebKit/LayoutTests/fast/files/script-tests/blob-constructor.js b/third_party/WebKit/LayoutTests/fast/files/script-tests/blob-constructor.js deleted file mode 100644 index 77ad34a..0000000 --- a/third_party/WebKit/LayoutTests/fast/files/script-tests/blob-constructor.js +++ /dev/null @@ -1,114 +0,0 @@ -description("Test the Blob constructor."); - -// Test the diffrent ways you can construct a Blob. -shouldBeTrue("(new Blob()) instanceof window.Blob"); -shouldBeTrue("(new Blob([])) instanceof window.Blob"); -shouldBeTrue("(new Blob(['hello'])) instanceof window.Blob"); -shouldBeTrue("(new Blob(['hello'], {})) instanceof window.Blob"); -shouldBeTrue("(new Blob(['hello'], {type:'text/html'})) instanceof window.Blob"); -shouldBeTrue("(new Blob(['hello'], {type:'text/html', endings:'native'})) instanceof window.Blob"); -shouldBeTrue("(new Blob(['hello'], {type:'text/html', endings:'transparent'})) instanceof window.Blob"); - -// Test invalid blob parts -shouldThrow("new Blob('hello')", '"TypeError: Failed to construct \'Blob\': The 1st argument is neither an array, nor does it have indexed properties."'); -shouldThrow("new Blob(0)", '"TypeError: Failed to construct \'Blob\': The 1st argument is neither an array, nor does it have indexed properties."'); - -// Test valid blob parts. -shouldBeTrue("(new Blob([])) instanceof window.Blob"); -shouldBeTrue("(new Blob(['stringPrimitive'])) instanceof window.Blob"); -shouldBeTrue("(new Blob([String('stringObject')])) instanceof window.Blob"); -shouldBeTrue("(new Blob([new Blob])) instanceof window.Blob"); -shouldBeTrue("(new Blob([new Blob([new Blob])])) instanceof window.Blob"); - -// Test some conversions to string in the parts array. -shouldBe("(new Blob([12])).size", "2"); -shouldBe("(new Blob([[]])).size", "0"); // [].toString() is the empty string -shouldBe("(new Blob([{}])).size", "15");; // {}.toString() is the string "[object Object]" -shouldBe("(new Blob([document])).size", "21"); // document.toString() is the string "[object HTMLDocument]" - -var toStringingObj = { toString: function() { return "A string"; } }; -shouldBe("(new Blob([toStringingObj])).size", "8"); - -var throwingObj = { toString: function() { throw "Error"; } }; -shouldThrow("new Blob([throwingObj])", "'Error'"); - -// Test some invalid property bags -shouldBeTrue("(new Blob([], {unknownKey:'value'})) instanceof window.Blob"); // Ignore invalid keys -shouldThrow("new Blob([], {endings:'illegalValue'})", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument\\'s \"endings\" property must be either \"transparent\" or \"native\".'"); -shouldThrow("new Blob([], {endings:throwingObj})", "'Error'"); -shouldThrow("new Blob([], {type:throwingObj})", "'Error'"); -shouldThrow("new Blob([], {type:'hello\u00EE'})", "'SyntaxError: Failed to construct \\'Blob\\': The 2nd argument\\'s \"type\" property must consist of ASCII characters.'"); - -// Test that order of property bag evaluation is lexigraphical -var throwingObj1 = { toString: function() { throw "Error 1"; } }; -var throwingObj2 = { toString: function() { throw "Error 2"; } }; -shouldThrow("new Blob([], {endings:throwingObj1, type:throwingObj2})", "'Error 1'"); -shouldThrow("new Blob([], {type:throwingObj2, endings:throwingObj1})", "'Error 1'"); -shouldThrow("new Blob([], {type:throwingObj2, endings:'illegal'})", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument\\'s \"endings\" property must be either \"transparent\" or \"native\".'"); - -// Test various non-object literals being used as property bags -shouldThrow("(new Blob([], null)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); -shouldThrow("(new Blob([], undefined)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); -shouldThrow("(new Blob([], 123)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); -shouldThrow("(new Blob([], 123.4)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); -shouldThrow("(new Blob([], true)) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); -shouldThrow("(new Blob([], 'abc')) instanceof window.Blob", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument is not of type Object.'"); -shouldBeTrue("(new Blob([], [])) instanceof window.Blob"); -shouldBeTrue("(new Blob([], /abc/)) instanceof window.Blob"); -shouldBeTrue("(new Blob([], function () {})) instanceof window.Blob"); - -// Test that the type/size is correctly added to the Blob -shouldBe("(new Blob([], {type:'text/html'})).type", "'text/html'"); -shouldBe("(new Blob([], {type:'text/html'})).size", "0"); -shouldBe("(new Blob([], {type:'text/plain;charset=UTF-8'})).type", "'text/plain;charset=utf-8'"); - -// Odds and ends -shouldBe("window.Blob.length", "2"); - -// Test ArrayBufferView Parameters -shouldBe("new Blob([new DataView(new ArrayBuffer(100))]).size", "100"); -shouldBe("new Blob([new Uint8Array(100)]).size", "100"); -shouldBe("new Blob([new Uint8ClampedArray(100)]).size", "100"); -shouldBe("new Blob([new Uint16Array(100)]).size", "200"); -shouldBe("new Blob([new Uint32Array(100)]).size", "400"); -shouldBe("new Blob([new Int8Array(100)]).size", "100"); -shouldBe("new Blob([new Int16Array(100)]).size", "200"); -shouldBe("new Blob([new Int32Array(100)]).size", "400"); -shouldBe("new Blob([new Float32Array(100)]).size", "400"); -shouldBe("new Blob([new Float64Array(100)]).size", "800"); -shouldBe("new Blob([new Float64Array(100), new Int32Array(100), new Uint8Array(100), new DataView(new ArrayBuffer(100))]).size", "1400"); -shouldBe("new Blob([new Blob([new Int32Array(100)]), new Uint8Array(100), new Float32Array(100), new DataView(new ArrayBuffer(100))]).size", "1000"); - -// Test ArrayBuffer Parameters -shouldBe("new Blob([(new DataView(new ArrayBuffer(100))).buffer]).size", "100"); -shouldBe("new Blob([(new Uint8Array(100)).buffer]).size", "100"); -shouldBe("new Blob([(new Uint8ClampedArray(100)).buffer]).size", "100"); -shouldBe("new Blob([(new Uint16Array(100)).buffer]).size", "200"); -shouldBe("new Blob([(new Uint32Array(100)).buffer]).size", "400"); -shouldBe("new Blob([(new Int8Array(100)).buffer]).size", "100"); -shouldBe("new Blob([(new Int16Array(100)).buffer]).size", "200"); -shouldBe("new Blob([(new Int32Array(100)).buffer]).size", "400"); -shouldBe("new Blob([(new Float32Array(100)).buffer]).size", "400"); -shouldBe("new Blob([(new Float64Array(100)).buffer]).size", "800"); -shouldBe("new Blob([(new Float64Array(100)).buffer, (new Int32Array(100)).buffer, (new Uint8Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size", "1400"); -shouldBe("new Blob([new Blob([(new Int32Array(100)).buffer]), (new Uint8Array(100)).buffer, (new Float32Array(100)).buffer, (new DataView(new ArrayBuffer(100))).buffer]).size", "1000"); - -// Test passing blob parts in sequences. -shouldBeTrue("new Blob({length: 0}) instanceof window.Blob"); -shouldBe("new Blob({length: 0}).size", "0"); -shouldBe("new Blob({length: 1, 0: 'string'}).size", "6"); -shouldBe("new Blob({length: 2, 0: new Uint8Array(100), 1: new Int16Array(100)}).size", "300"); -shouldBe("new Blob({length: 1, 0: 'string'}, {type: 'text/html'}).type", "'text/html'"); -shouldThrow("new Blob({length: 0}, {endings:'illegal'})", "'TypeError: Failed to construct \\'Blob\\': The 2nd argument\\'s \"endings\" property must be either \"transparent\" or \"native\".'"); - -// Test passing blog parts in a sequence-like object that throws on property access. -var throwingSequence = {length: 4, 0: 'hello', 3: 'world'}; -Object.defineProperty(throwingSequence, "1", { - get: function() { throw new Error("Misbehaving property"); }, - enumerable: true, configurable: true -}); -Object.defineProperty(throwingSequence, "2", { - get: function() { throw new Error("This should not be thrown"); }, - enumerable: true, configurable: true -}); -shouldThrow("new Blob(throwingSequence)", "'Error: Misbehaving property'"); diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt index 062c72f..420e464 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt @@ -4,19 +4,24 @@ Test verifies that content MIME type is set correctly when Blob is sent using XM On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS expectedMimeType is "text/plain;charset=utf-8" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "multipart/mixed;boundary=\"--blob-boundary\"" -PASS expectedMimeType is "" +PASS postedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "multipart/mixed;boundary=\"--blob-boundary\"" +PASS postedMimeType is "" PASS Exception should be thrown. PASS Cross-origin request without CORS headers should fail. -PASS expectedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "multipart/mixed;boundary=\"--blob-boundary\"" +PASS Exception should be thrown. PASS successfullyParsed is true TEST COMPLETE diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async.html index 1315f3e5..1dc1fb05 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async.html +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async.html @@ -1,73 +1,78 @@ <!DOCTYPE html> -<html> -<head> - <script src="/js-test-resources/js-test.js"></script> -</head> -<body> - <script src="post-blob-content-type-tests.js"></script> - <script type="text/javascript"> - description("Test verifies that content MIME type is set correctly " + - "when Blob is sent using " + - "<a href='http://www.w3.org/TR/XMLHttpRequest/#the-send-method'>XMLHttpRequest asynchronously.</a>"); - var xhr; - var expectedMimeType; - window.jsTestIsAsync = true; - var asyncTestCase = 0; +<script src="/js-test-resources/js-test.js"></script> +<script src="post-blob-content-type-tests.js"></script> +<script type="text/javascript"> + description("Test verifies that content MIME type is set correctly " + + "when Blob is sent using " + + "<a href='http://www.w3.org/TR/XMLHttpRequest/#the-send-method'>XMLHttpRequest asynchronously.</a>"); - function runNextAsyncTest() { - asyncTestCase++; - runAsyncTests(); - } + var xhr; + var expectedMimeType; + window.jsTestIsAsync = true; + var asyncTestCase = 0; - function reportResult(e) { - if (xhr.status === 200) { - expectedMimeType = JSON.parse(xhr.response)['content-type'] || ""; - shouldBeEqualToString("expectedMimeType", xhrBlobTestCases[asyncTestCase].expectedMime); - } else if (xhr.status === 0 && xhrBlobTestCases[asyncTestCase].shouldThrow){ - testPassed("Cross-origin request without CORS headers should fail."); - } else { - testFailed("Unknown error"); - } + function runNextAsyncTest() { + asyncTestCase++; + runAsyncTests(); + } - runNextAsyncTest(); - } + function reportResult(e) { + var testCase = xhrBlobTestCases[asyncTestCase]; + if (xhr.status === 200) { + postedMimeType = JSON.parse(xhr.response)['content-type'] || ""; + shouldBeEqualToString("postedMimeType", testCase.expectedMime); + } else if (xhr.status === 0 && testCase.shouldThrow){ + testPassed("Cross-origin request without CORS headers should fail."); + } else { + testFailed("Unknown error"); + } - function runAsyncTests() { - if (asyncTestCase >= xhrBlobTestCases.length) { - finishJSTest(); - return; - } else { - var mime = xhrBlobTestCases[asyncTestCase].mime; - var url = xhrBlobTestCases[asyncTestCase].url !== undefined ? xhrBlobTestCases[asyncTestCase].url + xhrBlobTestUrl : xhrBlobTestUrl; - url += xhrBlobTestCases[asyncTestCase].allowOrigin || ""; - if (xhrBlobTestCases[asyncTestCase].shouldThrow !== undefined) { - try { - testBlobContentTypeAsync(url, mime); - } catch (e) { - testPassed("Exception should be thrown.") - runNextAsyncTest(); - } - } else - testBlobContentTypeAsync(url, mime); - } - } + runNextAsyncTest(); + } - function testBlobContentTypeAsync(url, mimeType) { - var blob; - if (mimeType !== "") - blob = new Blob(["Test content"], {type: mimeType}); - else - blob = new Blob(["Test content"]); + function runAsyncTests() { + if (asyncTestCase >= xhrBlobTestCases.length) { + finishJSTest(); + return; + } else { + var testCase = xhrBlobTestCases[asyncTestCase]; + var mime = testCase.mime; + var file = testCase.file; + var url = testCase.url !== undefined ? testCase.url + xhrBlobTestUrl : xhrBlobTestUrl; + url += testCase.allowOrigin || ""; + if (testCase.shouldThrow !== undefined) { + try { + testBlobContentTypeAsync(url, mime, file); + } catch (e) { + testPassed("Exception should be thrown.") + runNextAsyncTest(); + } + } else + testBlobContentTypeAsync(url, mime); + } + } - xhr = new XMLHttpRequest(); - xhr.onloadend = reportResult; - xhr.open("POST", url, true); - xhr.send(blob); - } + function testBlobContentTypeAsync(url, mimeType, fileName) { + var blob; + if (fileName) { + if (mimeType !== "") + blob = new File(["Test content"], fileName, {type: mimeType}); + else + blob = new File(["Test content"], fileName); + } else { + if (mimeType !== "") + blob = new Blob(["Test content"], {type: mimeType}); + else + blob = new Blob(["Test content"]); + } - runAsyncTests(); + xhr = new XMLHttpRequest(); + xhr.onloadend = reportResult; + xhr.open("POST", url, true); + xhr.send(blob); + } - </script> -</body> -</html> + runAsyncTests(); + +</script> diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt index 853476f..90920def 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt @@ -4,19 +4,24 @@ Test verifies that content MIME type is set correctly when Blob is sent using XM On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS expectedMimeType is "text/plain;charset=utf-8" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "" -PASS expectedMimeType is "multipart/mixed;boundary=\"--blob-boundary\"" -PASS expectedMimeType is "" +PASS postedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "multipart/mixed;boundary=\"--blob-boundary\"" +PASS postedMimeType is "" PASS Exception should be thrown. PASS Exception should be thrown. -PASS expectedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "text/plain;charset=utf-8" +PASS postedMimeType is "" +PASS postedMimeType is "" +PASS postedMimeType is "multipart/mixed;boundary=\"--blob-boundary\"" +PASS Exception should be thrown. PASS successfullyParsed is true TEST COMPLETE diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync.html index 4a78bd6..e111c94 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync.html +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync.html @@ -1,57 +1,61 @@ <!DOCTYPE html> -<html> -<head> - <script src="/js-test-resources/js-test.js"></script> -</head> -<body> - <script src="post-blob-content-type-tests.js"></script> - <script type="text/javascript"> - description("Test verifies that content MIME type is set correctly " + - "when Blob is sent using " + - "<a href='http://www.w3.org/TR/XMLHttpRequest/#the-send-method'>XMLHttpRequest synchronously.</a>"); - - var xhr; - var expectedMimeType; - - function runSyncTests() { - var testCount = xhrBlobTestCases.length; - for (var i = 0; i < testCount; i++) { - var mime = xhrBlobTestCases[i].mime; - var expectedMime = xhrBlobTestCases[i].expectedMime; - var url = xhrBlobTestCases[i].url !== undefined ? xhrBlobTestCases[i].url + xhrBlobTestUrl : xhrBlobTestUrl; - url += xhrBlobTestCases[i].allowOrigin || ""; - if (xhrBlobTestCases[i].shouldThrow !== undefined) { - try { - testBlobContentTypeSync(url, mime, expectedMime); - } catch (e) { - testPassed("Exception should be thrown.") - } - } else { - testBlobContentTypeSync(url, mime, expectedMime); - } - } - } - - function testBlobContentTypeSync(url, mimeType, expectedMime) { - var blob; - if (mimeType !== "") - blob = new Blob(["Test content"], {type: mimeType}); - else - blob = new Blob(["Test content"]); - - xhr = new XMLHttpRequest(); - xhr.open("POST", url, false); - xhr.send(blob); - if (xhr.status === 200) { - expectedMimeType = JSON.parse(xhr.response)['content-type'] || ""; - shouldBeEqualToString("expectedMimeType", expectedMime); - } else - testFailed("Unknown error"); - - } - - runSyncTests(); - - </script> -</body> -</html> + +<script src="/js-test-resources/js-test.js"></script> +<script src="post-blob-content-type-tests.js"></script> +<script type="text/javascript"> + description("Test verifies that content MIME type is set correctly " + + "when Blob is sent using " + + "<a href='http://www.w3.org/TR/XMLHttpRequest/#the-send-method'>XMLHttpRequest synchronously.</a>"); + + var xhr; + var expectedMimeType; + + function runSyncTests() { + var testCount = xhrBlobTestCases.length; + for (var i = 0; i < testCount; i++) { + var testCase = xhrBlobTestCases[i]; + var mime = testCase.mime; + var file = testCase.file; + var expectedMime = testCase.expectedMime; + var url = testCase.url !== undefined ? testCase.url + xhrBlobTestUrl : xhrBlobTestUrl; + url += testCase.allowOrigin || ""; + if (testCase.shouldThrow !== undefined) { + try { + testBlobContentTypeSync(url, file, mime, expectedMime); + } catch (e) { + testPassed("Exception should be thrown.") + } + } else { + testBlobContentTypeSync(url, file, mime, expectedMime); + } + } + } + + function testBlobContentTypeSync(url, fileName, mimeType, expectedMime) { + var blob; + if (fileName) { + if (mimeType !== "") + blob = new File(["Test content"], fileName, {type: mimeType}); + else + blob = new File(["Test content"], fileName); + } else { + if (mimeType !== "") + blob = new Blob(["Test content"], {type: mimeType}); + else + blob = new Blob(["Test content"]); + } + + xhr = new XMLHttpRequest(); + xhr.open("POST", url, false); + xhr.send(blob); + if (xhr.status === 200) { + postedMimeType = JSON.parse(xhr.response)['content-type'] || ""; + shouldBeEqualToString("postedMimeType", expectedMime); + } else + testFailed("Unknown error"); + + } + + runSyncTests(); + +</script> diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-tests.js b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-tests.js index b2f29bc..6b5c611 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-tests.js +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-tests.js @@ -45,4 +45,25 @@ var xhrBlobTestCases = [{ expectedMime: 'text/plain;charset=utf-8', url: 'http://localhost:8000', allowOrigin: '?origin=http://127.0.0.1:8000' -}];
\ No newline at end of file +}, { + mime: 'text/plain;charset=utf-8', + expectedMime: 'text/plain;charset=utf-8', + file: 'hello.txt' +}, { + mime: 'ASCII/CR\r;charset=invalid', + expectedMime: '', + file: 'hello.txt' +}, { + mime: '', + expectedMime: '', + file: 'hello.txt' +}, { + mime: 'multipart/mixed;boundary="--blob-boundary"', + expectedMime: 'multipart/mixed;boundary="--blob-boundary"', + file: 'hello.txt' +}, { + mime: '\u0422\u0435\u0441\u0442', + expectedMime: '', + shouldThrow: true, + file: 'hello.txt' +}]; diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-content-type.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-content-type.html index bc7aff4..973b95e 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-content-type.html +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-content-type.html @@ -1,5 +1,5 @@ -<html> -<body> +<!DOCTYPE html> + <p>Test for <a href="http://crbug.com/172802">bug 172802</a> - Wrong default Content-Type set in XMLHttpRequest.send(DOMString)</p> <p>Should be text/plain;charset=UTF-8:</p> @@ -12,5 +12,3 @@ objXmlHttp.send(""); document.write("<pre>" + objXmlHttp.responseText + "</pre>"); </script> -</body> -</html> diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-formdata-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-formdata-expected.txt new file mode 100644 index 0000000..296dc7b --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-formdata-expected.txt @@ -0,0 +1,16 @@ +Test verifies that FormData is sent correctly when using XMLHttpRequest asynchronously. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS echoResult is "string=string value" +PASS echoResult is "bareBlob=blob:application/octet-stream:blob-value" +PASS echoResult is "mimeBlob=blob:text/html:blob-value" +PASS echoResult is "namedBlob=blob-file.txt:application/octet-stream:blob-value" +PASS echoResult is "bareFile=file-name.txt:application/octet-stream:file-value" +PASS echoResult is "mimeFile=file-name.html:text/html:file-value" +PASS echoResult is "renamedFile=file-name-override.html:text/html:file-value" +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-formdata.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-formdata.html new file mode 100644 index 0000000..8777ddc --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-formdata.html @@ -0,0 +1,89 @@ +<!DOCTYPE html> + +<script src="/js-test-resources/js-test.js"></script> +<script> +description("Test verifies that FormData is sent correctly when using " + + "<a href='http://www.w3.org/TR/XMLHttpRequest/#the-send-method'>XMLHttpRequest asynchronously.</a>"); + +var xhrFormDataTestUrl = '/xmlhttprequest/resources/multipart-post-echo.php'; +var xhrFormDataTestCases = [{ + data: { string: 'string value' }, + result: "string=string value" +}, { + data: { bareBlob: new Blob(['blob-value']) }, + result: 'bareBlob=blob:application/octet-stream:blob-value' +}, { + data: { mimeBlob: new Blob(['blob-value'], { type: 'text/html' }) }, + result: 'mimeBlob=blob:text/html:blob-value' +}, { + data: { + namedBlob: { + value: new Blob(['blob-value']), + fileName: 'blob-file.txt' + } + }, + result: 'namedBlob=blob-file.txt:application/octet-stream:blob-value' +}, { + data: { bareFile: new File(['file-value'], 'file-name.txt') }, + result: 'bareFile=file-name.txt:application/octet-stream:file-value' +}, { + data: { + mimeFile: new File(['file-value'], 'file-name.html', { type: 'text/html' }) + }, + result: 'mimeFile=file-name.html:text/html:file-value' +}, { + data: { + renamedFile: { + value: new File(['file-value'], 'file-name.html', { type: 'text/html' }), + fileName: 'file-name-override.html' + } + }, + result: 'renamedFile=file-name-override.html:text/html:file-value' +}]; + +var xhr; +var expectedMimeType; +window.jsTestIsAsync = true; +var asyncTestCase = 0; + +function runNextAsyncTest() { + asyncTestCase++; + runAsyncTests(); +} + +function reportResult(e) { + var testCase = xhrFormDataTestCases[asyncTestCase]; + if (xhr.status === 200) { + echoResult = xhr.response; + shouldBeEqualToString("echoResult", testCase.result); + } else { + testFailed("Unknown error"); + } + + runNextAsyncTest(); +} + +function runAsyncTests() { + if (asyncTestCase >= xhrFormDataTestCases.length) { + finishJSTest(); + return; + } + + var testCase = xhrFormDataTestCases[asyncTestCase]; + var formData = new FormData(); + for (var fieldName in testCase.data) { + fieldValue = testCase.data[fieldName]; + if (fieldValue.constructor === Object) + formData.append(fieldName, fieldValue.value, fieldValue.fileName); + else + formData.append(fieldName, fieldValue); + } + + xhr = new XMLHttpRequest(); + xhr.onloadend = reportResult; + xhr.open("POST", xhrFormDataTestUrl, true); + xhr.send(formData); +} + +runAsyncTests(); +</script> diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-dedicated-worker-expected.txt index 9a63e99..165afe3 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-dedicated-worker-expected.txt @@ -14,6 +14,7 @@ Starting worker: resources/global-context-constructors-listing.js [Worker] Error [Worker] EvalError [Worker] EventSource +[Worker] File [Worker] FileError [Worker] FileReader [Worker] FileReaderSync diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-shared-worker-expected.txt index ac0ee39..8cb2046 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-constructors-listing-shared-worker-expected.txt @@ -13,6 +13,7 @@ Starting worker: resources/global-context-constructors-listing.js [Worker] Error [Worker] EvalError [Worker] EventSource +[Worker] File [Worker] FileError [Worker] FileReader [Worker] FileReaderSync diff --git a/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-dedicated-worker-expected.txt index 45da6b0..e3912c7 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-dedicated-worker-expected.txt @@ -14,6 +14,7 @@ Starting worker: resources/global-context-constructors-listing.js [Worker] Error [Worker] EvalError [Worker] EventSource +[Worker] File [Worker] FileError [Worker] FileReader [Worker] FileReaderSync diff --git a/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-shared-worker-expected.txt index 35d341b..a06d5e2 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-constructors-listing-shared-worker-expected.txt @@ -13,6 +13,7 @@ Starting worker: resources/global-context-constructors-listing.js [Worker] Error [Worker] EvalError [Worker] EventSource +[Worker] File [Worker] FileError [Worker] FileReader [Worker] FileReaderSync diff --git a/third_party/WebKit/Source/bindings/bindings.gypi b/third_party/WebKit/Source/bindings/bindings.gypi index c7d340a..9f02268 100644 --- a/third_party/WebKit/Source/bindings/bindings.gypi +++ b/third_party/WebKit/Source/bindings/bindings.gypi @@ -152,6 +152,8 @@ 'v8/custom/V8AudioNodeCustom.cpp', 'v8/custom/V8BiquadFilterNodeCustom.cpp', 'v8/custom/V8BlobCustom.cpp', + 'v8/custom/V8BlobCustomHelpers.cpp', + 'v8/custom/V8BlobCustomHelpers.h', 'v8/custom/V8CSSRuleCustom.cpp', 'v8/custom/V8CSSStyleDeclarationCustom.cpp', 'v8/custom/V8CSSValueCustom.cpp', @@ -173,6 +175,7 @@ 'v8/custom/V8EventCustom.cpp', 'v8/custom/V8EventTargetCustom.cpp', 'v8/custom/V8ErrorEventCustom.cpp', + 'v8/custom/V8FileCustom.cpp', 'v8/custom/V8FileReaderCustom.cpp', 'v8/custom/V8Float32ArrayCustom.h', 'v8/custom/V8Float64ArrayCustom.h', diff --git a/third_party/WebKit/Source/bindings/v8/V8BindingMacros.h b/third_party/WebKit/Source/bindings/v8/V8BindingMacros.h index 0123dbf..8098652 100644 --- a/third_party/WebKit/Source/bindings/v8/V8BindingMacros.h +++ b/third_party/WebKit/Source/bindings/v8/V8BindingMacros.h @@ -42,6 +42,17 @@ namespace WebCore { return block.ReThrow(); \ } +#define V8TRYCATCH_RETURN(type, var, value, retVal) \ + type var; \ + { \ + v8::TryCatch block; \ + var = (value); \ + if (block.HasCaught()) { \ + block.ReThrow(); \ + return retVal; \ + } \ + } + #define V8TRYCATCH_VOID(type, var, value) \ type var; \ { \ diff --git a/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustom.cpp b/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustom.cpp index 96ba613..be506f8 100644 --- a/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustom.cpp +++ b/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustom.cpp @@ -31,14 +31,8 @@ #include "config.h" #include "V8Blob.h" -#include "bindings/v8/Dictionary.h" -#include "bindings/v8/ExceptionMessages.h" -#include "bindings/v8/V8Binding.h" -#include "bindings/v8/V8Utilities.h" -#include "bindings/v8/custom/V8ArrayBufferCustom.h" -#include "bindings/v8/custom/V8ArrayBufferViewCustom.h" +#include "bindings/v8/custom/V8BlobCustomHelpers.h" #include "core/fileapi/BlobBuilder.h" -#include "wtf/RefPtr.h" namespace WebCore { @@ -46,7 +40,7 @@ void V8Blob::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { if (!info.Length()) { RefPtr<Blob> blob = Blob::create(); - info.GetReturnValue().Set(toV8(blob.get(), info.Holder(), info.GetIsolate())); + v8SetReturnValue(info, blob.release()); return; } @@ -61,63 +55,25 @@ void V8Blob::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) } } - String type; - String endings = "transparent"; - + String contentType; + String endings = "transparent"; // default if no BlobPropertyBag is passed if (info.Length() > 1) { if (!info[1]->IsObject()) { throwTypeError(ExceptionMessages::failedToConstruct("Blob", "The 2nd argument is not of type Object."), info.GetIsolate()); return; } - V8TRYCATCH_VOID(Dictionary, dictionary, Dictionary(info[1], info.GetIsolate())); - - V8TRYCATCH_VOID(bool, containsEndings, dictionary.get("endings", endings)); - if (containsEndings) { - if (endings != "transparent" && endings != "native") { - throwTypeError(ExceptionMessages::failedToConstruct("Blob", "The 2nd argument's \"endings\" property must be either \"transparent\" or \"native\"."), info.GetIsolate()); - return; - } - } - - V8TRYCATCH_VOID(bool, containsType, dictionary.get("type", type)); - UNUSED_PARAM(containsType); - if (!type.containsOnlyASCII()) { - throwError(v8SyntaxError, ExceptionMessages::failedToConstruct("Blob", "The 2nd argument's \"type\" property must consist of ASCII characters."), info.GetIsolate()); + if (!V8BlobCustomHelpers::processBlobPropertyBag(info[1], "Blob", contentType, endings, info.GetIsolate())) return; - } - type = type.lower(); } - ASSERT(endings == "transparent" || endings == "native"); - BlobBuilder blobBuilder; v8::Local<v8::Object> blobParts = v8::Local<v8::Object>::Cast(info[0]); - for (uint32_t i = 0; i < length; ++i) { - v8::Local<v8::Value> item = blobParts->Get(v8::Uint32::New(i, info.GetIsolate())); - if (item.IsEmpty()) - return; - - if (V8ArrayBuffer::hasInstance(item, info.GetIsolate(), worldType(info.GetIsolate()))) { - ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(item)); - ASSERT(arrayBuffer); - blobBuilder.append(arrayBuffer); - } else if (V8ArrayBufferView::hasInstance(item, info.GetIsolate(), worldType(info.GetIsolate()))) { - ArrayBufferView* arrayBufferView = V8ArrayBufferView::toNative(v8::Handle<v8::Object>::Cast(item)); - ASSERT(arrayBufferView); - blobBuilder.append(arrayBufferView); - } else if (V8Blob::hasInstance(item, info.GetIsolate(), worldType(info.GetIsolate()))) { - Blob* blob = V8Blob::toNative(v8::Handle<v8::Object>::Cast(item)); - ASSERT(blob); - blobBuilder.append(blob); - } else { - V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, stringValue, item); - blobBuilder.append(stringValue, endings); - } - } + if (!V8BlobCustomHelpers::processBlobParts(blobParts, length, endings, blobBuilder, info.GetIsolate())) + return; - RefPtr<Blob> blob = blobBuilder.getBlob(type); - info.GetReturnValue().Set(toV8(blob.get(), info.Holder(), info.GetIsolate())); + RefPtr<Blob> blob = blobBuilder.createBlob(contentType); + v8SetReturnValue(info, blob.release()); } } // namespace WebCore diff --git a/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustomHelpers.cpp b/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustomHelpers.cpp new file mode 100644 index 0000000..ee35937 --- /dev/null +++ b/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustomHelpers.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "V8BlobCustomHelpers.h" + +#include "V8Blob.h" +#include "bindings/v8/Dictionary.h" +#include "bindings/v8/V8Binding.h" +#include "bindings/v8/V8Utilities.h" +#include "bindings/v8/custom/V8ArrayBufferCustom.h" +#include "bindings/v8/custom/V8ArrayBufferViewCustom.h" +#include "core/fileapi/BlobBuilder.h" + +namespace WebCore { + +namespace V8BlobCustomHelpers { + +bool processBlobPropertyBag(v8::Local<v8::Value> propertyBag, const char* blobClassName, String& contentType, String& endings, v8::Isolate* isolate) +{ + ASSERT(endings == "transparent"); + + V8TRYCATCH_RETURN(Dictionary, dictionary, Dictionary(propertyBag, isolate), false); + + V8TRYCATCH_RETURN(bool, containsEndings, dictionary.get("endings", endings), false); + if (containsEndings) { + if (endings != "transparent" && endings != "native") { + throwTypeError(ExceptionMessages::failedToConstruct(blobClassName, "The \"endings\" property must be either \"transparent\" or \"native\"."), isolate); + return false; + } + } + + V8TRYCATCH_RETURN(bool, containsType, dictionary.get("type", contentType), false); + if (containsType) { + if (!contentType.containsOnlyASCII()) { + throwError(v8SyntaxError, ExceptionMessages::failedToConstruct(blobClassName, "The \"type\" property must consist of ASCII characters."), isolate); + return false; + } + contentType = contentType.lower(); + } + return true; +} + +bool processBlobParts(v8::Local<v8::Object> blobParts, uint32_t blobPartsLength, const String& endings, BlobBuilder& blobBuilder, v8::Isolate* isolate) +{ + ASSERT(endings == "transparent" || endings == "native"); + + for (uint32_t i = 0; i < blobPartsLength; ++i) { + v8::Local<v8::Value> item = blobParts->Get(v8::Uint32::New(i, isolate)); + if (item.IsEmpty()) + return false; + + if (V8ArrayBuffer::hasInstance(item, isolate, worldType(isolate))) { + ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(item)); + ASSERT(arrayBuffer); + blobBuilder.append(arrayBuffer); + } else if (V8ArrayBufferView::hasInstance(item, isolate, worldType(isolate))) { + ArrayBufferView* arrayBufferView = V8ArrayBufferView::toNative(v8::Handle<v8::Object>::Cast(item)); + ASSERT(arrayBufferView); + blobBuilder.append(arrayBufferView); + } else if (V8Blob::hasInstance(item, isolate, worldType(isolate))) { + Blob* blob = V8Blob::toNative(v8::Handle<v8::Object>::Cast(item)); + ASSERT(blob); + blobBuilder.append(blob); + } else { + V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, item, false); + blobBuilder.append(stringValue, endings); + } + } + return true; +} + +} // namespace V8BlobCustomHelpers + +} // namespace WebCore diff --git a/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustomHelpers.h b/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustomHelpers.h new file mode 100644 index 0000000..8bb22f0 --- /dev/null +++ b/third_party/WebKit/Source/bindings/v8/custom/V8BlobCustomHelpers.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef V8BlobCustomHelpers_h +#define V8BlobCustomHelpers_h + +#include "bindings/v8/V8Binding.h" + +namespace WebCore { + +class BlobBuilder; + +// Shared code between the custom constructor bindings for Blob and File. +namespace V8BlobCustomHelpers { + +// Extracts the "type" and "endings" properties out of the BlobPropertyBag passed to a Blob constructor. +// http://www.w3.org/TR/FileAPI/#constructorParams +// Returns true if everything went well, false if a JS exception was thrown. +bool processBlobPropertyBag(v8::Local<v8::Value> propertyBag, const char* blobClassName, String& contentType, String& endings, v8::Isolate*); + +// Appends the blobParts passed to a Blob constructor into a BlobBuilder. +// http://www.w3.org/TR/FileAPI/#constructorParams +// Returns true if everything went well, false if a JS exception was thrown. +bool processBlobParts(v8::Local<v8::Object> blobParts, uint32_t blobPartsLength, const String& endings, BlobBuilder&, v8::Isolate*); + +} // namespace V8BlobCustomHelpers + +} // namespace WebCore + +#endif // V8BlobCustomHelpers_h diff --git a/third_party/WebKit/Source/bindings/v8/custom/V8FileCustom.cpp b/third_party/WebKit/Source/bindings/v8/custom/V8FileCustom.cpp new file mode 100644 index 0000000..6983ef2 --- /dev/null +++ b/third_party/WebKit/Source/bindings/v8/custom/V8FileCustom.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "V8File.h" + +#include "RuntimeEnabledFeatures.h" +#include "bindings/v8/custom/V8BlobCustomHelpers.h" +#include "core/fileapi/BlobBuilder.h" + +namespace WebCore { + +void V8File::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) +{ + if (!RuntimeEnabledFeatures::fileConstructorEnabled()) { + throwTypeError("Illegal constructor", info.GetIsolate()); + return; + } + + if (info.Length() < 2) { + throwTypeError("File constructor requires at least two arguments", info.GetIsolate()); + return; + } + + uint32_t length = 0; + if (info[0]->IsArray()) { + length = v8::Local<v8::Array>::Cast(info[0])->Length(); + } else { + const int sequenceArgumentIndex = 0; + if (toV8Sequence(info[sequenceArgumentIndex], length, info.GetIsolate()).IsEmpty()) { + throwTypeError(ExceptionMessages::failedToConstruct("File", ExceptionMessages::notAnArrayTypeArgumentOrValue(sequenceArgumentIndex + 1)), info.GetIsolate()); + return; + } + } + + V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, fileName, info[1]); + + String contentType; + String endings = "transparent"; // default if no BlobPropertyBag is passed + if (info.Length() > 2) { + if (!info[2]->IsObject()) { + throwTypeError(ExceptionMessages::failedToConstruct("File", "The 3rd argument is not of type Object."), info.GetIsolate()); + return; + } + + if (!V8BlobCustomHelpers::processBlobPropertyBag(info[2], "File", contentType, endings, info.GetIsolate())) + return; + } + + BlobBuilder blobBuilder; + v8::Local<v8::Object> blobParts = v8::Local<v8::Object>::Cast(info[0]); + if (!V8BlobCustomHelpers::processBlobParts(blobParts, length, endings, blobBuilder, info.GetIsolate())) + return; + + RefPtr<File> file = blobBuilder.createFile(contentType, fileName, currentTime()); + v8SetReturnValue(info, file.release()); +} + +} // namespace WebCore diff --git a/third_party/WebKit/Source/core/fileapi/Blob.cpp b/third_party/WebKit/Source/core/fileapi/Blob.cpp index 5fda7d84..def1ae0 100644 --- a/third_party/WebKit/Source/core/fileapi/Blob.cpp +++ b/third_party/WebKit/Source/core/fileapi/Blob.cpp @@ -82,7 +82,7 @@ PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& conte // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed. long long size; double modificationTime; - if (isFile()) { + if (hasBackingFile()) { // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous. toFile(this)->captureSnapshot(size, modificationTime); } else { @@ -112,7 +112,7 @@ PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& conte long long length = end - start; OwnPtr<BlobData> blobData = BlobData::create(); blobData->setContentType(contentType); - if (isFile()) { + if (hasBackingFile()) { if (!toFile(this)->fileSystemURL().isEmpty()) blobData->appendFileSystemURL(toFile(this)->fileSystemURL(), start, length, modificationTime); else diff --git a/third_party/WebKit/Source/core/fileapi/Blob.h b/third_party/WebKit/Source/core/fileapi/Blob.h index 58006c8..6a72155 100644 --- a/third_party/WebKit/Source/core/fileapi/Blob.h +++ b/third_party/WebKit/Source/core/fileapi/Blob.h @@ -60,7 +60,10 @@ public: String uuid() const { return m_blobDataHandle->uuid(); } String type() const { return m_blobDataHandle->type(); } virtual unsigned long long size() const { return m_blobDataHandle->size(); } + // True for all File instances, including the user-built ones. virtual bool isFile() const { return false; } + // Only true for File instances that are backed by platform files. + virtual bool hasBackingFile() const { return false; } PassRefPtr<BlobDataHandle> blobDataHandle() const { return m_blobDataHandle; } PassRefPtr<Blob> slice(long long start = 0, long long end = std::numeric_limits<long long>::max(), const String& contentType = String()) const; diff --git a/third_party/WebKit/Source/core/fileapi/BlobBuilder.cpp b/third_party/WebKit/Source/core/fileapi/BlobBuilder.cpp index 8be60c1..70583af 100644 --- a/third_party/WebKit/Source/core/fileapi/BlobBuilder.cpp +++ b/third_party/WebKit/Source/core/fileapi/BlobBuilder.cpp @@ -94,7 +94,7 @@ void BlobBuilder::append(Blob* blob) { if (!blob) return; - if (blob->isFile()) { + if (blob->hasBackingFile()) { File* file = toFile(blob); // If the blob is file that is not snapshoted, capture the snapshot now. // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous. @@ -122,7 +122,7 @@ void BlobBuilder::appendBytesData(const void* data, size_t length) m_size += buffer.size() - oldSize; } -PassRefPtr<Blob> BlobBuilder::getBlob(const String& contentType) +PassRefPtr<Blob> BlobBuilder::createBlob(const String& contentType) { OwnPtr<BlobData> blobData = BlobData::create(); blobData->setContentType(contentType); @@ -134,7 +134,22 @@ PassRefPtr<Blob> BlobBuilder::getBlob(const String& contentType) // Instead, we only need to keep a reference to the blob data just created. m_items.append(BlobDataItem(blob->blobDataHandle(), 0, m_size)); - return blob; + return blob.release(); +} + +PassRefPtr<File> BlobBuilder::createFile(const String& contentType, const String& fileName, double modificationTime) +{ + OwnPtr<BlobData> blobData = BlobData::create(); + blobData->setContentType(contentType); + blobData->swapItems(m_items); + + RefPtr<File> file = File::create(fileName, modificationTime, BlobDataHandle::create(blobData.release(), m_size)); + + // After creating a file from the current blob data, we do not need to keep the data around any more. + // Instead, we only need to keep a reference to the blob data just created. + m_items.append(BlobDataItem(file->blobDataHandle(), 0, m_size)); + + return file.release(); } } // namespace WebCore diff --git a/third_party/WebKit/Source/core/fileapi/BlobBuilder.h b/third_party/WebKit/Source/core/fileapi/BlobBuilder.h index 560a79c..cdf3cc5 100644 --- a/third_party/WebKit/Source/core/fileapi/BlobBuilder.h +++ b/third_party/WebKit/Source/core/fileapi/BlobBuilder.h @@ -34,15 +34,10 @@ #include "platform/blob/BlobData.h" #include "wtf/Forward.h" -namespace WTF{ -class TextEncoding; -} - namespace WebCore { class Blob; - -typedef int ExceptionCode; +class File; class BlobBuilder { public: @@ -53,7 +48,8 @@ public: void append(ArrayBuffer*); void append(ArrayBufferView*); - PassRefPtr<Blob> getBlob(const String& contentType); + PassRefPtr<Blob> createBlob(const String& contentType); + PassRefPtr<File> createFile(const String& contentType, const String& fileName, double modificationTime); private: void appendBytesData(const void*, size_t); diff --git a/third_party/WebKit/Source/core/fileapi/File.cpp b/third_party/WebKit/Source/core/fileapi/File.cpp index 02d9700..6842161 100644 --- a/third_party/WebKit/Source/core/fileapi/File.cpp +++ b/third_party/WebKit/Source/core/fileapi/File.cpp @@ -94,6 +94,7 @@ PassRefPtr<File> File::createWithRelativePath(const String& path, const String& File::File(const String& path, ContentTypeLookupPolicy policy) : Blob(BlobDataHandle::create(createBlobDataForFile(path, policy), -1)) + , m_hasBackingFile(true) , m_path(path) , m_name(blink::Platform::current()->fileUtilities()->baseName(path)) , m_snapshotSize(-1) @@ -104,6 +105,7 @@ File::File(const String& path, ContentTypeLookupPolicy policy) File::File(const String& path, const String& name, ContentTypeLookupPolicy policy) : Blob(BlobDataHandle::create(createBlobDataForFileWithName(path, name, policy), -1)) + , m_hasBackingFile(true) , m_path(path) , m_name(name) , m_snapshotSize(-1) @@ -114,6 +116,7 @@ File::File(const String& path, const String& name, ContentTypeLookupPolicy polic File::File(const String& path, PassRefPtr<BlobDataHandle> blobDataHandle) : Blob(blobDataHandle) + , m_hasBackingFile(true) , m_path(path) , m_name(blink::Platform::current()->fileUtilities()->baseName(path)) , m_snapshotSize(-1) @@ -125,8 +128,19 @@ File::File(const String& path, PassRefPtr<BlobDataHandle> blobDataHandle) // See SerializedScriptValue.cpp. } +File::File(const String& name, double modificationTime, PassRefPtr<BlobDataHandle> blobDataHandle) + : Blob(blobDataHandle) + , m_hasBackingFile(false) + , m_name(name) + , m_snapshotSize(Blob::size()) + , m_snapshotModificationTime(modificationTime) +{ + ScriptWrappable::init(this); +} + File::File(const String& name, const FileMetadata& metadata) : Blob(BlobDataHandle::create(createBlobDataForFileWithMetadata(name, metadata), metadata.length)) + , m_hasBackingFile(true) , m_path(metadata.platformPath) , m_name(name) , m_snapshotSize(metadata.length) @@ -137,6 +151,7 @@ File::File(const String& name, const FileMetadata& metadata) File::File(const KURL& fileSystemURL, const FileMetadata& metadata) : Blob(BlobDataHandle::create(createBlobDataForFileSystemURL(fileSystemURL, metadata), metadata.length)) + , m_hasBackingFile(true) , m_fileSystemURL(fileSystemURL) , m_snapshotSize(metadata.length) , m_snapshotModificationTime(metadata.modificationTime) diff --git a/third_party/WebKit/Source/core/fileapi/File.h b/third_party/WebKit/Source/core/fileapi/File.h index c6d8db4..f9c87b4 100644 --- a/third_party/WebKit/Source/core/fileapi/File.h +++ b/third_party/WebKit/Source/core/fileapi/File.h @@ -49,6 +49,11 @@ public: return adoptRef(new File(path, policy)); } + static PassRefPtr<File> create(const String& name, double modificationTime, PassRefPtr<BlobDataHandle> blobDataHandle) + { + return adoptRef(new File(name, modificationTime, blobDataHandle)); + } + // For deserialization. static PassRefPtr<File> create(const String& path, PassRefPtr<BlobDataHandle> blobDataHandle) { @@ -70,7 +75,7 @@ public: return adoptRef(new File(url, metadata)); } - KURL fileSystemURL() const { return m_fileSystemURL; } + KURL fileSystemURL() const { ASSERT(m_hasBackingFile); return m_fileSystemURL; } // Create a file with a name exposed to the author (via File.name and associated DOM properties) that differs from the one provided in the path. static PassRefPtr<File> createWithName(const String& path, const String& name, ContentTypeLookupPolicy policy = WellKnownContentTypes) @@ -80,10 +85,11 @@ public: return adoptRef(new File(path, name, policy)); } - virtual unsigned long long size() const; - virtual bool isFile() const { return true; } + virtual unsigned long long size() const OVERRIDE; + virtual bool isFile() const OVERRIDE { return true; } + virtual bool hasBackingFile() const OVERRIDE { return m_hasBackingFile; } - const String& path() const { return m_path; } + const String& path() const { ASSERT(m_hasBackingFile); return m_path; } const String& name() const { return m_name; } // This returns the current date and time if the file's last modifiecation date is not known (per spec: http://www.w3.org/TR/FileAPI/#dfn-lastModifiedDate). @@ -99,12 +105,14 @@ private: File(const String& path, ContentTypeLookupPolicy); File(const String& path, const String& name, ContentTypeLookupPolicy); File(const String& path, PassRefPtr<BlobDataHandle>); + File(const String& name, double modificationTime, PassRefPtr<BlobDataHandle>); File(const String& name, const FileMetadata&); File(const KURL& fileSystemURL, const FileMetadata&); // Returns true if this has a valid snapshot metadata (i.e. m_snapshotSize >= 0). bool hasValidSnapshotMetadata() const { return m_snapshotSize >= 0; } + bool m_hasBackingFile; String m_path; String m_name; diff --git a/third_party/WebKit/Source/core/fileapi/File.idl b/third_party/WebKit/Source/core/fileapi/File.idl index 56be7fc..fdbe18d 100644 --- a/third_party/WebKit/Source/core/fileapi/File.idl +++ b/third_party/WebKit/Source/core/fileapi/File.idl @@ -23,7 +23,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -interface File : Blob { +[ + GlobalContext=Window&WorkerGlobalScope, + CustomConstructor(sequence<any> blobParts, DOMString fileName, optional BlobPropertyBag options) +] interface File : Blob { readonly attribute DOMString name; readonly attribute Date lastModifiedDate; [RuntimeEnabled=DirectoryUpload] readonly attribute DOMString webkitRelativePath; diff --git a/third_party/WebKit/Source/core/fileapi/FileReader.cpp b/third_party/WebKit/Source/core/fileapi/FileReader.cpp index 2dffe0d..a2a5673 100644 --- a/third_party/WebKit/Source/core/fileapi/FileReader.cpp +++ b/third_party/WebKit/Source/core/fileapi/FileReader.cpp @@ -54,7 +54,7 @@ const CString utf8BlobUUID(Blob* blob) const CString utf8FilePath(Blob* blob) { - return blob->isFile() ? toFile(blob)->path().utf8() : ""; + return blob->hasBackingFile() ? toFile(blob)->path().utf8() : ""; } #endif diff --git a/third_party/WebKit/Source/core/html/FormDataList.cpp b/third_party/WebKit/Source/core/html/FormDataList.cpp index f490596..b564d2c 100644 --- a/third_party/WebKit/Source/core/html/FormDataList.cpp +++ b/third_party/WebKit/Source/core/html/FormDataList.cpp @@ -115,7 +115,7 @@ void FormDataList::appendKeyValuePairItemsTo(FormData* formData, const WTF::Text // Append body formData->appendData(header.data(), header.size()); if (value.blob()) { - if (value.blob()->isFile()) { + if (value.blob()->hasBackingFile()) { File* file = toFile(value.blob()); // Do not add the file if the path is empty. if (!file->path().isEmpty()) diff --git a/third_party/WebKit/Source/core/xml/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xml/XMLHttpRequest.cpp index f8e652a..a5311cb 100644 --- a/third_party/WebKit/Source/core/xml/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xml/XMLHttpRequest.cpp @@ -684,7 +684,7 @@ void XMLHttpRequest::send(Blob* body, ExceptionState& es) // FIXME: add support for uploading bundles. m_requestEntityBody = FormData::create(); - if (body->isFile()) + if (body->hasBackingFile()) m_requestEntityBody->appendFile(toFile(body)->path()); else m_requestEntityBody->appendBlob(body->uuid(), body->blobDataHandle()); diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index 2a730f3..1710595 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in @@ -50,6 +50,7 @@ EncryptedMedia status=experimental EncryptedMediaAnyVersion status=stable ExperimentalCanvasFeatures status=test ExperimentalContentSecurityPolicyFeatures status=experimental +FileConstructor status=experimental FileSystem status=stable FontLoadEvents status=experimental Fullscreen status=stable |