Title: [221839] trunk
Revision
221839
Author
wei...@apple.com
Date
2017-09-10 15:56:58 -0700 (Sun, 10 Sep 2017)

Log Message

Finish off the FormData implementation
https://bugs.webkit.org/show_bug.cgi?id=176659

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

* web-platform-tests/XMLHttpRequest/FormData-append-expected.txt:
* web-platform-tests/XMLHttpRequest/formdata-delete-expected.txt:
* web-platform-tests/XMLHttpRequest/formdata-foreach-expected.txt:
* web-platform-tests/XMLHttpRequest/formdata-get-expected.txt:
* web-platform-tests/XMLHttpRequest/formdata-has-expected.txt:
* web-platform-tests/XMLHttpRequest/formdata-set-expected.txt:
* web-platform-tests/XMLHttpRequest/interfaces-expected.txt:
        
    Update results.

Source/WebCore:

* fileapi/Blob.cpp:
* fileapi/Blob.h:
* fileapi/File.cpp:
* fileapi/File.h:

    Add constructors / create functions for making File objects
    from an existing Blob or File with an override name.

* html/DOMFormData.cpp:
* html/DOMFormData.h:

    Add missing operations and iterator implementation
    and bring append up to spec by no ignoring empty names.

* html/DOMFormData.idl:

    Bring IDL up to spec. Leave its exposure to just the window for
    now, as FormData currently depends on the Document/Page for replace
    file generation and therefore cannot operate in a worker.

* html/FormDataList.cpp:
* html/FormDataList.h:

    Changes FormDataList::Item to a String key and Variant<RefPtr<File>, String>
    data, matching spec concepts more cleanly. Normalization / encoding has also
    been made lazy, and now does not happen until creating a FormData from the
    FormDataList.

    Since we now store Files, rather than Blobs, we follow the spec's 'create an 
    entry' algorithm to convert Blobs into Files with the same backing bytes. This
    was previously done as part of FormData::appendKeyValuePairItems.

* html/HTMLKeygenElement.cpp:
(WebCore::HTMLKeygenElement::appendFormData):

    Remove unnecessary conversion to utf8, the data is base64 encoded, allowing
    us to remove an overload of appendData that took a CString.

* inspector/InspectorNetworkAgent.cpp:
(WebCore::buildObjectForResourceRequest):

    Update for new signature of FormData::flatten() which now
    returns a Vector, rather than takes one in.

* platform/network/FormData.h:
* platform/network/FormData.cpp:
(WebCore::FormData::FormData):
(WebCore::FormData::create):
(WebCore::FormData::createMultiPart):
        
    Cleanup redundancy by using auto.
        
(WebCore::FormData::appendKeyValuePairItems):
        
    Updated to handle new FormDataList item format (e.g. pairs of key / data) allowing
    us to remove two-by-two iteration. Some complexity was removed around Blobs, as
    FormDataList now always creates File. 

    Since FormDataList no longer eagerly encodes / normalizes the keys and string data
    values, we now perform those operations here.
        
(WebCore::FormData::expandDataStore):
(WebCore::appendBlobResolved):
(WebCore::FormData::resolveBlobReferences):
(WebCore::FormData::generateFiles):
(WebCore::FormData::hasGeneratedFiles const):
(WebCore::FormData::hasOwnedGeneratedFiles const):
(WebCore::FormData::removeGeneratedFilesIfNeeded):

    Adopt auto and modern for-in loops.

