Changeset 226366 in webkit


Ignore:
Timestamp:
Jan 3, 2018 10:36:24 AM (6 years ago)
Author:
Michael Catanzaro
Message:

[GTK] Add web process API to detect when form is submitted via JavaScript
https://bugs.webkit.org/show_bug.cgi?id=173915

Reviewed by Carlos Garcia Campos.

Source/WebKit:

Epiphany relies on the DOM submit event to detect when a form has been submitted. However,
for historical reasons, the submit event is not emitted when a form is submitted by
JavaScript. It is therefore not currently possible for a web browser to reliably detect form
submission and not possible to implement a robust password storage feature. In order to
avoid this problem, this patch adds a new WebKitWebPage signal, will-submit-form, that
browsers can use in preference to a DOM event listener.

Unfortunately, this signal is not available for WPE because it depends on the DOM API.

There are two submission events, WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT and
WEBKIT_FORM_SUBMISSION_WILL_COMPLETE. WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT
occurs earlier than WEBKIT_FORM_SUBMISSION_WILL_COMPLETE and can be used to retrieve form
values before websites receive the DOM submit event. This is useful as some websites like
to delete form values right before a submit would normally happen in order to attempt to
defeat browser password managers. There are two tricks to note: JavaScript can cancel form
submission immediately after this event occurs (by returning false in an onsubmit handler),
and, for historical reasons, this event will not occur at all when form submission is
triggered by JavaScript. WEBKIT_FORM_SUBMISSION_WILL_COMPLETE occurs next, and is more
straightforward: it is always emitted when a form is about to be submitted, when it is too
late to cancel.

The recommended way to reliably retrieve password form values would be to watch for both
events, use the form value detected in WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT
if that event is emitted, and use the value detected later in
WEBKIT_FORM_SUBMISSION_WILL_COMPLETE otherwise.

Since one of the signal arguments is an enum, we now have to run glib-mkenums for the web
process API. And that has resulted in this patch also adding GType goo for
WebKitConsoleMessageLevel and WebKitConsoleMessageSource that was previously missing. Any
applications that for some unlikely reason want to use these enums in properties or signals
will be happy.

  • PlatformGTK.cmake:
  • UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
  • WebProcess/InjectedBundle/API/glib/WebKitWebPage.cpp:

(webkit_web_page_class_init):

  • WebProcess/InjectedBundle/API/gtk/WebKitWebPage.h:
  • WebProcess/InjectedBundle/API/gtk/WebKitWebProcessEnumTypes.cpp.template: Added.
  • WebProcess/InjectedBundle/API/gtk/WebKitWebProcessEnumTypes.h.template: Added.

Tools:

Test it.

  • TestWebKitAPI/Tests/WebKitGLib/TestWebExtensions.cpp:

(FormSubmissionTest::FormSubmissionTest):
(FormSubmissionTest::~FormSubmissionTest):
(FormSubmissionTest::testFormSubmissionResult):
(FormSubmissionTest::willSendDOMEventCallback):
(FormSubmissionTest::willCompleteCallback):
(FormSubmissionTest::runJavaScriptAndWaitUntilFormSubmitted):
(testWebExtensionFormSubmissionSteps):
(beforeAll):

  • TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp:

(DelayedSignal::DelayedSignal):
(emitFormSubmissionEvent):
(handleFormSubmissionCallback):
(willSubmitFormCallback):
(pageCreatedCallback):

