RESOLVED FIXED 227718
Add support for FormDataEvent
https://bugs.webkit.org/show_bug.cgi?id=227718
Summary Add support for FormDataEvent
Qiaosong Zhou
Reported 2021-07-06 13:50:34 PDT
FormData event handler addition
Attachments
Patch (3.34 KB, patch)
2021-07-06 14:00 PDT, Qiaosong Zhou
no flags
Patch (17.47 KB, patch)
2021-07-12 01:55 PDT, Qiaosong Zhou
no flags
Patch (18.41 KB, patch)
2021-07-12 14:01 PDT, Qiaosong Zhou
no flags
Patch (19.24 KB, patch)
2021-07-12 16:15 PDT, Qiaosong Zhou
no flags
Patch (19.16 KB, patch)
2021-07-12 17:01 PDT, Qiaosong Zhou
no flags
Patch (20.50 KB, patch)
2021-07-14 22:43 PDT, Qiaosong Zhou
ews-feeder: commit-queue-
Patch (25.12 KB, patch)
2021-07-14 23:19 PDT, Qiaosong Zhou
no flags
Patch (24.43 KB, patch)
2021-07-14 23:35 PDT, Qiaosong Zhou
no flags
Patch (25.00 KB, patch)
2021-07-18 23:41 PDT, Qiaosong Zhou
no flags
Patch (47.15 KB, patch)
2021-07-19 00:10 PDT, Qiaosong Zhou
no flags
Patch (46.23 KB, patch)
2021-07-19 01:18 PDT, Qiaosong Zhou
no flags
Patch (64.35 KB, patch)
2021-07-19 02:49 PDT, Qiaosong Zhou
no flags
Patch (65.69 KB, patch)
2021-07-19 13:20 PDT, Qiaosong Zhou
no flags
Patch (65.72 KB, patch)
2021-07-19 16:56 PDT, Qiaosong Zhou
no flags
Patch (67.21 KB, patch)
2021-07-19 19:31 PDT, Qiaosong Zhou
no flags
Patch (95.34 KB, patch)
2021-07-20 10:47 PDT, Qiaosong Zhou
no flags
Patch (39.69 KB, patch)
2021-07-20 13:05 PDT, Qiaosong Zhou
no flags
Patch (93.76 KB, patch)
2021-07-20 13:15 PDT, Qiaosong Zhou
no flags
Patch (105.84 KB, patch)
2021-07-21 17:57 PDT, Qiaosong Zhou
no flags
Patch (97.62 KB, patch)
2021-07-22 16:42 PDT, Qiaosong Zhou
no flags
Patch (96.74 KB, patch)
2021-07-22 19:43 PDT, Qiaosong Zhou
no flags
Patch (96.79 KB, patch)
2021-07-23 03:57 PDT, Qiaosong Zhou
no flags
Patch (97.07 KB, patch)
2021-07-23 13:14 PDT, Qiaosong Zhou
no flags
Patch (97.07 KB, patch)
2021-07-23 13:16 PDT, Qiaosong Zhou
no flags
Patch (98.39 KB, patch)
2021-07-23 17:39 PDT, Qiaosong Zhou
no flags
Patch (3.68 KB, patch)
2021-07-26 16:27 PDT, Qiaosong Zhou
no flags
Patch (3.66 KB, patch)
2021-07-26 16:31 PDT, Qiaosong Zhou
no flags
Chris Dumez
Comment 1 2021-07-06 13:53:07 PDT
(In reply to Qiaosong Zhou from comment #0) > FormData event handler addition Please provide a better bug title / description. This is way too vague.
Qiaosong Zhou
Comment 2 2021-07-06 14:00:13 PDT
Chris Dumez
Comment 3 2021-07-06 14:02:42 PDT
Comment on attachment 432970 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=432970&action=review Also missing test or test rebaseline. > Source/WebCore/ChangeLog:7 > + Please add detailed change log description. > Source/WebCore/platform/network/FormData.cpp:96 > + scheduleEvent(eventNames().formdataEvent) Spec says we should fire an FormDataEvent, not a generic Event.
Qiaosong Zhou
Comment 4 2021-07-06 14:04:35 PDT
Sorry I'm just creating a ChangeLog stub. Haven't finalized the changes yet.
Chris Dumez
Comment 5 2021-07-06 14:05:09 PDT
(In reply to Qiaosong Zhou from comment #4) > Sorry I'm just creating a ChangeLog stub. Haven't finalized the changes yet. Then please do not set r? flag, which indicates that you are requesting a review.
Qiaosong Zhou
Comment 6 2021-07-12 01:55:28 PDT
Chris Dumez
Comment 7 2021-07-12 09:00:55 PDT
Comment on attachment 433304 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433304&action=review > Source/WebCore/dom/FormDataEvent.cpp:43 > + : Event(eventType, initializer, IsTrusted::Yes) This doesn't seem right. Events constructed by JavaScript should NOT be trusted. Only the events constructed by the browser in native code should be trusted. As far as I can tell, the JS constructed ends up calling this constructor and is incorrectly marked as trusted.
Qiaosong Zhou
Comment 8 2021-07-12 14:01:32 PDT
Qiaosong Zhou
Comment 9 2021-07-12 14:08:00 PDT
(In reply to Chris Dumez from comment #7) > Comment on attachment 433304 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=433304&action=review > > > Source/WebCore/dom/FormDataEvent.cpp:43 > > + : Event(eventType, initializer, IsTrusted::Yes) > > This doesn't seem right. Events constructed by JavaScript should NOT be > trusted. Only the events constructed by the browser in native code should be > trusted. > As far as I can tell, the JS constructed ends up calling this constructor > and is incorrectly marked as trusted. Thanks for the feedback. I'll change this on the next upload. Currently for some reason DOMFormData constructor is called repeatedly when a FormDataEvent is dispatched to HTMLFormElement, causing a stack overflow.
Chris Dumez
Comment 10 2021-07-12 14:16:34 PDT
Comment on attachment 433355 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433355&action=review > Source/WebCore/html/DOMFormData.cpp:60 > + auto formDataEvent = FormDataEvent::create(eventNames().formdataEvent, Event::CanBubble::No, Event::IsCancelable::No, Event::IsComposed::No, this); You probably need to move the event creation / dispatch to DOMFormData::create(), *after* calling the constructor. Calling this from inside the destructor is a bad idea because constructing the FormDataEvent will ref() |this| before it is done constructing.
Qiaosong Zhou
Comment 11 2021-07-12 16:15:32 PDT
Chris Dumez
Comment 12 2021-07-12 16:19:27 PDT
Comment on attachment 433367 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433367&action=review > Source/WebCore/html/DOMFormData.cpp:64 > + EventDispatcher::dispatchEvent(*form, formDataEvent.get()); form can be null so *form is wrong here.
Chris Dumez
Comment 13 2021-07-12 16:57:51 PDT
Comment on attachment 433367 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433367&action=review > Source/WebCore/dom/FormDataEvent.h:46 > + static Ref<FormDataEvent> create(const AtomString&, CanBubble, IsCancelable, IsComposed, DOMFormData*); Should take in a Ref<DOMFormData>&&, not a DOMFormData* since it cannot be null. > Source/WebCore/dom/FormDataEvent.h:48 > + DOMFormData* formData() const { return m_formData.get(); } Should return a DOMFormData& since it cannot be null. > Source/WebCore/dom/FormDataEvent.h:53 > + RefPtr<DOMFormData> m_formData; Should use Ref<> since it cannot be null. > Source/WebCore/html/DOMFormData.cpp:63 > + auto formDataEvent = FormDataEvent::create(eventNames().formdataEvent, Event::CanBubble::No, Event::IsCancelable::No, Event::IsComposed::No, formData.ptr()); formData.copyRef()
Qiaosong Zhou
Comment 14 2021-07-12 17:01:09 PDT
Chris Dumez
Comment 15 2021-07-12 17:11:48 PDT
Comment on attachment 433373 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433373&action=review > Source/WebCore/WebCore.xcodeproj/project.pbxproj:5526 > + FD3160BF12B0272A00C1A359 /* (null) in Headers */ = {isa = PBXBuildFile; }; Suspicious change. > Source/WebCore/WebCore.xcodeproj/project.pbxproj:31622 > + FD3160BF12B0272A00C1A359 /* (null) in Headers */, Ditto. > Source/WebCore/dom/FormDataEvent.h:35 > +struct FormDataEventInit : public EventInit { Should probably be moved inside the FormDataEvent class. > Source/WebCore/dom/FormDataEvent.h:53 > + RefPtr<DOMFormData> m_formData; Please leave a blank line between the functions and the data members. > Source/WebCore/dom/FormDataEvent.idl:28 > + constructor(DOMString type, FormDataEventInit eventInitDict); We use 4 space indentation in WebKit (not 2 space). > Source/WebCore/html/DOMFormData.cpp:61 > + Ref<DOMFormData> formData = adoptRef(*new DOMFormData(form)); auto formData > Source/WebCore/html/DOMFormData.cpp:62 > + auto formDataEvent = FormDataEvent::create(eventNames().formdataEvent, Event::CanBubble::No, Event::IsCancelable::No, Event::IsComposed::No, formData.ptr()); Should be inside the if scope below. Why construct an event if you're not going to dispatch it? > Source/WebCore/html/DOMFormData.cpp:64 > + form->dispatchEvent(formDataEvent.get()); form->dispatchEvent(FormDataEvent::create(eventNames().formdataEvent, Event::CanBubble::No, Event::IsCancelable::No, Event::IsComposed::No, formData.ptr()));
Radar WebKit Bug Importer
Comment 16 2021-07-13 13:51:21 PDT
Qiaosong Zhou
Comment 17 2021-07-14 22:43:54 PDT
Qiaosong Zhou
Comment 18 2021-07-14 23:19:40 PDT
Qiaosong Zhou
Comment 19 2021-07-14 23:35:05 PDT
Chris Dumez
Comment 20 2021-07-15 08:46:04 PDT
Comment on attachment 433565 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433565&action=review Note that some tests still need rebaselining and there are a new real-looking crashes as well. > Source/WebCore/WebCore.xcodeproj/project.pbxproj:5527 > + FD3160BF12B0272A00C1A359 /* (null) in Headers */ = {isa = PBXBuildFile; }; Bad change, please drop. > Source/WebCore/WebCore.xcodeproj/project.pbxproj:31611 > + FD3160BF12B0272A00C1A359 /* (null) in Headers */, ditto. > Source/WebCore/dom/FormDataEvent.cpp:38 > + if (!init.formData) Should not be needed. The generated bindings code should already do this check for you, if it is marked as required in the IDL, then you can assume the pointer is non-null here. > Source/WebCore/dom/FormDataEvent.cpp:57 > + , m_formData(formData) WTFMove(formData) to avoid ref-counting churn. > Source/WebCore/dom/FormDataEvent.cpp:66 > +} } // namespace WebCore is our usual pattern. > Source/WebCore/dom/FormDataEvent.h:38 > + struct FormDataEventInit : public EventInit { Just name this struct "Init". Also, no need for "public" since inheritance is public by default for struct (unlike class). > Source/WebCore/dom/FormDataEvent.h:42 > + using Init = FormDataEventInit; Then drop this alias. > Source/WebCore/dom/FormDataEvent.h:44 > + static ExceptionOr<Ref<FormDataEvent>> create(const AtomString&, FormDataEventInit&&); Shouldn't need the ExceptionOr<> > Source/WebCore/dom/FormDataEvent.idl:26 > +[Exposed=Window] The format we usually use in our IDL is: [ Exposed=Window ] interface FormDataEvent : Event { > Source/WebCore/html/DOMFormData.cpp:63 > + return dispatchFormDataEvent(adoptRef(*new DOMFormData(form)), *form); Why aren't you using DOMFormData::create(form) ? Also, if we should to leave the cloning up to the caller, then it would look like: if (form) { auto formData = DOMFormData::create(form); auto dispatchResult = dispatchFormDataEvent(formData, *form); if (dispatchResult.hasException()) return dispatchResult.releaseException(); return formData->clone(); } > Source/WebCore/html/DOMFormData.cpp:71 > + if (!DOMFormData::formDataDispatched) { Seems like this should be an early return instead: if (isDispatchingFormDataEvent) return Exception { InvalidStateError, "Cannot call \"new FormData()\" within FormDataEvent handler"_s }; > Source/WebCore/html/DOMFormData.cpp:77 > + return DOMFormData::create(WTFMove(formData)); Given that not all call sites seem to want cloning, we should probably return { }; return and have the return type be ExceptionOr<void>. > Source/WebCore/html/DOMFormData.cpp:88 > +Ref<DOMFormData> DOMFormData::create(Ref<DOMFormData>&& other) It feels weird to have a factory function on DOMFormData that takes in a Ref<DOMFormData>&& in. Shouldn't we simply add a "clone()" member function to DOMFormData? > Source/WebCore/html/DOMFormData.h:58 > + inline static bool formDataDispatched = false; No inline here. I don't think using a static variable makes sense either. Imagine 2 tabs sharing the same process, I don't think you'd want the formdata dispatch for one page to be impacted by the formdata dispatch in another. Also, the name should be something like "isDispatchingFormDataEvent". I am also unclear why this is public. > Source/WebCore/loader/FormSubmission.cpp:230 > + DOMFormData::dispatchFormDataEvent(domFormData.copyRef(), form); How come we're not using the returned DOMFormData here? If this call site doesn't need to clone, then dispatchFormDataEvent() should probably not do the cloning and we should leave it up to the caller.
Alex Christensen
Comment 21 2021-07-15 09:33:25 PDT
Comment on attachment 433565 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433565&action=review > Source/WebCore/dom/GlobalEventHandlers.idl:59 > // FIXME: Implement 'onformdata'. This line should be removed.
Alex Christensen
Comment 22 2021-07-15 17:07:36 PDT
Comment on attachment 433565 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433565&action=review >> Source/WebCore/html/DOMFormData.h:58 >> + inline static bool formDataDispatched = false; > > No inline here. I don't think using a static variable makes sense either. Imagine 2 tabs sharing the same process, I don't think you'd want the formdata dispatch for one page to be impacted by the formdata dispatch in another. > > Also, the name should be something like "isDispatchingFormDataEvent". > > I am also unclear why this is public. This could be a function-scoped static bool instead of a class-scoped static bool because it is only used in one function.
Chris Dumez
Comment 23 2021-07-15 17:08:26 PDT
(In reply to Alex Christensen from comment #22) > Comment on attachment 433565 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=433565&action=review > > >> Source/WebCore/html/DOMFormData.h:58 > >> + inline static bool formDataDispatched = false; > > > > No inline here. I don't think using a static variable makes sense either. Imagine 2 tabs sharing the same process, I don't think you'd want the formdata dispatch for one page to be impacted by the formdata dispatch in another. > > > > Also, the name should be something like "isDispatchingFormDataEvent". > > > > I am also unclear why this is public. > > This could be a function-scoped static bool instead of a class-scoped static > bool because it is only used in one function. As I said, it should not be a static at all. It doesn't make sense.
Qiaosong Zhou
Comment 24 2021-07-16 00:42:43 PDT
(In reply to Chris Dumez from comment #23) > As I said, it should not be a static at all. It doesn't make sense. I have removed the static variable. Instead I'm using a threadGlobalData member variable to address the problem of threads sharing static variables. I hope that's the optimal solution here?
Qiaosong Zhou
Comment 25 2021-07-16 00:50:45 PDT
(In reply to Chris Dumez from comment #20) > > Source/WebCore/html/DOMFormData.cpp:63 > > + return dispatchFormDataEvent(adoptRef(*new DOMFormData(form)), *form); > > Why aren't you using DOMFormData::create(form) ? > > Also, if we should to leave the cloning up to the caller, then it would look > like: > if (form) { > auto formData = DOMFormData::create(form); > auto dispatchResult = dispatchFormDataEvent(formData, *form); > if (dispatchResult.hasException()) > return dispatchResult.releaseException(); > return formData->clone(); > } > > > Source/WebCore/html/DOMFormData.cpp:77 > > + return DOMFormData::create(WTFMove(formData)); > > Given that not all call sites seem to want cloning, we should probably > return { }; return and have the return type be ExceptionOr<void>. The reason that I have to clone for in this case is that if the handler for FormDataEvent stores the DOMFormData object in the outer scope, the correct behavior is that changing the outer scope reference outside of the event handler should not change the original DOMFormData object. To fall in line with that, I clone the DOMFormData after the event is dispatched. > > Source/WebCore/html/DOMFormData.cpp:88 > > +Ref<DOMFormData> DOMFormData::create(Ref<DOMFormData>&& other) > > It feels weird to have a factory function on DOMFormData that takes in a > Ref<DOMFormData>&& in. Shouldn't we simply add a "clone()" member function > to DOMFormData? Yes I will apply that change. > > > Source/WebCore/loader/FormSubmission.cpp:230 > > + DOMFormData::dispatchFormDataEvent(domFormData.copyRef(), form); > > How come we're not using the returned DOMFormData here? > > If this call site doesn't need to clone, then dispatchFormDataEvent() should > probably not do the cloning and we should leave it up to the caller. Same as above, I feel like cloning should be mandatory to prevent illegal tampering with DOMFormData from outside of the event handler.
Qiaosong Zhou
Comment 26 2021-07-16 00:54:51 PDT
Specifically, the last two asserts for test "Newly created FormData contains entries added to "formData" IDL attribute of FormDataEvent." on http://wpt.live/xhr/formdata.html seems to mandate cloning.
Kent Tamura
Comment 27 2021-07-16 02:43:04 PDT
*** Bug 193231 has been marked as a duplicate of this bug. ***
Qiaosong Zhou
Comment 28 2021-07-18 23:41:36 PDT
Qiaosong Zhou
Comment 29 2021-07-19 00:10:14 PDT
Qiaosong Zhou
Comment 30 2021-07-19 01:18:53 PDT
Qiaosong Zhou
Comment 31 2021-07-19 02:49:26 PDT
Chris Dumez
Comment 32 2021-07-19 08:35:37 PDT
Comment on attachment 433782 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433782&action=review > Source/WebCore/html/DOMFormData.cpp:71 > + if (threadGlobalData().isFormDataEventDispatched()) This is not any different than a static and still incorrect behavior. I don't think 2 pages in the same process should impact each other's for submissions. > Source/WebCore/platform/network/FormData.cpp:278 > + // FIXME: Rmove the following if statement when fixed. Typo: Remove
Chris Dumez
Comment 33 2021-07-19 08:38:09 PDT
Comment on attachment 433782 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433782&action=review > Source/WebCore/html/DOMFormData.cpp:92 > + for (auto& item : this->items()) Any reason we cannot simply do: ``` newFormData->m_items = m_items; ``` ?
Chris Dumez
Comment 34 2021-07-19 08:40:59 PDT
Comment on attachment 433782 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433782&action=review >> Source/WebCore/html/DOMFormData.cpp:71 >> + if (threadGlobalData().isFormDataEventDispatched()) > > This is not any different than a static and still incorrect behavior. I don't think 2 pages in the same process should impact each other's for submissions. We likely want a flag on the HTMLFormElement or FormSubmission instead.
Alex Christensen
Comment 35 2021-07-19 13:12:32 PDT
Comment on attachment 433782 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433782&action=review >>> Source/WebCore/html/DOMFormData.cpp:71 >>> + if (threadGlobalData().isFormDataEventDispatched()) >> >> This is not any different than a static and still incorrect behavior. I don't think 2 pages in the same process should impact each other's for submissions. > > We likely want a flag on the HTMLFormElement or FormSubmission instead. It looks like this needs to move to DOMFormData::create, but I don't think this can be accomplished with a flag on HTMLFormElement or FormSubmission. This needs to change what DOMFormData::create returns if it is called inside the stack trace of dispatching the FormDataEvent.
Chris Dumez
Comment 36 2021-07-19 13:14:24 PDT
Comment on attachment 433782 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433782&action=review >>>> Source/WebCore/html/DOMFormData.cpp:71 >>>> + if (threadGlobalData().isFormDataEventDispatched()) >>> >>> This is not any different than a static and still incorrect behavior. I don't think 2 pages in the same process should impact each other's for submissions. >> >> We likely want a flag on the HTMLFormElement or FormSubmission instead. > > It looks like this needs to move to DOMFormData::create, but I don't think this can be accomplished with a flag on HTMLFormElement or FormSubmission. This needs to change what DOMFormData::create returns if it is called inside the stack trace of dispatching the FormDataEvent. The form is passed as parameter here so I don't see why a flag on the form wouldn't work. Note that as far as I can tell, Blink is using a flag on the form.
Chris Dumez
Comment 37 2021-07-19 13:16:47 PDT
Comment on attachment 433782 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433782&action=review >>>>> Source/WebCore/html/DOMFormData.cpp:71 >>>>> + if (threadGlobalData().isFormDataEventDispatched()) >>>> >>>> This is not any different than a static and still incorrect behavior. I don't think 2 pages in the same process should impact each other's for submissions. >>> >>> We likely want a flag on the HTMLFormElement or FormSubmission instead. >> >> It looks like this needs to move to DOMFormData::create, but I don't think this can be accomplished with a flag on HTMLFormElement or FormSubmission. This needs to change what DOMFormData::create returns if it is called inside the stack trace of dispatching the FormDataEvent. > > The form is passed as parameter here so I don't see why a flag on the form wouldn't work. Note that as far as I can tell, Blink is using a flag on the form. For the record, this is the section of the spec where this is specified: https://html.spec.whatwg.org/#constructing-form-data-set:formdataevent "Set form's firing submission events to true." / "Set form's firing submission events to false." In particular this flag: https://html.spec.whatwg.org/#constructing-entry-list Which is a flag on the form. Please match the spec exactly.
Alex Christensen
Comment 38 2021-07-19 13:19:56 PDT
Oh, I see. Not all FormData constructors will fail inside of that event, just the ones using that FormData with the flag. You're right.
Chris Dumez
Comment 39 2021-07-19 13:20:16 PDT
Comment on attachment 433782 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433782&action=review >>>>>> Source/WebCore/html/DOMFormData.cpp:71 >>>>>> + if (threadGlobalData().isFormDataEventDispatched()) >>>>> >>>>> This is not any different than a static and still incorrect behavior. I don't think 2 pages in the same process should impact each other's for submissions. >>>> >>>> We likely want a flag on the HTMLFormElement or FormSubmission instead. >>> >>> It looks like this needs to move to DOMFormData::create, but I don't think this can be accomplished with a flag on HTMLFormElement or FormSubmission. This needs to change what DOMFormData::create returns if it is called inside the stack trace of dispatching the FormDataEvent. >> >> The form is passed as parameter here so I don't see why a flag on the form wouldn't work. Note that as far as I can tell, Blink is using a flag on the form. > > For the record, this is the section of the spec where this is specified: > https://html.spec.whatwg.org/#constructing-form-data-set:formdataevent > "Set form's firing submission events to true." / "Set form's firing submission events to false." > > In particular this flag: > https://html.spec.whatwg.org/#constructing-entry-list > > Which is a flag on the form. > > Please match the spec exactly. And from the spec, it looks like this flag is being checked when submitting a form, not when constructing a DOMFormData, so this is definitely the wrong place. See https://html.spec.whatwg.org/#form-submission-algorithm:constructing-entry-list
Qiaosong Zhou
Comment 40 2021-07-19 13:20:51 PDT
Chris Dumez
Comment 41 2021-07-19 13:22:10 PDT
Comment on attachment 433817 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433817&action=review > Source/WebCore/html/DOMFormData.cpp:71 > + if (form.formDataEventDispatched()) As mentioned earlier, this is not the right place to check this. The name of the flag is also wrong. Please match the spec text.
Chris Dumez
Comment 42 2021-07-19 14:34:29 PDT
(In reply to Chris Dumez from comment #41) > Comment on attachment 433817 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=433817&action=review > > > Source/WebCore/html/DOMFormData.cpp:71 > > + if (form.formDataEventDispatched()) > > As mentioned earlier, this is not the right place to check this. The name of > the flag is also wrong. Please match the spec text. Looking at the spec for the FormData constructor here: - https://xhr.spec.whatwg.org/#dom-formdata It does appear that it calls "construct an entry-list" (https://html.spec.whatwg.org/#constructing-entry-list), which does check the flag. So I think we need to try and match the spec a bit more closely for clarity. Ideally, we'd have a constructEntryList() function which is called both from the FormData constructor and form submission and this function would return early if the flag is set. And we would rename the flag to match the spec more exactly. While the behavior now is properly more or less correct, it will be much more obvious once our implementation matches for directly the spec language.
Qiaosong Zhou
Comment 43 2021-07-19 16:56:22 PDT
Qiaosong Zhou
Comment 44 2021-07-19 19:31:14 PDT
Qiaosong Zhou
Comment 45 2021-07-20 10:47:30 PDT
Qiaosong Zhou
Comment 46 2021-07-20 13:05:30 PDT
Qiaosong Zhou
Comment 47 2021-07-20 13:15:40 PDT
Chris Dumez
Comment 48 2021-07-20 13:18:07 PDT
Comment on attachment 433895 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433895&action=review > Source/WebCore/html/DOMFormData.cpp:71 > + if (form.formDataEventDispatched()) Still not matching the spec. There is no such flag in the spec, as mentioned earlier. There is a flag in the spec but it is not about the form data event being dispatched, it is about constructing an entry list.
Qiaosong Zhou
Comment 49 2021-07-21 17:57:01 PDT
Chris Dumez
Comment 50 2021-07-21 19:41:52 PDT
Comment on attachment 433980 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433980&action=review > Source/WebCore/html/DOMFormData.cpp:59 > + May be good to have a link to the corresponding spec section here as a comment: // https://html.spec.whatwg.org/C/#constructing-the-form-data-set > Source/WebCore/html/DOMFormData.cpp:60 > +ExceptionOr<Ref<DOMFormData>> DOMFormData::constructEntryList(HTMLFormElement& form, StringPairVector* formValues, bool isMultiPartForm, bool& containsPasswordData) Could we move this to HTMLFormElement ? This way, we don't need to pass in a form. Also, we probably won't need the public isConstructingEntryList() / setIsConstructingEntryList() on HTMLFormElement. > Source/WebCore/html/DOMFormData.cpp:64 > + I think this function is supposed to: 1. Construct a new DOMFormData object 2. Do your loop below which populates the DOMFormData object 3. dispatch the FormDataEvent 4. Return the DOMFormData object > Source/WebCore/html/DOMFormData.cpp:65 > + form.setIsConstructingEntryList(true); Once you move this to HTMLFormElement, please use WTF::SetForScope to change the value of m_isConstructingEntryList. > Source/WebCore/html/DOMFormData.cpp:97 > +void DOMFormData::dispatchFormDataEvent(Ref<DOMFormData>&& formData, HTMLFormElement& form) We probably don't need a whole function for this. We can probably just merge into constructEntryList() as a one liner: dispatchEvent(FormDataEvent::create(eventNames().formdataEvent, Event::CanBubble::Yes, Event::IsCancelable::No, Event::IsComposed::No, formData.copyRef())); > Source/WebCore/html/DOMFormData.cpp:113 > + Unnecessary blank line. > Source/WebCore/html/DOMFormData.h:56 > + static void dispatchFormDataEvent(Ref<DOMFormData>&&, HTMLFormElement&); Not needed. > Source/WebCore/html/HTMLFormElement.cpp:402 > + auto result = FormSubmission::create(*this, submitter, m_attributes, event, shouldLockHistory, trigger); I don't think HTMLFormElement::submit() is supposed to throw an exception. I also don't think that it is possible that the isConstructingEntryList flag is true. I think constructEntryListList() should just return a RefPtr<> and let the call-site decide if they want to throw or not. In the DOMFormData constructor case, we'd throw if constructEntryList() returns null. In the form submission case, we'd RELEASE_ASSERT() that the value is non-null. > Source/WebCore/loader/FormSubmission.cpp:217 > + if (entryListResult.hasException()) { I don't think this case is possible, I think we should just RELEASE_ASSERT() that constructEntryList returned a valid domFormData.
Chris Dumez
Comment 51 2021-07-21 19:44:08 PDT
Comment on attachment 433980 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=433980&action=review > Source/WebCore/html/DOMFormData.cpp:63 > + return Exception { InvalidStateError, "Already constructing Form entry list."_s }; I think we should just return null here, like in the spec text and let the DOMFormData constructor throw the exception if it get null. >> Source/WebCore/html/DOMFormData.cpp:64 >> + > > I think this function is supposed to: > 1. Construct a new DOMFormData object > 2. Do your loop below which populates the DOMFormData object > 3. dispatch the FormDataEvent > 4. Return the DOMFormData object To clarify, for step 4, I meant return a *clone* of the DOMFormData, as per https://html.spec.whatwg.org/C/#constructing-the-form-data-set
Qiaosong Zhou
Comment 52 2021-07-22 16:42:43 PDT
Qiaosong Zhou
Comment 53 2021-07-22 19:43:48 PDT
Qiaosong Zhou
Comment 54 2021-07-23 03:57:17 PDT
Alex Christensen
Comment 55 2021-07-23 11:44:26 PDT
Comment on attachment 434080 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434080&action=review Looks like you addressed Chris's comments. I think it looks good. A few style things and I'd say it's ready. > Source/WebCore/ChangeLog:6 > + Reviewed by NOBODY (OOPS!). nit: space below > Source/WebCore/html/DOMFormData.cpp:36 > +#include "ThreadGlobalData.h" This isn't used any more. > Source/WebCore/html/HTMLFormElement.h:128 > + RefPtr<DOMFormData> constructEntryList(Ref<DOMFormData>&&, StringPairVector*, bool, bool&); Style nit: It would be nicer if this didn't have an out-param and used 2-state enums instead of bools to make the call sites more readable. Like this: enum class IsMultiPartForm : bool { No, Yes }; enum class ContainsPasswordData : bool { No, Yes }; std::pair<RefPtr<DOMFormData>, ContainsPasswordData> constructEntryList(Ref<DOMFormData>&&, StringPairVector*, IsMultiPartForm);
Chris Dumez
Comment 56 2021-07-23 12:21:07 PDT
Comment on attachment 434080 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434080&action=review > Source/WebCore/html/DOMFormData.cpp:52 > + auto result = form->constructEntryList(WTFMove(domFormData), nullptr, true, temp); Why is it correct to unconditionally pass isMultiPartForm=true here? I might be, I just don't know why. > Source/WebCore/html/HTMLFormElement.cpp:973 > + SetForScope<bool> isConstructingEntryListRestorer(m_isConstructingEntryList, true); I'd name this: "isConstructingEntryListScope". We usually use "Scope" in the name for such things. > Source/WebCore/loader/FormSubmission.cpp:215 > + auto result = form.constructEntryList(WTFMove(domFormData), &formValues, isMultiPartForm, containsPasswordData); Could constructEntryList() call fomFormData->setContainsPasswordData() by itself instead of requiring an out-parameter?
Chris Dumez
Comment 57 2021-07-23 12:26:52 PDT
Comment on attachment 434080 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434080&action=review > Source/WebCore/html/DOMFormData.cpp:51 > + bool temp; FYI, temp is a terrible name and I would have used to actual parameter name here. That said, I think we should be able to get rid of this out-parameter entirely with my earlier suggestion. >> Source/WebCore/html/DOMFormData.cpp:52 >> + auto result = form->constructEntryList(WTFMove(domFormData), nullptr, true, temp); > > Why is it correct to unconditionally pass isMultiPartForm=true here? I might be, I just don't know why. It is probably fine. Looks like it is only used by FileInputType::appendFormData() for something that is likely obsolete. Passing true is likely OK but I'd switch to an enum class for clarity, like Alex mentioned.
Qiaosong Zhou
Comment 58 2021-07-23 13:14:42 PDT
Qiaosong Zhou
Comment 59 2021-07-23 13:16:09 PDT
Alex Christensen
Comment 60 2021-07-23 13:39:52 PDT
Comment on attachment 434115 [details] Patch Looks good to me. I'll let Chis double check it.
Geoffrey Garen
Comment 61 2021-07-23 14:06:36 PDT
Comment on attachment 434115 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434115&action=review > Source/WebCore/html/HTMLFormElement.h:132 > + bool containsPasswordData() const { return m_containsPasswordData; } As far as I can tell, nobody ever consults the value of containsPasswordData. (And, the value is lost accidentally when serializing across processes in FormData::encode(), and when serializing across threads in FormData::isolatedCopy(), consistent with a theory that it may be vestigial and unused.) I think you can remove containsPasswordData, and the associated code you need to modify in order to maintain it. Why don't you give that a shot and see if it builds. > Source/WebCore/platform/network/FormData.cpp:278 > + // FIXME: DOMFormData created in FormData Event callback with text/plain enctype will crash here because values can be file. The expected behavior is to convert files to string for enctype "text/plain". Conversion may be added at "void DOMFormData::set(const String& name, Blob& blob, const String& filename)" or here. > + // FIXME: Remove the following if statement when fixed. I would say just: // FIXME: if the item is a file, we are expected to converted the file to a string. No need to mention that a crash is how you started debugging; what you've learned since then is most helpful to the next reader.
Qiaosong Zhou
Comment 62 2021-07-23 17:39:31 PDT
Chris Dumez
Comment 63 2021-07-26 08:28:03 PDT
Comment on attachment 434149 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434149&action=review r=me with one comment. > Source/WebCore/platform/network/FormData.cpp:278 > + if (!WTF::holds_alternative<String>(item.data)) Is this really still needed? I thought my proposal to do `newFormData->m_items = m_items;` would avoid this.
Qiaosong Zhou
Comment 64 2021-07-26 12:48:49 PDT
(In reply to Chris Dumez from comment #63) > Comment on attachment 434149 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=434149&action=review > > r=me with one comment. > > > Source/WebCore/platform/network/FormData.cpp:278 > > + if (!WTF::holds_alternative<String>(item.data)) > > Is this really still needed? I thought my proposal to do > `newFormData->m_items = m_items;` would avoid this. It is still needed. It is related to another issue, where the current formdata does not process forms with enctype="text/plain" properly. It's supposed to automatically convert files to string if the form is "text/plain". Currently it is possible to receive a file here, causing a crash when the variant is unparsed as a string. (further down the line) The specific test case that causes a crash is http://wpt.live/html/semantics/forms/form-submission-0/text-plain.window.html
Chris Dumez
Comment 65 2021-07-26 12:49:38 PDT
(In reply to Qiaosong Zhou from comment #64) > (In reply to Chris Dumez from comment #63) > > Comment on attachment 434149 [details] > > Patch > > > > View in context: > > https://bugs.webkit.org/attachment.cgi?id=434149&action=review > > > > r=me with one comment. > > > > > Source/WebCore/platform/network/FormData.cpp:278 > > > + if (!WTF::holds_alternative<String>(item.data)) > > > > Is this really still needed? I thought my proposal to do > > `newFormData->m_items = m_items;` would avoid this. > > It is still needed. It is related to another issue, where the current > formdata does not process forms with enctype="text/plain" properly. It's > supposed to automatically convert files to string if the form is > "text/plain". Currently it is possible to receive a file here, causing a > crash when the variant is unparsed as a string. (further down the line) > > The specific test case that causes a crash is > http://wpt.live/html/semantics/forms/form-submission-0/text-plain.window.html Ok.
EWS
Comment 66 2021-07-26 13:15:56 PDT
Committed r280310 (239960@main): <https://commits.webkit.org/239960@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 434149 [details].
Darin Adler
Comment 67 2021-07-26 14:28:38 PDT
Comment on attachment 434149 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434149&action=review > Source/WebCore/dom/FormDataEvent.h:45 > + DOMFormData& formData() const { return m_formData.get(); } Seems like this should return a const& for conceptual const-ness. > Source/WebCore/html/DOMFormData.cpp:46 > + auto domFormData = adoptRef(*new DOMFormData()); I think the local variable should just be named formData or data. Also no need for the (). > Source/WebCore/html/DOMFormData.cpp:48 > + return domFormData; This should have a WTFMove() because the return value optimization doesn’t work if we don’t have types that match exactly. > Source/WebCore/html/DOMFormData.h:33 > +#include "ExceptionOr.h" Should not need to include this. A forward declaration should be sufficient. > Source/WebCore/html/DOMFormData.h:35 > +#include "FormState.h" Should not need to include this. Not clear why it’s needed. > Source/WebCore/html/DOMFormData.h:68 > + Ref<DOMFormData> clone(); Should be const.
Qiaosong Zhou
Comment 68 2021-07-26 16:27:06 PDT
Reopening to attach new patch.
Qiaosong Zhou
Comment 69 2021-07-26 16:27:09 PDT
Chris Dumez
Comment 70 2021-07-26 16:28:48 PDT
Comment on attachment 434254 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434254&action=review > Source/WebCore/html/DOMFormData.cpp:46 > + auto data = adoptRef(*new DOMFormData); I'd much prefer "formData" to the overly generic "data" here.
Qiaosong Zhou
Comment 71 2021-07-26 16:31:20 PDT
EWS
Comment 72 2021-07-26 17:37:14 PDT
Committed r280332 (239979@main): <https://commits.webkit.org/239979@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 434255 [details].
Darin Adler
Comment 73 2021-07-28 09:24:20 PDT
Comment on attachment 434149 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=434149&action=review >> Source/WebCore/html/DOMFormData.cpp:48 >> + return domFormData; > > This should have a WTFMove() because the return value optimization doesn’t work if we don’t have types that match exactly. According to r280376, I was wrong about this. I would like to find out more about why I was wrong!
Qiaosong Zhou
Comment 74 2021-07-29 03:18:34 PDT
(In reply to Darin Adler from comment #73) > Comment on attachment 434149 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=434149&action=review > > >> Source/WebCore/html/DOMFormData.cpp:48 > >> + return domFormData; > > > > This should have a WTFMove() because the return value optimization doesn’t work if we don’t have types that match exactly. > > According to r280376, I was wrong about this. I would like to find out more > about why I was wrong! I think return optimization implicitly moves the rvalue. This link explains it better: https://stackoverflow.com/questions/17473753/c11-return-value-optimization-or-move
Note You need to log in before you can comment on or make changes to this bug.