(WebCore::FormData::flatten const):
(WebCore::FormData::flattenToString const):

    Update flatten to return a Vector, rather than take it in.

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,3 +1,20 @@
+2017-09-09  Sam Weinig  <s...@webkit.org>
+
+        Finish off the FormData implementation
+        https://bugs.webkit.org/show_bug.cgi?id=176659
+
+        Reviewed by Darin Adler.
+
+        * web-platform-tests/XMLHttpRequest/FormData-append-expected.txt:
+        * web-platform-tests/XMLHttpRequest/formdata-delete-expected.txt:
+        * web-platform-tests/XMLHttpRequest/formdata-foreach-expected.txt:
+        * web-platform-tests/XMLHttpRequest/formdata-get-expected.txt:
+        * web-platform-tests/XMLHttpRequest/formdata-has-expected.txt:
+        * web-platform-tests/XMLHttpRequest/formdata-set-expected.txt:
+        * web-platform-tests/XMLHttpRequest/interfaces-expected.txt:
+        
+            Update results.
+
 2017-09-08  Antti Koivisto  <an...@apple.com>
 
         Remove support for >> descendant combinator syntax

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/FormData-append-expected.txt (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/FormData-append-expected.txt	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/FormData-append-expected.txt	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,16 +1,16 @@
 
 PASS Passing a String object to FormData.append should work. 
-FAIL testFormDataAppend1 create_formdata(['key', 'value1']).get is not a function. (In 'create_formdata(['key', 'value1']).get('key')', 'create_formdata(['key', 'value1']).get' is undefined)
-FAIL testFormDataAppend2 create_formdata(['key', 'value2'], ['key', 'value1']).get is not a function. (In 'create_formdata(['key', 'value2'], ['key', 'value1']).get('key')', 'create_formdata(['key', 'value2'], ['key', 'value1']).get' is undefined)
-FAIL testFormDataAppendUndefined1 create_formdata(['key', undefined]).get is not a function. (In 'create_formdata(['key', undefined]).get('key')', 'create_formdata(['key', undefined]).get' is undefined)
-FAIL testFormDataAppendUndefined2 create_formdata(['key', undefined], ['key', 'value1']).get is not a function. (In 'create_formdata(['key', undefined], ['key', 'value1']).get('key')', 'create_formdata(['key', undefined], ['key', 'value1']).get' is undefined)
-FAIL testFormDataAppendNull1 create_formdata(['key', null]).get is not a function. (In 'create_formdata(['key', null]).get('key')', 'create_formdata(['key', null]).get' is undefined)
-FAIL testFormDataAppendNull2 create_formdata(['key', null], ['key', 'value1']).get is not a function. (In 'create_formdata(['key', null], ['key', 'value1']).get('key')', 'create_formdata(['key', null], ['key', 'value1']).get' is undefined)
-FAIL testFormDataAppendToForm1 fd.get is not a function. (In 'fd.get('key')', 'fd.get' is undefined)
-FAIL testFormDataAppendToForm2 fd.get is not a function. (In 'fd.get('key')', 'fd.get' is undefined)
-FAIL testFormDataAppendToFormUndefined1 fd.get is not a function. (In 'fd.get('key')', 'fd.get' is undefined)
-FAIL testFormDataAppendToFormUndefined2 fd.get is not a function. (In 'fd.get('key')', 'fd.get' is undefined)
-FAIL testFormDataAppendToFormNull1 fd.get is not a function. (In 'fd.get('key')', 'fd.get' is undefined)
-FAIL testFormDataAppendToFormNull2 fd.get is not a function. (In 'fd.get('key')', 'fd.get' is undefined)
-FAIL testFormDataAppendEmptyBlob create_formdata(['key', new Blob(), 'blank.txt']).get is not a function. (In 'create_formdata(['key', new Blob(), 'blank.txt']).get('key')', 'create_formdata(['key', new Blob(), 'blank.txt']).get' is undefined)
+PASS testFormDataAppend1 
+PASS testFormDataAppend2 
+PASS testFormDataAppendUndefined1 
+PASS testFormDataAppendUndefined2 
+PASS testFormDataAppendNull1 
+PASS testFormDataAppendNull2 
+PASS testFormDataAppendToForm1 
+PASS testFormDataAppendToForm2 
+PASS testFormDataAppendToFormUndefined1 
+PASS testFormDataAppendToFormUndefined2 
+PASS testFormDataAppendToFormNull1 
+PASS testFormDataAppendToFormNull2 
+PASS testFormDataAppendEmptyBlob 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-delete-expected.txt (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-delete-expected.txt	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-delete-expected.txt	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,9 +1,9 @@
 
-FAIL testFormDataDelete fd.delete is not a function. (In 'fd.delete('key')', 'fd.delete' is undefined)
-FAIL testFormDataDeleteFromForm fd.delete is not a function. (In 'fd.delete('key')', 'fd.delete' is undefined)
-FAIL testFormDataDeleteFromFormNonExistentKey fd.delete is not a function. (In 'fd.delete('nil')', 'fd.delete' is undefined)
-FAIL testFormDataDeleteFromFormOtherKey fd.delete is not a function. (In 'fd.delete('key1')', 'fd.delete' is undefined)
-FAIL testFormDataDeleteFromEmptyForm fd.delete is not a function. (In 'fd.delete('key')', 'fd.delete' is undefined)
-FAIL testFormDataDeleteNonExistentKey fd.delete is not a function. (In 'fd.delete('nil')', 'fd.delete' is undefined)
-FAIL testFormDataDeleteOtherKey fd.delete is not a function. (In 'fd.delete('key1')', 'fd.delete' is undefined)
+PASS testFormDataDelete 
+PASS testFormDataDeleteFromForm 
+PASS testFormDataDeleteFromFormNonExistentKey 
+PASS testFormDataDeleteFromFormOtherKey 
+PASS testFormDataDeleteFromEmptyForm 
+PASS testFormDataDeleteNonExistentKey 
+PASS testFormDataDeleteOtherKey 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-foreach-expected.txt (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-foreach-expected.txt	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-foreach-expected.txt	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,4 +1,6 @@
-CONSOLE MESSAGE: line 16: TypeError: fd.delete is not a function. (In 'fd.delete('n2')', 'fd.delete' is undefined)
 
-FAIL FormData: foreach TypeError: fd.delete is not a function. (In 'fd.delete('n2')', 'fd.delete' is undefined)
+PASS Iterator should return duplicate keys and non-deleted values 
+PASS Entries iterator should return duplicate keys and non-deleted values 
+PASS Keys iterator should return duplicates 
+PASS Values iterator should return non-deleted values 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-get-expected.txt (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-get-expected.txt	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-get-expected.txt	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,14 +1,14 @@
 
-FAIL testFormDataGet create_formdata(['key', 'value1'], ['key', 'value2']).get is not a function. (In 'create_formdata(['key', 'value1'], ['key', 'value2']).get('key')', 'create_formdata(['key', 'value1'], ['key', 'value2']).get' is undefined)
-FAIL testFormDataGetFromForm new FormData(document.getElementById('form')).get is not a function. (In 'new FormData(document.getElementById('form')).get('key')', 'new FormData(document.getElementById('form')).get' is undefined)
-FAIL testFormDataGetFromFormNull new FormData(document.getElementById('form')).get is not a function. (In 'new FormData(document.getElementById('form')).get('nil')', 'new FormData(document.getElementById('form')).get' is undefined)
-FAIL testFormDataGetFromEmptyForm new FormData(document.getElementById('empty-form')).get is not a function. (In 'new FormData(document.getElementById('empty-form')).get('key')', 'new FormData(document.getElementById('empty-form')).get' is undefined)
-FAIL testFormDataGetNull1 create_formdata(['key', 'value1'], ['key', 'value2']).get is not a function. (In 'create_formdata(['key', 'value1'], ['key', 'value2']).get('nil')', 'create_formdata(['key', 'value1'], ['key', 'value2']).get' is undefined)
-FAIL testFormDataGetNull2 create_formdata().get is not a function. (In 'create_formdata().get('key')', 'create_formdata().get' is undefined)
-FAIL testFormDataGetAll create_formdata(['key', 'value1'], ['key', 'value2']).getAll is not a function. (In 'create_formdata(['key', 'value1'], ['key', 'value2']).getAll('key')', 'create_formdata(['key', 'value1'], ['key', 'value2']).getAll' is undefined)
-FAIL testFormDataGetAllEmpty1 create_formdata(['key', 'value1'], ['key', 'value2']).getAll is not a function. (In 'create_formdata(['key', 'value1'], ['key', 'value2']).getAll('nil')', 'create_formdata(['key', 'value1'], ['key', 'value2']).getAll' is undefined)
-FAIL testFormDataGetAllEmpty2 create_formdata().getAll is not a function. (In 'create_formdata().getAll('key')', 'create_formdata().getAll' is undefined)
-FAIL testFormDataGetAllFromForm new FormData(document.getElementById('form')).getAll is not a function. (In 'new FormData(document.getElementById('form')).getAll('key')', 'new FormData(document.getElementById('form')).getAll' is undefined)
-FAIL testFormDataGetAllFromFormNull new FormData(document.getElementById('form')).getAll is not a function. (In 'new FormData(document.getElementById('form')).getAll('nil')', 'new FormData(document.getElementById('form')).getAll' is undefined)
-FAIL testFormDataGetAllFromEmptyForm new FormData(document.getElementById('empty-form')).getAll is not a function. (In 'new FormData(document.getElementById('empty-form')).getAll('key')', 'new FormData(document.getElementById('empty-form')).getAll' is undefined)
+PASS testFormDataGet 
+PASS testFormDataGetFromForm 
+PASS testFormDataGetFromFormNull 
+PASS testFormDataGetFromEmptyForm 
+PASS testFormDataGetNull1 
+PASS testFormDataGetNull2 
+PASS testFormDataGetAll 
+PASS testFormDataGetAllEmpty1 
+PASS testFormDataGetAllEmpty2 
+PASS testFormDataGetAllFromForm 
+PASS testFormDataGetAllFromFormNull 
+PASS testFormDataGetAllFromEmptyForm 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-has-expected.txt (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-has-expected.txt	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-has-expected.txt	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,8 +1,8 @@
 
-FAIL testFormDataHas create_formdata(['key', 'value1'], ['key', 'value2']).has is not a function. (In 'create_formdata(['key', 'value1'], ['key', 'value2']).has('key')', 'create_formdata(['key', 'value1'], ['key', 'value2']).has' is undefined)
-FAIL testFormDataHasFromForm new FormData(document.getElementById('form')).has is not a function. (In 'new FormData(document.getElementById('form')).has('key')', 'new FormData(document.getElementById('form')).has' is undefined)
-FAIL testFormDataHasFromFormNull new FormData(document.getElementById('form')).has is not a function. (In 'new FormData(document.getElementById('form')).has('nil')', 'new FormData(document.getElementById('form')).has' is undefined)
-FAIL testFormDataHasFromEmptyForm new FormData(document.getElementById('empty-form')).has is not a function. (In 'new FormData(document.getElementById('empty-form')).has('key')', 'new FormData(document.getElementById('empty-form')).has' is undefined)
-FAIL testFormDataHasEmpty1 create_formdata(['key', 'value1'], ['key', 'value2']).has is not a function. (In 'create_formdata(['key', 'value1'], ['key', 'value2']).has('nil')', 'create_formdata(['key', 'value1'], ['key', 'value2']).has' is undefined)
-FAIL testFormDataHasEmpty2 create_formdata().has is not a function. (In 'create_formdata().has('key')', 'create_formdata().has' is undefined)
+PASS testFormDataHas 
+PASS testFormDataHasFromForm 
+PASS testFormDataHasFromFormNull 
+PASS testFormDataHasFromEmptyForm 
+PASS testFormDataHasEmpty1 
+PASS testFormDataHasEmpty2 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-set-expected.txt (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-set-expected.txt	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/formdata-set-expected.txt	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,16 +1,16 @@
 
-FAIL Passing a String object to FormData.set should work fd.set is not a function. (In 'fd.set("name", new String("value"))', 'fd.set' is undefined)
-FAIL testFormDataSet1 undefined is not an object (evaluating 'fd.set.apply')
-FAIL testFormDataSet2 undefined is not an object (evaluating 'fd.set.apply')
-FAIL testFormDataSetUndefined1 undefined is not an object (evaluating 'fd.set.apply')
-FAIL testFormDataSetUndefined2 undefined is not an object (evaluating 'fd.set.apply')
-FAIL testFormDataSetNull1 undefined is not an object (evaluating 'fd.set.apply')
-FAIL testFormDataSetNull2 undefined is not an object (evaluating 'fd.set.apply')
-FAIL testFormDataSetToForm1 fd.set is not a function. (In 'fd.set('key', 'value1')', 'fd.set' is undefined)
-FAIL testFormDataSetToForm2 fd.set is not a function. (In 'fd.set('key', 'value2')', 'fd.set' is undefined)
-FAIL testFormDataSetToFormUndefined1 fd.set is not a function. (In 'fd.set('key', undefined)', 'fd.set' is undefined)
-FAIL testFormDataSetToFormUndefined2 fd.set is not a function. (In 'fd.set('key', undefined)', 'fd.set' is undefined)
-FAIL testFormDataSetToFormNull1 fd.set is not a function. (In 'fd.set('key', null)', 'fd.set' is undefined)
-FAIL testFormDataSetToFormNull2 fd.set is not a function. (In 'fd.set('key', null)', 'fd.set' is undefined)
-FAIL testFormDataSetEmptyBlob fd.set is not a function. (In 'fd.set('key', new Blob([]), 'blank.txt')', 'fd.set' is undefined)
+PASS Passing a String object to FormData.set should work 
+PASS testFormDataSet1 
+PASS testFormDataSet2 
+PASS testFormDataSetUndefined1 
+PASS testFormDataSetUndefined2 
+PASS testFormDataSetNull1 
+PASS testFormDataSetNull2 
+PASS testFormDataSetToForm1 
+PASS testFormDataSetToForm2 
+PASS testFormDataSetToFormUndefined1 
+PASS testFormDataSetToFormUndefined2 
+PASS testFormDataSetToFormNull1 
+PASS testFormDataSetToFormNull2 
+PASS testFormDataSetEmptyBlob 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/interfaces-expected.txt (221838 => 221839)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/interfaces-expected.txt	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/XMLHttpRequest/interfaces-expected.txt	2017-09-10 22:56:58 UTC (rev 221839)
@@ -108,44 +108,44 @@
 PASS FormData interface: existence and properties of interface prototype object's "constructor" property 
 PASS FormData interface: operation append(USVString,Blob,USVString) 
 PASS FormData interface: operation append(USVString,USVString) 
-FAIL FormData interface: operation delete(USVString) assert_own_property: interface prototype object missing non-static operation expected property "delete" missing
-FAIL FormData interface: operation get(USVString) assert_own_property: interface prototype object missing non-static operation expected property "get" missing
-FAIL FormData interface: operation getAll(USVString) assert_own_property: interface prototype object missing non-static operation expected property "getAll" missing
-FAIL FormData interface: operation has(USVString) assert_own_property: interface prototype object missing non-static operation expected property "has" missing
-FAIL FormData interface: operation set(USVString,Blob,USVString) assert_own_property: interface prototype object missing non-static operation expected property "set" missing
-FAIL FormData interface: operation set(USVString,USVString) assert_own_property: interface prototype object missing non-static operation expected property "set" missing
+PASS FormData interface: operation delete(USVString) 
+PASS FormData interface: operation get(USVString) 
+PASS FormData interface: operation getAll(USVString) 
+PASS FormData interface: operation has(USVString) 
+PASS FormData interface: operation set(USVString,Blob,USVString) 
+PASS FormData interface: operation set(USVString,USVString) 
 PASS FormData interface: new FormData() must inherit property "append" with the proper type (0) 
 PASS FormData interface: calling append(USVString,Blob,USVString) on new FormData() with too few arguments must throw TypeError 
 PASS FormData interface: new FormData() must inherit property "append" with the proper type (1) 
 PASS FormData interface: calling append(USVString,USVString) on new FormData() with too few arguments must throw TypeError 
-FAIL FormData interface: new FormData() must inherit property "delete" with the proper type (2) assert_inherits: property "delete" not found in prototype chain
-FAIL FormData interface: calling delete(USVString) on new FormData() with too few arguments must throw TypeError assert_inherits: property "delete" not found in prototype chain
-FAIL FormData interface: new FormData() must inherit property "get" with the proper type (3) assert_inherits: property "get" not found in prototype chain
-FAIL FormData interface: calling get(USVString) on new FormData() with too few arguments must throw TypeError assert_inherits: property "get" not found in prototype chain
-FAIL FormData interface: new FormData() must inherit property "getAll" with the proper type (4) assert_inherits: property "getAll" not found in prototype chain
-FAIL FormData interface: calling getAll(USVString) on new FormData() with too few arguments must throw TypeError assert_inherits: property "getAll" not found in prototype chain
-FAIL FormData interface: new FormData() must inherit property "has" with the proper type (5) assert_inherits: property "has" not found in prototype chain
-FAIL FormData interface: calling has(USVString) on new FormData() with too few arguments must throw TypeError assert_inherits: property "has" not found in prototype chain
-FAIL FormData interface: new FormData() must inherit property "set" with the proper type (6) assert_inherits: property "set" not found in prototype chain
-FAIL FormData interface: calling set(USVString,Blob,USVString) on new FormData() with too few arguments must throw TypeError assert_inherits: property "set" not found in prototype chain
-FAIL FormData interface: new FormData() must inherit property "set" with the proper type (7) assert_inherits: property "set" not found in prototype chain
-FAIL FormData interface: calling set(USVString,USVString) on new FormData() with too few arguments must throw TypeError assert_inherits: property "set" not found in prototype chain
+PASS FormData interface: new FormData() must inherit property "delete" with the proper type (2) 
+PASS FormData interface: calling delete(USVString) on new FormData() with too few arguments must throw TypeError 
+PASS FormData interface: new FormData() must inherit property "get" with the proper type (3) 
+PASS FormData interface: calling get(USVString) on new FormData() with too few arguments must throw TypeError 
+PASS FormData interface: new FormData() must inherit property "getAll" with the proper type (4) 
+PASS FormData interface: calling getAll(USVString) on new FormData() with too few arguments must throw TypeError 
+PASS FormData interface: new FormData() must inherit property "has" with the proper type (5) 
+PASS FormData interface: calling has(USVString) on new FormData() with too few arguments must throw TypeError 
+PASS FormData interface: new FormData() must inherit property "set" with the proper type (6) 
+PASS FormData interface: calling set(USVString,Blob,USVString) on new FormData() with too few arguments must throw TypeError 
+PASS FormData interface: new FormData() must inherit property "set" with the proper type (7) 
+PASS FormData interface: calling set(USVString,USVString) on new FormData() with too few arguments must throw TypeError 
 PASS FormData interface: new FormData(form) must inherit property "append" with the proper type (0) 
 PASS FormData interface: calling append(USVString,Blob,USVString) on new FormData(form) with too few arguments must throw TypeError 
 PASS FormData interface: new FormData(form) must inherit property "append" with the proper type (1) 
 PASS FormData interface: calling append(USVString,USVString) on new FormData(form) with too few arguments must throw TypeError 
-FAIL FormData interface: new FormData(form) must inherit property "delete" with the proper type (2) assert_inherits: property "delete" not found in prototype chain
-FAIL FormData interface: calling delete(USVString) on new FormData(form) with too few arguments must throw TypeError assert_inherits: property "delete" not found in prototype chain
-FAIL FormData interface: new FormData(form) must inherit property "get" with the proper type (3) assert_inherits: property "get" not found in prototype chain
-FAIL FormData interface: calling get(USVString) on new FormData(form) with too few arguments must throw TypeError assert_inherits: property "get" not found in prototype chain
-FAIL FormData interface: new FormData(form) must inherit property "getAll" with the proper type (4) assert_inherits: property "getAll" not found in prototype chain
-FAIL FormData interface: calling getAll(USVString) on new FormData(form) with too few arguments must throw TypeError assert_inherits: property "getAll" not found in prototype chain
-FAIL FormData interface: new FormData(form) must inherit property "has" with the proper type (5) assert_inherits: property "has" not found in prototype chain
-FAIL FormData interface: calling has(USVString) on new FormData(form) with too few arguments must throw TypeError assert_inherits: property "has" not found in prototype chain
-FAIL FormData interface: new FormData(form) must inherit property "set" with the proper type (6) assert_inherits: property "set" not found in prototype chain
-FAIL FormData interface: calling set(USVString,Blob,USVString) on new FormData(form) with too few arguments must throw TypeError assert_inherits: property "set" not found in prototype chain
-FAIL FormData interface: new FormData(form) must inherit property "set" with the proper type (7) assert_inherits: property "set" not found in prototype chain
-FAIL FormData interface: calling set(USVString,USVString) on new FormData(form) with too few arguments must throw TypeError assert_inherits: property "set" not found in prototype chain
+PASS FormData interface: new FormData(form) must inherit property "delete" with the proper type (2) 
+PASS FormData interface: calling delete(USVString) on new FormData(form) with too few arguments must throw TypeError 
+PASS FormData interface: new FormData(form) must inherit property "get" with the proper type (3) 
+PASS FormData interface: calling get(USVString) on new FormData(form) with too few arguments must throw TypeError 
+PASS FormData interface: new FormData(form) must inherit property "getAll" with the proper type (4) 
+PASS FormData interface: calling getAll(USVString) on new FormData(form) with too few arguments must throw TypeError 
+PASS FormData interface: new FormData(form) must inherit property "has" with the proper type (5) 
+PASS FormData interface: calling has(USVString) on new FormData(form) with too few arguments must throw TypeError 
+PASS FormData interface: new FormData(form) must inherit property "set" with the proper type (6) 
+PASS FormData interface: calling set(USVString,Blob,USVString) on new FormData(form) with too few arguments must throw TypeError 
+PASS FormData interface: new FormData(form) must inherit property "set" with the proper type (7) 
+PASS FormData interface: calling set(USVString,USVString) on new FormData(form) with too few arguments must throw TypeError 
 PASS ProgressEvent interface: existence and properties of interface object 
 PASS ProgressEvent interface object length 
 PASS ProgressEvent interface object name 

Modified: trunk/Source/WebCore/ChangeLog (221838 => 221839)


--- trunk/Source/WebCore/ChangeLog	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/ChangeLog	2017-09-10 22:56:58 UTC (rev 221839)
@@ -1,3 +1,86 @@
+2017-09-09  Sam Weinig  <s...@webkit.org>
+
+        Finish off the FormData implementation
+        https://bugs.webkit.org/show_bug.cgi?id=176659
+
+        Reviewed by Darin Adler.
+
+        * fileapi/Blob.cpp:
+        * fileapi/Blob.h:
+        * fileapi/File.cpp:
+        * fileapi/File.h:
+
+            Add constructors / create functions for making File objects
+            from an existing Blob or File with an override name.
+
+        * html/DOMFormData.cpp:
+        * html/DOMFormData.h:
+
+            Add missing operations and iterator implementation
+            and bring append up to spec by no ignoring empty names.
+
+        * html/DOMFormData.idl:
+
+            Bring IDL up to spec. Leave its exposure to just the window for
+            now, as FormData currently depends on the Document/Page for replace
+            file generation and therefore cannot operate in a worker.
+
+        * html/FormDataList.cpp:
+        * html/FormDataList.h:
+
+            Changes FormDataList::Item to a String key and Variant<RefPtr<File>, String>
+            data, matching spec concepts more cleanly. Normalization / encoding has also
+            been made lazy, and now does not happen until creating a FormData from the
+            FormDataList.
+
+            Since we now store Files, rather than Blobs, we follow the spec's 'create an 
+            entry' algorithm to convert Blobs into Files with the same backing bytes. This
+            was previously done as part of FormData::appendKeyValuePairItems.
+
+        * html/HTMLKeygenElement.cpp:
+        (WebCore::HTMLKeygenElement::appendFormData):
+
+            Remove unnecessary conversion to utf8, the data is base64 encoded, allowing
+            us to remove an overload of appendData that took a CString.
+
+        * inspector/InspectorNetworkAgent.cpp:
+        (WebCore::buildObjectForResourceRequest):
+
+            Update for new signature of FormData::flatten() which now
+            returns a Vector, rather than takes one in.
+
+        * platform/network/FormData.h:
+        * platform/network/FormData.cpp:
+        (WebCore::FormData::FormData):
+        (WebCore::FormData::create):
+        (WebCore::FormData::createMultiPart):
+        
+            Cleanup redundancy by using auto.
+        
+        (WebCore::FormData::appendKeyValuePairItems):
+        
+            Updated to handle new FormDataList item format (e.g. pairs of key / data) allowing
+            us to remove two-by-two iteration. Some complexity was removed around Blobs, as
+            FormDataList now always creates File. 
+
+            Since FormDataList no longer eagerly encodes / normalizes the keys and string data
+            values, we now perform those operations here.
+        
+        (WebCore::FormData::expandDataStore):
+        (WebCore::appendBlobResolved):
+        (WebCore::FormData::resolveBlobReferences):
+        (WebCore::FormData::generateFiles):
+        (WebCore::FormData::hasGeneratedFiles const):
+        (WebCore::FormData::hasOwnedGeneratedFiles const):
+        (WebCore::FormData::removeGeneratedFilesIfNeeded):
+
+            Adopt auto and modern for-in loops.
+
+        (WebCore::FormData::flatten const):
+        (WebCore::FormData::flattenToString const):
+
+            Update flatten to return a Vector, rather than take it in.
+
 2017-09-10  Darin Adler  <da...@apple.com>
 
         Refactor Document::updateTitleElement to use traits instead of function pointers

Modified: trunk/Source/WebCore/fileapi/Blob.cpp (221838 => 221839)


--- trunk/Source/WebCore/fileapi/Blob.cpp	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/fileapi/Blob.cpp	2017-09-10 22:56:58 UTC (rev 221839)
@@ -79,6 +79,14 @@
     ThreadableBlobRegistry::registerBlobURL(m_internalURL, { },  { });
 }
 
+Blob::Blob(const Blob& blob)
+    : m_internalURL(BlobURL::createInternalURL())
+    , m_type(blob.type())
+    , m_size(blob.size())
+{
+    ThreadableBlobRegistry::registerBlobURL(m_internalURL, { BlobPart(blob.url()) } , m_type);
+}
+
 Blob::Blob(Vector<BlobPartVariant>&& blobPartVariants, const BlobPropertyBag& propertyBag)
     : m_internalURL(BlobURL::createInternalURL())
     , m_type(normalizedContentType(propertyBag.type))

Modified: trunk/Source/WebCore/fileapi/Blob.h (221838 => 221839)


--- trunk/Source/WebCore/fileapi/Blob.h	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/fileapi/Blob.h	2017-09-10 22:56:58 UTC (rev 221839)
@@ -98,6 +98,7 @@
 
 protected:
     Blob();
+    Blob(const Blob&);
     Blob(Vector<BlobPartVariant>&&, const BlobPropertyBag&);
     Blob(Vector<uint8_t>&&, const String& contentType);
 

Modified: trunk/Source/WebCore/fileapi/File.cpp (221838 => 221839)


--- trunk/Source/WebCore/fileapi/File.cpp	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/fileapi/File.cpp	2017-09-10 22:56:58 UTC (rev 221839)
@@ -85,6 +85,23 @@
 {
 }
 
+File::File(const Blob& blob, const String& name)
+    : Blob(blob)
+    , m_name(name)
+{
+    ASSERT(!blob.isFile());
+}
+
+File::File(const File& file, const String& name)
+    : Blob(file)
+    , m_path(file.path())
+    , m_relativePath(file.relativePath())
+    , m_name(!name.isNull() ? name : file.name())
+    , m_overrideLastModifiedDate(file.m_overrideLastModifiedDate)
+    , m_isDirectory(file.isDirectory())
+{
+}
+
 double File::lastModified() const
 {
     if (m_overrideLastModifiedDate)

Modified: trunk/Source/WebCore/fileapi/File.h (221838 => 221839)


--- trunk/Source/WebCore/fileapi/File.h	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/fileapi/File.h	2017-09-10 22:56:58 UTC (rev 221839)
@@ -65,6 +65,16 @@
         return adoptRef(*new File(path, nameOverride));
     }
 
+    static Ref<File> create(const Blob& blob, const String& name)
+    {
+        return adoptRef(*new File(blob, name));
+    }
+
+    static Ref<File> create(const File& file, const String& name)
+    {
+        return adoptRef(*new File(file, name));
+    }
+
     static Ref<File> createWithRelativePath(const String& path, const String& relativePath);
 
     bool isFile() const override { return true; }
@@ -87,6 +97,8 @@
     WEBCORE_EXPORT explicit File(const String& path);
     File(const String& path, const String& nameOverride);
     File(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag&);
+    File(const Blob&, const String& name);
+    File(const File&, const String& name);
 
     File(DeserializationContructor, const String& path, const URL& srcURL, const String& type, const String& name);
 

Modified: trunk/Source/WebCore/html/DOMFormData.cpp (221838 => 221839)


--- trunk/Source/WebCore/html/DOMFormData.cpp	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/html/DOMFormData.cpp	2017-09-10 22:56:58 UTC (rev 221839)
@@ -55,14 +55,76 @@
 
 void DOMFormData::append(const String& name, const String& value)
 {
-    if (!name.isEmpty())
-        appendData(name, value);
+    appendData(name, value);
 }
 
 void DOMFormData::append(const String& name, Blob& blob, const String& filename)
 {
-    if (!name.isEmpty())
-        appendBlob(name, blob, filename);
+    appendBlob(name, blob, filename);
 }
 
+void DOMFormData::remove(const String& name)
+{
+    m_items.removeAllMatching([&name] (const auto& item) {
+        return item.name == name;
+    });
+}
+
+auto DOMFormData::get(const String& name) -> std::optional<FormDataEntryValue>
+{
+    for (auto& item : m_items) {
+        if (item.name == name)
+            return item.data;
+    }
+
+    return std::nullopt;
+}
+
+auto DOMFormData::getAll(const String& name) -> Vector<FormDataEntryValue>
+{
+    Vector<FormDataEntryValue> result;
+
+    for (auto& item : m_items) {
+        if (item.name == name)
+            result.append(item.data);
+    }
+
+    return result;
+}
+
+bool DOMFormData::has(const String& name)
+{
+    for (auto& item : m_items) {
+        if (item.name == name)
+            return true;
+    }
+    
+    return false;
+}
+
+void DOMFormData::set(const String& name, const String& value)
+{
+    setData(name, value);
+}
+
+void DOMFormData::set(const String& name, Blob& blob, const String& filename)
+{
+    setBlob(name, blob, filename);
+}
+
+DOMFormData::Iterator::Iterator(DOMFormData& target)
+    : m_target(target)
+{
+}
+
+std::optional<WTF::KeyValuePair<String, DOMFormData::FormDataEntryValue>> DOMFormData::Iterator::next()
+{
+    auto& items = m_target->items();
+    if (m_index >= items.size())
+        return std::nullopt;
+
+    auto& item = items[m_index++];
+    return WTF::KeyValuePair<String, FormDataEntryValue> { item.name, item.data };
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/DOMFormData.h (221838 => 221839)


--- trunk/Source/WebCore/html/DOMFormData.h	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/html/DOMFormData.h	2017-09-10 22:56:58 UTC (rev 221839)
@@ -32,6 +32,7 @@
 
 #include "FormDataList.h"
 #include <wtf/Forward.h>
+#include <wtf/Optional.h>
 #include <wtf/RefCounted.h>
 
 namespace WebCore {
@@ -40,14 +41,34 @@
 class HTMLFormElement;
 class TextEncoding;
 
+// FIXME: Do we need to have separate DOMFormData and FormDataList classes?
 class DOMFormData : public FormDataList, public RefCounted<DOMFormData> {
 public:
     static Ref<DOMFormData> create(HTMLFormElement* form) { return adoptRef(*new DOMFormData(form)); }
     static Ref<DOMFormData> create(const TextEncoding& encoding) { return adoptRef(*new DOMFormData(encoding)); }
 
+    using FormDataEntryValue = Item::Data;
+
     void append(const String& name, const String& value);
-    void append(const String& name, Blob&, const String& filename = String());
+    void append(const String& name, Blob&, const String& filename = { });
+    void remove(const String& name);
+    std::optional<FormDataEntryValue> get(const String& name);
+    Vector<FormDataEntryValue> getAll(const String& name);
+    bool has(const String& name);
+    void set(const String& name, const String& value);
+    void set(const String& name, Blob&, const String& filename = { });
 
+    class Iterator {
+    public:
+        explicit Iterator(DOMFormData&);
+        std::optional<WTF::KeyValuePair<String, FormDataEntryValue>> next();
+
+    private:
+        Ref<DOMFormData> m_target;
+        size_t m_index { 0 };
+    };
+    Iterator createIterator() { return Iterator { *this }; }
+
 private:
     explicit DOMFormData(const TextEncoding&);
     explicit DOMFormData(HTMLFormElement*);

Modified: trunk/Source/WebCore/html/DOMFormData.idl (221838 => 221839)


--- trunk/Source/WebCore/html/DOMFormData.idl	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/html/DOMFormData.idl	2017-09-10 22:56:58 UTC (rev 221839)
@@ -28,6 +28,12 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+typedef (File or USVString) FormDataEntryValue;
+
+// FIXME: Should be Exposed=(Window,Worker) It is not currently possible to do this due to
+// Fetch and XMLHttpRequest expecting to have Document when processing DOMFormData to perform
+// file replacement (https://webkit.org/b/176674).
+
 [
     Constructor(optional HTMLFormElement? form),
     JSGenerateToNativeObject,
@@ -36,6 +42,13 @@
     ImplementationLacksVTable,
 ] interface DOMFormData {
     void append(USVString name, USVString value);
-    void append(USVString name, Blob value, optional USVString filename);
+    void append(USVString name, Blob blobValue, optional USVString filename);
+    [ImplementedAs=remove] void delete(USVString name);
+    FormDataEntryValue? get(USVString name);
+    sequence<FormDataEntryValue> getAll(USVString name);
+    boolean has(USVString name);
+    void set(USVString name, USVString value);
+    void set(USVString name, Blob blobValue, optional USVString filename);
+
+    iterable<USVString, FormDataEntryValue>;
 };
-

Modified: trunk/Source/WebCore/html/FormDataList.cpp (221838 => 221839)


--- trunk/Source/WebCore/html/FormDataList.cpp	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/html/FormDataList.cpp	2017-09-10 22:56:58 UTC (rev 221839)
@@ -22,29 +22,79 @@
 #include "FormDataList.h"
 
 #include "LineEnding.h"
-#include <wtf/text/StringView.h>
+#include <wtf/text/CString.h>
 
 namespace WebCore {
 
-FormDataList::FormDataList(const TextEncoding& c)
-    : m_encoding(c)
+FormDataList::FormDataList(const TextEncoding& encoding)
+    : m_encoding(encoding)
 {
 }
 
-void FormDataList::appendString(const String& s)
+CString FormDataList::normalizeString(const String& value) const
 {
-    CString cstr = m_encoding.encode(s, EntitiesForUnencodables);
-    m_items.append(normalizeLineEndingsToCRLF(cstr));
+    return normalizeLineEndingsToCRLF(m_encoding.encode(value, EntitiesForUnencodables));
 }
 
-void FormDataList::appendString(const CString& s)
+// https://xhr.spec.whatwg.org/#create-an-entry
+auto FormDataList::createFileEntry(const String& name, Ref<Blob>&& blob, const String& filename) -> Item
 {
-    m_items.append(s);
+    if (!blob->isFile())
+        return { name, File::create(blob.get(), filename.isNull() ? ASCIILiteral("blob") : filename) };
+    
+    if (!filename.isNull())
+        return { name, File::create(downcast<File>(blob.get()), filename) };
+
+    return { name, static_reference_cast<File>(WTFMove(blob)) };
 }
 
-void FormDataList::appendBlob(Ref<Blob>&& blob, const String& filename)
+void FormDataList::appendData(const String& name, const String& value)
 {
-    m_items.append(Item(WTFMove(blob), filename));
+    m_items.append({ name, value });
 }
 
-} // namespace
+void FormDataList::appendData(const String& name, int value)
+{
+    m_items.append({ name, String::number(value) });
+}
+
+void FormDataList::appendBlob(const String& name, Ref<Blob>&& blob, const String& filename)
+{
+    m_items.append(createFileEntry(name, WTFMove(blob), filename));
+}
+
+void FormDataList::set(const String& name, Item&& item)
+{
+    std::optional<size_t> initialMatchLocation;
+
+    // Find location of the first item with a matching name.
+    for (size_t i = 0; i < m_items.size(); ++i) {
+        if (name == m_items[i].name) {
+            initialMatchLocation = i;
+            break;
+        }
+    }
+
+    if (initialMatchLocation) {
+        m_items[*initialMatchLocation] = WTFMove(item);
+
+        m_items.removeAllMatching([&name] (const auto& item) {
+            return item.name == name;
+        }, *initialMatchLocation + 1);
+        return;
+    }
+
+    m_items.append(WTFMove(item));
+}
+
+void FormDataList::setData(const String& name, const String& value)
+{
+    set(name, { name, value });
+}
+
+void FormDataList::setBlob(const String& name, Ref<Blob>&& blob, const String& filename)
+{
+    set(name, createFileEntry(name, WTFMove(blob), filename));
+}
+
+}

Modified: trunk/Source/WebCore/html/FormDataList.h (221838 => 221839)


--- trunk/Source/WebCore/html/FormDataList.h	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/html/FormDataList.h	2017-09-10 22:56:58 UTC (rev 221839)
@@ -20,65 +20,39 @@
 
 #pragma once
 
-#include "Blob.h"
+#include "File.h"
 #include "TextEncoding.h"
 #include <wtf/Forward.h>
-#include <wtf/text/CString.h>
+#include <wtf/Variant.h>
 
 namespace WebCore {
 
 class FormDataList {
 public:
-    class Item {
-    public:
-        Item() { }
-        Item(const WTF::CString& data) : m_data(data) { }
-        Item(Ref<Blob>&& blob, const String& filename)
-            : m_blob(WTFMove(blob))
-            , m_filename(filename)
-        { }
+    struct Item {
+        using Data = "" String>;
 
-        const WTF::CString& data() const { return m_data; }
-        Blob* blob() const { return m_blob.get(); }
-        const String& filename() const { return m_filename; }
-
-    private:
-        WTF::CString m_data;
-        RefPtr<Blob> m_blob;
-        String m_filename;
+        String name;
+        Data data;
     };
 
-    FormDataList(const TextEncoding&);
+    void appendData(const String& name, const String& value);
+    void appendData(const String& name, int value);
+    void appendBlob(const String& name, Ref<Blob>&&, const String& filename = { });
+    void setData(const String& name, const String& value);
+    void setBlob(const String& name, Ref<Blob>&&, const String& filename = { });
 
-    void appendData(const String& key, const String& value)
-    {
-        appendString(key);
-        appendString(value);
-    }
-    void appendData(const String& key, const CString& value)
-    {
-        appendString(key);
-        appendString(value);
-    }
-    void appendData(const String& key, int value)
-    {
-        appendString(key);
-        appendString(String::number(value));
-    }
-    void appendBlob(const String& key, Ref<Blob>&& blob, const String& filename = String())
-    {
-        appendString(key);
-        appendBlob(WTFMove(blob), filename);
-    }
-
     const Vector<Item>& items() const { return m_items; }
     const TextEncoding& encoding() const { return m_encoding; }
 
-private:
-    void appendString(const CString&);
-    void appendString(const String&);
-    void appendBlob(Ref<Blob>&&, const String& filename);
+    CString normalizeString(const String&) const;
 
+protected:
+    FormDataList(const TextEncoding&);
+
+    Item createFileEntry(const String& name, Ref<Blob>&&, const String& filename);
+    void set(const String& name, Item&&);
+
     TextEncoding m_encoding;
     Vector<Item> m_items;
 };

Modified: trunk/Source/WebCore/html/HTMLKeygenElement.cpp (221838 => 221839)


--- trunk/Source/WebCore/html/HTMLKeygenElement.cpp	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/html/HTMLKeygenElement.cpp	2017-09-10 22:56:58 UTC (rev 221839)
@@ -123,7 +123,7 @@
     String value = signedPublicKeyAndChallengeString(shadowSelect()->selectedIndex(), attributeWithoutSynchronization(challengeAttr), document().baseURL());
     if (value.isNull())
         return false;
-    encoded_values.appendData(name(), value.utf8());
+    encoded_values.appendData(name(), value);
     return true;
 }
 

Modified: trunk/Source/WebCore/inspector/InspectorNetworkAgent.cpp (221838 => 221839)


--- trunk/Source/WebCore/inspector/InspectorNetworkAgent.cpp	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/inspector/InspectorNetworkAgent.cpp	2017-09-10 22:56:58 UTC (rev 221839)
@@ -256,8 +256,7 @@
         .setHeaders(buildObjectForHeaders(request.httpHeaderFields()))
         .release();
     if (request.httpBody() && !request.httpBody()->isEmpty()) {
-        Vector<char> bytes;
-        request.httpBody()->flatten(bytes);
+        auto bytes = request.httpBody()->flatten();
         requestObject->setPostData(String::fromUTF8WithLatin1Fallback(bytes.data(), bytes.size()));
     }
     return requestObject;

Modified: trunk/Source/WebCore/platform/network/FormData.cpp (221838 => 221839)


--- trunk/Source/WebCore/platform/network/FormData.cpp	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/platform/network/FormData.cpp	2017-09-10 22:56:58 UTC (rev 221839)
@@ -50,7 +50,7 @@
 {
     // We shouldn't be copying FormData that hasn't already removed its generated files
     // but just in case, make sure the new FormData is ready to generate its own files.
-    for (FormDataElement& element : m_elements) {
+    for (auto& element : m_elements) {
         if (element.m_type == FormDataElement::Type::EncodedFile) {
             element.m_generatedFilename = String();
             element.m_ownsGeneratedFile = false;
@@ -73,7 +73,7 @@
 
 Ref<FormData> FormData::create(const void* data, size_t size)
 {
-    Ref<FormData> result = create();
+    auto result = create();
     result->appendData(data, size);
     return result;
 }
@@ -80,7 +80,7 @@
 
 Ref<FormData> FormData::create(const CString& string)
 {
-    Ref<FormData> result = create();
+    auto result = create();
     result->appendData(string.data(), string.length());
     return result;
 }
@@ -87,7 +87,7 @@
 
 Ref<FormData> FormData::create(const Vector<char>& vector)
 {
-    Ref<FormData> result = create();
+    auto result = create();
     result->appendData(vector.data(), vector.size());
     return result;
 }
@@ -94,14 +94,14 @@
 
 Ref<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding, EncodingType encodingType)
 {
-    Ref<FormData> result = create();
-    result->appendKeyValuePairItems(list, encoding, false, 0, encodingType);
+    auto result = create();
+    result->appendKeyValuePairItems(list, encoding, false, nullptr, encodingType);
     return result;
 }
 
 Ref<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
 {
-    Ref<FormData> result = create();
+    auto result = create();
     result->appendKeyValuePairItems(list, encoding, true, document);
     return result;
 }
@@ -188,45 +188,29 @@
         m_boundary = FormDataBuilder::generateUniqueBoundaryString();
 
     Vector<char> encodedData;
-
-    const Vector<FormDataList::Item>& items = list.items();
-    size_t formDataListSize = items.size();
-    ASSERT(!(formDataListSize % 2));
-    for (size_t i = 0; i < formDataListSize; i += 2) {
-        const FormDataList::Item& key = items[i];
-        const FormDataList::Item& value = items[i + 1];
+    for (const auto& item : list.items()) {
+        auto normalizedName = list.normalizeString(item.name);
+    
         if (isMultiPartForm) {
             Vector<char> header;
-            FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data());
+            FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), normalizedName);
 
             bool shouldGenerateFile = false;
 
-            // If the current type is blob, then we also need to include the filename
-            if (value.blob()) {
-                String name;
-                if (is<File>(*value.blob())) {
-                    File& file = downcast<File>(*value.blob());
-                    name = file.name();
-                    // Let the application specify a filename if it's going to generate a replacement file for the upload.
-                    const String& path = file.path();
-                    if (!path.isEmpty()) {
-                        if (Page* page = document->page()) {
-                            String generatedFileName;
-                            shouldGenerateFile = page->chrome().client().shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
-                            if (shouldGenerateFile)
-                                name = generatedFileName;
-                        }
+            if (WTF::holds_alternative<RefPtr<File>>(item.data)) {
+                // If the current type is a file, then we also need to include the filename
+                auto& file = *WTF::get<RefPtr<File>>(item.data);
+                auto name = file.name();
+
+                // Let the application specify a filename if it's going to generate a replacement file for the upload.
+                const auto& path = file.path();
+                if (!path.isEmpty()) {
+                    if (Page* page = document->page()) {
+                        String generatedFileName;
+                        shouldGenerateFile = page->chrome().client().shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
+                        if (shouldGenerateFile)
+                            name = generatedFileName;
                     }
-
-                    // If a filename is passed in FormData.append(), use it instead of the file blob's name.
-                    if (!value.filename().isNull())
-                        name = value.filename();
-                } else {
-                    // For non-file blob, use the filename if it is passed in FormData.append().
-                    if (!value.filename().isNull())
-                        name = value.filename();
-                    else
-                        name = "blob";
                 }
 
                 // We have to include the filename=".." part in the header, even if the filename is empty
@@ -233,7 +217,7 @@
                 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
 
                 // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867).
-                String contentType = value.blob()->type();
+                auto contentType = file.type();
                 if (contentType.isEmpty())
                     contentType = "application/octet-stream";
                 ASSERT(Blob::isNormalizedContentType(contentType));
@@ -242,22 +226,26 @@
 
             FormDataBuilder::finishMultiPartHeader(header);
 
-            // Append body
             appendData(header.data(), header.size());
-            if (value.blob()) {
-                if (is<File>(*value.blob())) {
-                    File& file = downcast<File>(*value.blob());
-                    // Do not add the file if the path is empty.
-                    if (!file.path().isEmpty())
-                        appendFile(file.path(), shouldGenerateFile);
-                }
+
+            if (WTF::holds_alternative<RefPtr<File>>(item.data)) {
+                auto& file = *WTF::get<RefPtr<File>>(item.data);
+                if (!file.path().isEmpty())
+                    appendFile(file.path(), shouldGenerateFile);
                 else
-                    appendBlob(value.blob()->url());
-            } else
-                appendData(value.data().data(), value.data().length());
+                    appendBlob(file.url());
+            } else {
+                auto normalizedStringData = list.normalizeString(WTF::get<String>(item.data));
+                appendData(normalizedStringData.data(), normalizedStringData.length());
+            }
+
             appendData("\r\n", 2);
-        } else
-            FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType);
+        } else {
+            ASSERT(WTF::holds_alternative<String>(item.data));
+
+            auto normalizedStringData = list.normalizeString(WTF::get<String>(item.data));
+            FormDataBuilder::addKeyValuePairAsFormData(encodedData, normalizedName, normalizedStringData, encodingType);
+        }
     }
 
     if (isMultiPartForm)
@@ -270,29 +258,31 @@
 {
     m_lengthInBytes = std::nullopt;
     if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::Type::Data)
-        m_elements.append(FormDataElement());
-    FormDataElement& e = m_elements.last();
-    size_t oldSize = e.m_data.size();
-    e.m_data.grow(oldSize + size);
-    return e.m_data.data() + oldSize;
+        m_elements.append({ });
+
+    auto& lastElement = m_elements.last();
+    size_t oldSize = lastElement.m_data.size();
+
+    auto newSize = Checked<size_t>(oldSize) + size;
+
+    lastElement.m_data.grow(newSize.unsafeGet());
+    return lastElement.m_data.data() + oldSize;
 }
 
-void FormData::flatten(Vector<char>& data) const
+Vector<char> FormData::flatten() const
 {
     // Concatenate all the byte arrays, but omit any files.
-    data.clear();
-    size_t n = m_elements.size();
-    for (size_t i = 0; i < n; ++i) {
-        const FormDataElement& e = m_elements[i];
-        if (e.m_type == FormDataElement::Type::Data)
-            data.append(e.m_data.data(), static_cast<size_t>(e.m_data.size()));
+    Vector<char> data;
+    for (auto& element : m_elements) {
+        if (element.m_type == FormDataElement::Type::Data)
+            data.append(element.m_data.data(), static_cast<size_t>(element.m_data.size()));
     }
+    return data;
 }
 
 String FormData::flattenToString() const
 {
-    Vector<char> bytes;
-    flatten(bytes);
+    auto bytes = flatten();
     return Latin1Encoding().decode(reinterpret_cast<const char*>(bytes.data()), bytes.size());
 }
 
@@ -302,6 +292,7 @@
         LOG_ERROR("Tried to resolve a blob without a usable registry");
         return;
     }
+
     BlobData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url);
     if (!blobData) {
         LOG_ERROR("Could not get blob data from a registry");
@@ -308,10 +299,7 @@
         return;
     }
 
-    BlobDataItemList::const_iterator it = blobData->items().begin();
-    const BlobDataItemList::const_iterator itend = blobData->items().end();
-    for (; it != itend; ++it) {
-        const BlobDataItem& blobItem = *it;
+    for (const auto& blobItem : blobData->items()) {
         if (blobItem.type() == BlobDataItem::Type::Data) {
             ASSERT(blobItem.data().data());
             formData->appendData(blobItem.data().data()->data() + static_cast<int>(blobItem.offset()), static_cast<int>(blobItem.length()));
@@ -326,10 +314,8 @@
 {
     // First check if any blobs needs to be resolved, or we can take the fast path.
     bool hasBlob = false;
-    Vector<FormDataElement>::const_iterator it = elements().begin();
-    const Vector<FormDataElement>::const_iterator itend = elements().end();
-    for (; it != itend; ++it) {
-        if (it->m_type == FormDataElement::Type::EncodedBlob) {
+    for (auto& element : m_elements) {
+        if (element.m_type == FormDataElement::Type::EncodedBlob) {
             hasBlob = true;
             break;
         }
@@ -339,12 +325,11 @@
         return *this;
 
     // Create a copy to append the result into.
-    Ref<FormData> newFormData = FormData::create();
+    auto newFormData = FormData::create();
     newFormData->setAlwaysStream(alwaysStream());
     newFormData->setIdentifier(identifier());
-    it = elements().begin();
-    for (; it != itend; ++it) {
-        const FormDataElement& element = *it;
+
+    for (auto& element : m_elements) {
         if (element.m_type == FormDataElement::Type::Data)
             newFormData->appendData(element.m_data.data(), element.m_data.size());
         else if (element.m_type == FormDataElement::Type::EncodedFile)
@@ -363,7 +348,7 @@
     if (!page)
         return;
 
-    for (FormDataElement& element : m_elements) {
+    for (auto& element : m_elements) {
         if (element.m_type == FormDataElement::Type::EncodedFile && element.m_shouldGenerateFile) {
             ASSERT(!element.m_ownsGeneratedFile);
             ASSERT(element.m_generatedFilename.isEmpty());
@@ -378,7 +363,7 @@
 
 bool FormData::hasGeneratedFiles() const
 {
-    for (const FormDataElement& element : m_elements) {
+    for (auto& element : m_elements) {
         if (element.m_type == FormDataElement::Type::EncodedFile && !element.m_generatedFilename.isEmpty())
             return true;
     }
@@ -387,7 +372,7 @@
 
 bool FormData::hasOwnedGeneratedFiles() const
 {
-    for (const FormDataElement& element : m_elements) {
+    for (auto& element : m_elements) {
         if (element.m_type == FormDataElement::Type::EncodedFile && element.m_ownsGeneratedFile) {
             ASSERT(!element.m_generatedFilename.isEmpty());
             return true;
@@ -398,7 +383,7 @@
 
 void FormData::removeGeneratedFilesIfNeeded()
 {
-    for (FormDataElement& element : m_elements) {
+    for (auto& element : m_elements) {
         if (element.m_type == FormDataElement::Type::EncodedFile && element.m_ownsGeneratedFile) {
             ASSERT(!element.m_generatedFilename.isEmpty());
             ASSERT(element.m_shouldGenerateFile);

Modified: trunk/Source/WebCore/platform/network/FormData.h (221838 => 221839)


--- trunk/Source/WebCore/platform/network/FormData.h	2017-09-10 22:17:59 UTC (rev 221838)
+++ trunk/Source/WebCore/platform/network/FormData.h	2017-09-10 22:56:58 UTC (rev 221839)
@@ -222,7 +222,7 @@
     WEBCORE_EXPORT void appendBlob(const URL& blobURL);
     char* expandDataStore(size_t);
 
-    void flatten(Vector<char>&) const; // omits files
+    Vector<char> flatten() const; // omits files
     String flattenToString() const; // omits files
 
     // Resolve all blob references so we only have file and data.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to