Location:
trunk
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r226354 r226366  
     12018-01-03  Michael Catanzaro  <mcatanzaro@igalia.com>
     2
     3        [GTK] Add web process API to detect when form is submitted via JavaScript
     4        https://bugs.webkit.org/show_bug.cgi?id=173915
     5
     6        Reviewed by Carlos Garcia Campos.
     7
     8        Epiphany relies on the DOM submit event to detect when a form has been submitted. However,
     9        for historical reasons, the submit event is not emitted when a form is submitted by
     10        JavaScript. It is therefore not currently possible for a web browser to reliably detect form
     11        submission and not possible to implement a robust password storage feature. In order to
     12        avoid this problem, this patch adds a new WebKitWebPage signal, will-submit-form, that
     13        browsers can use in preference to a DOM event listener.
     14
     15        Unfortunately, this signal is not available for WPE because it depends on the DOM API.
     16
     17        There are two submission events, WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT and
     18        WEBKIT_FORM_SUBMISSION_WILL_COMPLETE. WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT
     19        occurs earlier than WEBKIT_FORM_SUBMISSION_WILL_COMPLETE and can be used to retrieve form
     20        values before websites receive the DOM submit event. This is useful as some websites like
     21        to delete form values right before a submit would normally happen in order to attempt to
     22        defeat browser password managers. There are two tricks to note: JavaScript can cancel form
     23        submission immediately after this event occurs (by returning false in an onsubmit handler),
     24        and, for historical reasons, this event will not occur at all when form submission is
     25        triggered by JavaScript. WEBKIT_FORM_SUBMISSION_WILL_COMPLETE occurs next, and is more
     26        straightforward: it is always emitted when a form is about to be submitted, when it is too
     27        late to cancel.
     28
     29        The recommended way to reliably retrieve password form values would be to watch for both
     30        events, use the form value detected in WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT
     31        if that event is emitted, and use the value detected later in
     32        WEBKIT_FORM_SUBMISSION_WILL_COMPLETE otherwise.
     33
     34        Since one of the signal arguments is an enum, we now have to run glib-mkenums for the web
     35        process API. And that has resulted in this patch also adding GType goo for
     36        WebKitConsoleMessageLevel and WebKitConsoleMessageSource that was previously missing. Any
     37        applications that for some unlikely reason want to use these enums in properties or signals
     38        will be happy.
     39
     40        * PlatformGTK.cmake:
     41        * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
     42        * WebProcess/InjectedBundle/API/glib/WebKitWebPage.cpp:
     43        (webkit_web_page_class_init):
     44        * WebProcess/InjectedBundle/API/gtk/WebKitWebPage.h:
     45        * WebProcess/InjectedBundle/API/gtk/WebKitWebProcessEnumTypes.cpp.template: Added.
     46        * WebProcess/InjectedBundle/API/gtk/WebKitWebProcessEnumTypes.h.template: Added.
     47
    1482018-01-03  Carlos Garcia Campos  <cgarcia@igalia.com>
    249
  • trunk/Source/WebKit/PlatformGTK.cmake

    r226268 r226366  
    426426
    427427    ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitEnumTypes.cpp
     428    ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitWebProcessEnumTypes.cpp
    428429)
    429430
     
    500501
    501502set(WebKit2WebExtension_INSTALLED_HEADERS
     503    ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitWebProcessEnumTypes.h
    502504    ${WEBKIT_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitConsoleMessage.h
    503505    ${WEBKIT_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitFrame.h
     
    850852
    851853    COMMAND glib-mkenums --template ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitEnumTypes.cpp.template ${WebKit2GTK_ENUM_GENERATION_HEADERS} | sed s/web_kit/webkit/ > ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitEnumTypes.cpp
    852     VERBATIM)
     854    VERBATIM
     855)
     856
     857set(WebKit2GTK_WEB_PROCESS_ENUM_GENERATION_HEADERS ${WebKit2WebExtension_INSTALLED_HEADERS})
     858list(REMOVE_ITEM WebKit2GTK_WEB_PROCESS_ENUM_GENERATION_HEADERS ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitWebProcessEnumTypes.h)
     859add_custom_command(
     860    OUTPUT ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitWebProcessEnumTypes.h
     861           ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitWebProcessEnumTypes.cpp
     862    DEPENDS ${WebKit2GTK_WEB_PROCESS_ENUM_GENERATION_HEADERS}
     863
     864    COMMAND glib-mkenums --template ${WEBKIT_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitWebProcessEnumTypes.h.template ${WebKit2GTK_WEB_PROCESS_ENUM_GENERATION_HEADERS} | sed s/web_kit/webkit/ | sed s/WEBKIT_TYPE_KIT/WEBKIT_TYPE/ > ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitWebProcessEnumTypes.h
     865
     866    COMMAND glib-mkenums --template ${WEBKIT_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitWebProcessEnumTypes.cpp.template ${WebKit2GTK_WEB_PROCESS_ENUM_GENERATION_HEADERS} | sed s/web_kit/webkit/ > ${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitWebProcessEnumTypes.cpp
     867    VERBATIM
     868)
    853869
    854870WEBKIT_BUILD_INSPECTOR_GRESOURCES(${DERIVED_SOURCES_WEBKIT2GTK_DIR})
     
    10531069    "${FORWARDING_HEADERS_DIR}"
    10541070    "${FORWARDING_HEADERS_WEBKIT2GTK_DIR}"
     1071    "${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}"
    10551072)
    10561073
  • trunk/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt

    r226264 r226366  
    14391439<FILE>WebKitWebPage</FILE>
    14401440WebKitWebPage
     1441WebKitFormSubmissionStep
    14411442webkit_web_page_get_dom_document
    14421443webkit_web_page_get_id
     
    14531454WEBKIT_IS_WEB_PAGE_CLASS
    14541455WEBKIT_WEB_PAGE_GET_CLASS
     1456WEBKIT_TYPE_FORM_SUBMISSION_STEP
    14551457
    14561458<SUBSECTION Private>
    14571459WebKitWebPagePrivate
    14581460webkit_web_page_get_type
     1461webkit_form_submission_step_get_type
    14591462</SECTION>
    14601463
     
    15541557<SUBSECTION Standard>
    15551558WEBKIT_TYPE_CONSOLE_MESSAGE
     1559WEBKIT_TYPE_CONSOLE_MESSAGE_LEVEL
     1560WEBKIT_TYPE_CONSOLE_MESSAGE_SOURCE
    15561561
    15571562<SUBSECTION Private>
    15581563webkit_console_message_get_type
     1564webkit_console_message_level_get_type
     1565webkit_console_message_source_get_type
    15591566</SECTION>
    15601567
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebPage.cpp

    r223953 r226366  
    5858#include "WebKitDOMDocumentPrivate.h"
    5959#include "WebKitDOMElementPrivate.h"
     60#include "WebKitDOMHTMLFormElementPrivate.h"
    6061#include "WebKitWebHitTestResultPrivate.h"
     62#include "WebKitWebProcessEnumTypes.h"
    6163#endif
    6264
     
    7375#if PLATFORM(GTK)
    7476    FORM_CONTROLS_ASSOCIATED,
     77    WILL_SUBMIT_FORM,
    7578#endif
    7679
     
    381384    }
    382385
     386    void willSubmitForm(WebPage*, HTMLFormElement* formElement, WebFrame* frame, WebFrame* sourceFrame, const Vector<std::pair<String, String>>& values, RefPtr<API::Object>&) override
     387    {
     388        fireFormSubmissionEvent(WEBKIT_FORM_SUBMISSION_WILL_COMPLETE, formElement, frame, sourceFrame, values);
     389    }
     390
     391    void willSendSubmitEvent(WebPage*, HTMLFormElement* formElement, WebFrame* frame, WebFrame* sourceFrame, const Vector<std::pair<String, String>>& values) override
     392    {
     393        fireFormSubmissionEvent(WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT, formElement, frame, sourceFrame, values);
     394    }
     395
    383396    void didAssociateFormControls(WebPage*, const Vector<RefPtr<Element>>& elements) override
    384397    {
     
    393406
    394407private:
     408    void fireFormSubmissionEvent(WebKitFormSubmissionStep step, HTMLFormElement* formElement, WebFrame* frame, WebFrame* sourceFrame, const Vector<std::pair<String, String>>& values)
     409    {
     410        WebKitFrame* webkitTargetFrame = webkitFrameGetOrCreate(frame);
     411        WebKitFrame* webkitSourceFrame = webkitFrameGetOrCreate(sourceFrame);
     412
     413        GRefPtr<GPtrArray> textFieldNames = adoptGRef(g_ptr_array_new_full(values.size(), g_free));
     414        GRefPtr<GPtrArray> textFieldValues = adoptGRef(g_ptr_array_new_full(values.size(), g_free));
     415        for (auto& pair : values) {
     416            g_ptr_array_add(textFieldNames.get(), g_strdup(pair.first.utf8().data()));
     417            g_ptr_array_add(textFieldValues.get(), g_strdup(pair.second.utf8().data()));
     418        }
     419
     420        g_signal_emit(m_webPage, signals[WILL_SUBMIT_FORM], 0, WebKit::kit(formElement), step, webkitSourceFrame, webkitTargetFrame, textFieldNames.get(), textFieldValues.get());
     421    }
     422
    395423    WebKitWebPage* m_webPage;
    396424};
     
    559587        g_cclosure_marshal_VOID__BOXED,
    560588        G_TYPE_NONE, 1,
     589        G_TYPE_PTR_ARRAY);
     590
     591    /**
     592     * WebKitWebPage::will-submit-form:
     593     * @web_page: the #WebKitWebPage on which the signal is emitted
     594     * @form: the #WebKitDOMHTMLFormElement to be submitted
     595     * @step: a #WebKitFormSubmissionEventType indicating the current
     596     * stage of form submission
     597     * @source_frame: the #WebKitFrame containing the form to be
     598     * submitted
     599     * @target_frame: the #WebKitFrame containing the form's target,
     600     * which may be the same as @source_frame if no target was specified
     601     * @text_field_names: (element-type utf8) (transfer none): names of
     602     * the form's text fields
     603     * @text_field_values: (element-type utf8) (transfer none): values
     604     * of the form's text fields
     605     *
     606     * This signal is emitted to indicate various points during form
     607     * submission. @step indicates the current stage of form submission.
     608     *
     609     * If this signal is emitted with %WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT,
     610     * then the DOM submit event is about to be emitted. JavaScript code
     611     * may rely on the submit event to detect that the user has clicked
     612     * on a submit button, and to possibly cancel the form submission
     613     * before %WEBKIT_FORM_SUBMISSION_WILL_COMPLETE. However, beware
     614     * that, for historical reasons, the submit event is not emitted at
     615     * all if the form submission is triggered by JavaScript. For these
     616     * reasons, %WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT may not
     617     * be used to reliably detect whether a form will be submitted.
     618     * Instead, use it to detect if a user has clicked on a form's
     619     * submit button even if JavaScript later cancels the form
     620     * submission, or to read the values of the form's fields even if
     621     * JavaScript later clears certain fields before submitting. This
     622     * may be needed, for example, to implement a robust browser
     623     * password manager, as some misguided websites may use such
     624     * techniques to attempt to thwart password managers.
     625     *
     626     * If this signal is emitted with %WEBKIT_FORM_SUBMISSION_WILL_COMPLETE,
     627     * the form will imminently be submitted. It can no longer be
     628     * cancelled. This event always occurs immediately before a form is
     629     * submitted to its target, so use this event to reliably detect
     630     * when a form is submitted. This event occurs after
     631     * %WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT if that event is
     632     * emitted.
     633     *
     634     * Since: 2.20
     635     */
     636    signals[WILL_SUBMIT_FORM] = g_signal_new(
     637        "will-submit-form",
     638        G_TYPE_FROM_CLASS(klass),
     639        G_SIGNAL_RUN_LAST,
     640        0, 0, nullptr,
     641        g_cclosure_marshal_generic,
     642        G_TYPE_NONE, 6,
     643        WEBKIT_DOM_TYPE_HTML_FORM_ELEMENT,
     644        WEBKIT_TYPE_FORM_SUBMISSION_STEP,
     645        WEBKIT_TYPE_FRAME,
     646        WEBKIT_TYPE_FRAME,
     647        G_TYPE_PTR_ARRAY,
    561648        G_TYPE_PTR_ARRAY);
    562649#endif
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.h

    r187024 r226366  
    4747typedef struct _WebKitWebEditor      WebKitWebEditor;
    4848
     49/**
     50 * WebKitFormSubmissionStep:
     51 * @WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT: indicates the form's
     52 * DOM submit event is about to be emitted.
     53 * @WEBKIT_FORM_SUBMISSION_WILL_COMPLETE: indicates the form is about
     54 * to be submitted.
     55 *
     56 * Used to indicate a particular stage in form submission. See
     57 * #WebKitWebPage::will-submit-form.
     58 *
     59 * Since: 2.20
     60 */
     61typedef enum {
     62    WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT,
     63    WEBKIT_FORM_SUBMISSION_WILL_COMPLETE,
     64} WebKitFormSubmissionStep;
     65
    4966struct _WebKitWebPage {
    5067    GObject parent;
  • trunk/Tools/ChangeLog

    r226365 r226366  
     12018-01-03  Michael Catanzaro  <mcatanzaro@igalia.com>
     2
     3        [GTK] Add web process API to detect when form is submitted via JavaScript
     4        https://bugs.webkit.org/show_bug.cgi?id=173915
     5
     6        Reviewed by Carlos Garcia Campos.
     7
     8        Test it.
     9
     10        * TestWebKitAPI/Tests/WebKitGLib/TestWebExtensions.cpp:
     11        (FormSubmissionTest::FormSubmissionTest):
     12        (FormSubmissionTest::~FormSubmissionTest):
     13        (FormSubmissionTest::testFormSubmissionResult):
     14        (FormSubmissionTest::willSendDOMEventCallback):
     15        (FormSubmissionTest::willCompleteCallback):
     16        (FormSubmissionTest::runJavaScriptAndWaitUntilFormSubmitted):
     17        (testWebExtensionFormSubmissionSteps):
     18        (beforeAll):
     19        * TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp:
     20        (DelayedSignal::DelayedSignal):
     21        (emitFormSubmissionEvent):
     22        (handleFormSubmissionCallback):
     23        (willSubmitFormCallback):
     24        (pageCreatedCallback):
     25
    1262018-01-03  Michael Catanzaro  <mcatanzaro@igalia.com>
    227
  • trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebExtensions.cpp

    r226326 r226366  
    3131#define FORM2_ID "form2-id"
    3232
     33#define FORM_SUBMISSION_TEST_ID "form-submission-test-id"
     34
    3335#if PLATFORM(GTK)
    3436static void testWebExtensionGetTitle(WebViewTest* test, gconstpointer)
     
    278280    g_dbus_connection_signal_unsubscribe(connection, id);
    279281}
     282
     283class FormSubmissionTest : public WebViewTest {
     284public:
     285    MAKE_GLIB_TEST_FIXTURE(FormSubmissionTest);
     286
     287    FormSubmissionTest()
     288    {
     289        GUniquePtr<char> extensionBusName(g_strdup_printf("org.webkit.gtk.WebExtensionTest%u", s_webExtensionID));
     290        m_proxy = adoptGRef(bus->createProxy(extensionBusName.get(),
     291            "/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", m_mainLoop));
     292        GDBusConnection* connection = g_dbus_proxy_get_connection(m_proxy.get());
     293
     294        m_willSendDOMEventCallbackID = g_dbus_connection_signal_subscribe(connection,
     295            nullptr,
     296            "org.webkit.gtk.WebExtensionTest",
     297            "FormSubmissionWillSendDOMEvent",
     298            "/org/webkit/gtk/WebExtensionTest",
     299            nullptr,
     300            G_DBUS_SIGNAL_FLAGS_NONE,
     301            reinterpret_cast<GDBusSignalCallback>(willSendDOMEventCallback),
     302            this,
     303            nullptr);
     304        g_assert(m_willSendDOMEventCallbackID);
     305
     306        m_willCompleteCallbackID = g_dbus_connection_signal_subscribe(connection,
     307            nullptr,
     308            "org.webkit.gtk.WebExtensionTest",
     309            "FormSubmissionWillComplete",
     310            "/org/webkit/gtk/WebExtensionTest",
     311            nullptr,
     312            G_DBUS_SIGNAL_FLAGS_NONE,
     313            reinterpret_cast<GDBusSignalCallback>(willCompleteCallback),
     314            this,
     315            nullptr);
     316        g_assert(m_willCompleteCallbackID);
     317    }
     318
     319    ~FormSubmissionTest()
     320    {
     321        GDBusConnection* connection = g_dbus_proxy_get_connection(m_proxy.get());
     322        g_dbus_connection_signal_unsubscribe(connection, m_willSendDOMEventCallbackID);
     323        g_dbus_connection_signal_unsubscribe(connection, m_willCompleteCallbackID);
     324    }
     325
     326    static void testFormSubmissionResult(GVariant* result)
     327    {
     328        const char* formID;
     329        const char* concatenatedTextFieldNames;
     330        const char* concatenatedTextFieldValues;
     331        gboolean targetFrameIsMainFrame;
     332        gboolean sourceFrameIsMainFrame;
     333        g_variant_get(result, "(&s&s&sbb)", &formID, &concatenatedTextFieldNames, &concatenatedTextFieldValues, &targetFrameIsMainFrame, &sourceFrameIsMainFrame);
     334
     335        g_assert_cmpstr(formID, ==, FORM_SUBMISSION_TEST_ID);
     336        g_assert_cmpstr(concatenatedTextFieldNames, ==, "foo,bar,");
     337        g_assert_cmpstr(concatenatedTextFieldValues, ==, "first,second,");
     338        g_assert(!targetFrameIsMainFrame);
     339        g_assert(sourceFrameIsMainFrame);
     340    }
     341
     342    static void willSendDOMEventCallback(GDBusConnection*, const char*, const char*, const char*, const char*, GVariant* result, FormSubmissionTest* test)
     343    {
     344        test->m_willSendDOMEventCallbackExecuted = true;
     345        testFormSubmissionResult(result);
     346    }
     347
     348    static void willCompleteCallback(GDBusConnection*, const char*, const char*, const char*, const char*, GVariant* result, FormSubmissionTest* test)
     349    {
     350        test->m_willCompleteCallbackExecuted = true;
     351        testFormSubmissionResult(result);
     352        test->quitMainLoop();
     353    }
     354
     355    void runJavaScriptAndWaitUntilFormSubmitted(const char* js)
     356    {
     357        webkit_web_view_run_javascript(m_webView, js, nullptr, nullptr, nullptr);
     358        g_main_loop_run(m_mainLoop);
     359    }
     360
     361    GRefPtr<GDBusProxy> m_proxy;
     362    guint m_willSendDOMEventCallbackID { 0 };
     363    guint m_willCompleteCallbackID { 0 };
     364    bool m_willSendDOMEventCallbackExecuted { false };
     365    bool m_willCompleteCallbackExecuted { false };
     366};
     367
     368static void testWebExtensionFormSubmissionSteps(FormSubmissionTest* test, gconstpointer)
     369{
     370    test->loadHtml("<form id=\"" FORM_SUBMISSION_TEST_ID "\" target=\"target_frame\">"
     371        "<input type=\"text\" name=\"foo\" value=\"first\">"
     372        "<input type=\"text\" name=\"bar\" value=\"second\">"
     373        "<input type=\"submit\" id=\"submit_button\">"
     374        "</form>"
     375        "<iframe name=\"target_frame\"></iframe>", nullptr);
     376    test->waitUntilLoadFinished();
     377
     378    static const char* submitFormScript =
     379        "var form = document.getElementById(\"" FORM_SUBMISSION_TEST_ID "\");"
     380        "form.submit();";
     381    test->runJavaScriptAndWaitUntilFormSubmitted(submitFormScript);
     382    // Submit must not be emitted when the form is submitted via JS.
     383    // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
     384    g_assert(!test->m_willSendDOMEventCallbackExecuted);
     385    g_assert(test->m_willCompleteCallbackExecuted);
     386    test->m_willCompleteCallbackExecuted = false;
     387
     388    static const char* manuallySubmitFormScript =
     389        "var button = document.getElementById(\"submit_button\");"
     390        "button.click();";
     391    test->runJavaScriptAndWaitUntilFormSubmitted(manuallySubmitFormScript);
     392    g_assert(test->m_willSendDOMEventCallbackExecuted);
     393    g_assert(test->m_willCompleteCallbackExecuted);
     394    test->m_willSendDOMEventCallbackExecuted = false;
     395    test->m_willCompleteCallbackExecuted = false;
     396
     397    test->loadHtml("<form id=\"" FORM_SUBMISSION_TEST_ID "\" target=\"target_frame\">"
     398        "</form>"
     399        "<iframe name=\"target_frame\"></iframe>", nullptr);
     400    test->waitUntilLoadFinished();
     401}
    280402#endif // PLATFORM(GTK)
    281403
     
    297419    WebViewTest::add("WebKitWebView", "install-missing-plugins-permission-request", testInstallMissingPluginsPermissionRequest);
    298420    WebViewTest::add("WebKitWebExtension", "form-controls-associated-signal", testWebExtensionFormControlsAssociated);
     421    FormSubmissionTest::add("WebKitWebExtension", "form-submission-steps", testWebExtensionFormSubmissionSteps);
    299422#endif
    300423}
  • trunk/Tools/TestWebKitAPI/Tests/WebKitGLib/WebExtensionTest.cpp

    r220403 r226366  
    6262    "   <arg type='s' name='formIds' direction='out'/>"
    6363    "  </signal>"
     64    "  <signal name='FormSubmissionWillSendDOMEvent'>"
     65    "    <arg type='s' name='formID' direction='out'/>"
     66    "    <arg type='s' name='textFieldNames' direction='out'/>"
     67    "    <arg type='s' name='textFieldValues' direction='out'/>"
     68    "    <arg type='b' name='targetFrameIsMainFrame' direction='out'/>"
     69    "    <arg type='b' name='sourceFrameIsMainFrame' direction='out'/>"
     70    "  </signal>"
     71    "  <signal name='FormSubmissionWillComplete'>"
     72    "    <arg type='s' name='formID' direction='out'/>"
     73    "    <arg type='s' name='textFieldNames' direction='out'/>"
     74    "    <arg type='s' name='textFieldValues' direction='out'/>"
     75    "    <arg type='b' name='targetFrameIsMainFrame' direction='out'/>"
     76    "    <arg type='b' name='sourceFrameIsMainFrame' direction='out'/>"
     77    "  </signal>"
    6478    "  <signal name='URIChanged'>"
    6579    "   <arg type='s' name='uri' direction='out'/>"
     
    7286    DocumentLoadedSignal,
    7387    URIChangedSignal,
     88#if PLATFORM(GTK)
    7489    FormControlsAssociatedSignal,
     90    FormSubmissionWillSendDOMEventSignal,
     91    FormSubmissionWillCompleteSignal,
     92#endif
    7593} DelayedSignalType;
    7694
    7795struct DelayedSignal {
    78     DelayedSignal(DelayedSignalType type)
     96    explicit DelayedSignal(DelayedSignalType type)
    7997        : type(type)
    8098    {
     
    87105    }
    88106
     107    DelayedSignal(DelayedSignalType type, const char* str, const char* str2, const char* str3, gboolean b, gboolean b2)
     108        : type(type)
     109        , str(str)
     110        , str2(str2)
     111        , str3(str3)
     112        , b(b)
     113        , b2(b2)
     114    {
     115    }
     116
    89117    DelayedSignalType type;
    90118    CString str;
     119    CString str2;
     120    CString str3;
     121    gboolean b;
     122    gboolean b2;
    91123};
    92124
     
    309341        delayedSignalsQueue.append(DelayedSignal(FormControlsAssociatedSignal, formIds.get()));
    310342}
     343
     344static void emitFormSubmissionEvent(GDBusConnection* connection, const char* methodName, const char* formID, const char* names, const char* values, gboolean targetFrameIsMainFrame, gboolean sourceFrameIsMainFrame)
     345{
     346    bool ok = g_dbus_connection_emit_signal(
     347        connection,
     348        nullptr,
     349        "/org/webkit/gtk/WebExtensionTest",
     350        "org.webkit.gtk.WebExtensionTest",
     351        methodName,
     352        g_variant_new("(sssbb)", formID, names, values, targetFrameIsMainFrame, sourceFrameIsMainFrame),
     353        nullptr);
     354    g_assert(ok);
     355}
     356
     357static void handleFormSubmissionCallback(WebKitWebPage* webPage, DelayedSignalType delayedSignalType, const char* methodName, WebKitDOMHTMLFormElement* formElement, WebKitFrame* sourceFrame, WebKitFrame* targetFrame, GPtrArray* textFieldNames, GPtrArray* textFieldValues, WebKitWebExtension* extension)
     358{
     359    GString* namesBuilder = g_string_new(nullptr);
     360    for (guint i = 0; i < textFieldNames->len; ++i) {
     361        auto* name = static_cast<char*>(g_ptr_array_index(textFieldNames, i));
     362        g_string_append(namesBuilder, name);
     363        g_string_append_c(namesBuilder, ',');
     364    }
     365    GUniquePtr<char> names(g_string_free(namesBuilder, FALSE));
     366
     367    GString* valuesBuilder = g_string_new(nullptr);
     368    for (guint i = 0; i < textFieldValues->len; ++i) {
     369        auto* value = static_cast<char*>(g_ptr_array_index(textFieldValues, i));
     370        g_string_append(valuesBuilder, value);
     371        g_string_append_c(valuesBuilder, ',');
     372    }
     373    GUniquePtr<char> values(g_string_free(valuesBuilder, FALSE));
     374
     375    gpointer data = g_object_get_data(G_OBJECT(extension), "dbus-connection");
     376    if (data)
     377        emitFormSubmissionEvent(G_DBUS_CONNECTION(data), methodName, webkit_dom_element_get_id(WEBKIT_DOM_ELEMENT(formElement)), names.get(), values.get(), webkit_frame_is_main_frame(targetFrame), webkit_frame_is_main_frame(sourceFrame));
     378    else
     379        delayedSignalsQueue.append(DelayedSignal(delayedSignalType, webkit_dom_element_get_id(WEBKIT_DOM_ELEMENT(formElement)), names.get(), values.get(), webkit_frame_is_main_frame(targetFrame), webkit_frame_is_main_frame(sourceFrame)));
     380}
     381
     382static void willSubmitFormCallback(WebKitWebPage* webPage, WebKitDOMHTMLFormElement* formElement, WebKitFormSubmissionStep step, WebKitFrame* sourceFrame, WebKitFrame* targetFrame, GPtrArray* textFieldNames, GPtrArray* textFieldValues, WebKitWebExtension* extension)
     383{
     384    switch (step) {
     385    case WEBKIT_FORM_SUBMISSION_WILL_SEND_DOM_EVENT:
     386        handleFormSubmissionCallback(webPage, FormSubmissionWillSendDOMEventSignal, "FormSubmissionWillSendDOMEvent", formElement, sourceFrame, targetFrame, textFieldNames, textFieldValues, extension);
     387        break;
     388    case WEBKIT_FORM_SUBMISSION_WILL_COMPLETE:
     389        handleFormSubmissionCallback(webPage, FormSubmissionWillCompleteSignal, "FormSubmissionWillComplete", formElement, sourceFrame, targetFrame, textFieldNames, textFieldValues, extension);
     390        break;
     391    default:
     392        g_assert_not_reached();
     393    }
     394}
    311395#endif
    312396
     
    320404    g_signal_connect(webPage, "context-menu", G_CALLBACK(contextMenuCallback), nullptr);
    321405    g_signal_connect(webPage, "form-controls-associated", G_CALLBACK(formControlsAssociatedCallback), extension);
     406    g_signal_connect(webPage, "will-submit-form", G_CALLBACK(willSubmitFormCallback), extension);
    322407#endif
    323408}
     
    446531            emitURIChanged(connection, delayedSignal.str.data());
    447532            break;
     533#if PLATFORM(GTK)
    448534        case FormControlsAssociatedSignal:
    449 #if PLATFORM(GTK)
    450535            emitFormControlsAssociated(connection, delayedSignal.str.data());
    451 #elif PLATFORM(WPE)
     536            break;
     537        case FormSubmissionWillCompleteSignal:
     538            emitFormSubmissionEvent(connection, "FormSubmissionWillComplete", delayedSignal.str.data(), delayedSignal.str2.data(), delayedSignal.str3.data(), delayedSignal.b, delayedSignal.b2);
     539            break;
     540        case FormSubmissionWillSendDOMEventSignal:
     541            emitFormSubmissionEvent(connection, "FormSubmissionWillSendDOMEvent", delayedSignal.str.data(), delayedSignal.str2.data(), delayedSignal.str3.data(), delayedSignal.b, delayedSignal.b2);
     542            break;
     543#endif
    452544            g_assert_not_reached();
    453 #endif
    454             break;
    455545        }
    456546    }
Note: See TracChangeset for help on using the changeset viewer.