[Cairo] Refactor PlatformContextCairo::drawSurfaceToContext() into a Cairo operation
[WebKit-https.git] / Source / WebDriver / Session.cpp
1 /*
2  * Copyright (C) 2017 Igalia S.L.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "Session.h"
28
29 #include "CommandResult.h"
30 #include "SessionHost.h"
31 #include "WebDriverAtoms.h"
32 #include <wtf/CryptographicallyRandomNumber.h>
33 #include <wtf/HexNumber.h>
34 #include <wtf/UUID.h>
35
36 namespace WebDriver {
37
38 // The web element identifier is a constant defined by the spec in Section 11 Elements.
39 // https://www.w3.org/TR/webdriver/#elements
40 static const String webElementIdentifier = ASCIILiteral("element-6066-11e4-a52e-4f735466cecf");
41
42 // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-session-script-timeout
43 static const Seconds defaultScriptTimeout = 30_s;
44 // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-session-page-load-timeout
45 static const Seconds defaultPageLoadTimeout = 300_s;
46 // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-session-implicit-wait-timeout
47 static const Seconds defaultImplicitWaitTimeout = 0_s;
48
49 Session::Session(std::unique_ptr<SessionHost>&& host)
50     : m_host(WTFMove(host))
51     , m_id(createCanonicalUUIDString())
52     , m_scriptTimeout(defaultScriptTimeout)
53     , m_pageLoadTimeout(defaultPageLoadTimeout)
54     , m_implicitWaitTimeout(defaultImplicitWaitTimeout)
55 {
56 }
57
58 Session::~Session()
59 {
60 }
61
62 const Capabilities& Session::capabilities() const
63 {
64     return m_host->capabilities();
65 }
66
67 static std::optional<String> firstWindowHandleInResult(JSON::Value& result)
68 {
69     RefPtr<JSON::Array> handles;
70     if (result.asArray(handles) && handles->length()) {
71         auto handleValue = handles->get(0);
72         String handle;
73         if (handleValue->asString(handle))
74             return handle;
75     }
76     return std::nullopt;
77 }
78
79 void Session::closeAllToplevelBrowsingContexts(const String& toplevelBrowsingContext, Function<void (CommandResult&&)>&& completionHandler)
80 {
81     closeTopLevelBrowsingContext(toplevelBrowsingContext, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
82         if (result.isError()) {
83             completionHandler(WTFMove(result));
84             return;
85         }
86         if (auto handle = firstWindowHandleInResult(*result.result())) {
87             closeAllToplevelBrowsingContexts(handle.value(), WTFMove(completionHandler));
88             return;
89         }
90         completionHandler(CommandResult::success());
91     });
92 }
93
94 void Session::close(Function<void (CommandResult&&)>&& completionHandler)
95 {
96     m_toplevelBrowsingContext = std::nullopt;
97     getWindowHandles([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
98         if (result.isError()) {
99             completionHandler(WTFMove(result));
100             return;
101         }
102         if (auto handle = firstWindowHandleInResult(*result.result())) {
103             closeAllToplevelBrowsingContexts(handle.value(), WTFMove(completionHandler));
104             return;
105         }
106         completionHandler(CommandResult::success());
107     });
108 }
109
110 void Session::getTimeouts(Function<void (CommandResult&&)>&& completionHandler)
111 {
112     RefPtr<JSON::Object> parameters = JSON::Object::create();
113     parameters->setInteger(ASCIILiteral("script"), m_scriptTimeout.millisecondsAs<int>());
114     parameters->setInteger(ASCIILiteral("pageLoad"), m_pageLoadTimeout.millisecondsAs<int>());
115     parameters->setInteger(ASCIILiteral("implicit"), m_implicitWaitTimeout.millisecondsAs<int>());
116     completionHandler(CommandResult::success(WTFMove(parameters)));
117 }
118
119 void Session::setTimeouts(const Timeouts& timeouts, Function<void (CommandResult&&)>&& completionHandler)
120 {
121     if (timeouts.script)
122         m_scriptTimeout = timeouts.script.value();
123     if (timeouts.pageLoad)
124         m_pageLoadTimeout = timeouts.pageLoad.value();
125     if (timeouts.implicit)
126         m_implicitWaitTimeout = timeouts.implicit.value();
127     completionHandler(CommandResult::success());
128 }
129
130 void Session::switchToTopLevelBrowsingContext(std::optional<String> toplevelBrowsingContext)
131 {
132     m_toplevelBrowsingContext = toplevelBrowsingContext;
133     m_currentBrowsingContext = std::nullopt;
134 }
135
136 void Session::switchToBrowsingContext(std::optional<String> browsingContext)
137 {
138     // Automation sends empty strings for main frame.
139     if (!browsingContext || browsingContext.value().isEmpty())
140         m_currentBrowsingContext = std::nullopt;
141     else
142         m_currentBrowsingContext = browsingContext;
143 }
144
145 std::optional<String> Session::pageLoadStrategyString() const
146 {
147     if (!capabilities().pageLoadStrategy)
148         return std::nullopt;
149
150     switch (capabilities().pageLoadStrategy.value()) {
151     case PageLoadStrategy::None:
152         return String("None");
153     case PageLoadStrategy::Normal:
154         return String("Normal");
155     case PageLoadStrategy::Eager:
156         return String("Eager");
157     }
158
159     return std::nullopt;
160 }
161
162 void Session::createTopLevelBrowsingContext(Function<void (CommandResult&&)>&& completionHandler)
163 {
164     ASSERT(!m_toplevelBrowsingContext.value());
165     m_host->startAutomationSession(m_id, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<String> errorMessage) mutable {
166         if (errorMessage) {
167             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError, errorMessage.value()));
168             return;
169         }
170         m_host->sendCommandToBackend(ASCIILiteral("createBrowsingContext"), nullptr, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
171             if (response.isError || !response.responseObject) {
172                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
173                 return;
174             }
175             String handle;
176             if (!response.responseObject->getString(ASCIILiteral("handle"), handle)) {
177                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
178                 return;
179             }
180             switchToTopLevelBrowsingContext(handle);
181             completionHandler(CommandResult::success());
182         });
183     });
184 }
185
186 void Session::handleUserPrompts(Function<void (CommandResult&&)>&& completionHandler)
187 {
188     RefPtr<JSON::Object> parameters = JSON::Object::create();
189     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
190     m_host->sendCommandToBackend(ASCIILiteral("isShowingJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
191         if (response.isError || !response.responseObject) {
192             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
193             return;
194         }
195         bool isShowingJavaScriptDialog;
196         if (!response.responseObject->getBoolean("result", isShowingJavaScriptDialog)) {
197             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
198             return;
199         }
200
201         if (!isShowingJavaScriptDialog) {
202             completionHandler(CommandResult::success());
203             return;
204         }
205
206         handleUnexpectedAlertOpen(WTFMove(completionHandler));
207     });
208 }
209
210 void Session::handleUnexpectedAlertOpen(Function<void (CommandResult&&)>&& completionHandler)
211 {
212     switch (capabilities().unhandledPromptBehavior.value_or(UnhandledPromptBehavior::DismissAndNotify)) {
213     case UnhandledPromptBehavior::Dismiss:
214         dismissAlert(WTFMove(completionHandler));
215         break;
216     case UnhandledPromptBehavior::Accept:
217         acceptAlert(WTFMove(completionHandler));
218         break;
219     case UnhandledPromptBehavior::DismissAndNotify:
220         dismissAndNotifyAlert(WTFMove(completionHandler));
221         break;
222     case UnhandledPromptBehavior::AcceptAndNotify:
223         acceptAndNotifyAlert(WTFMove(completionHandler));
224         break;
225     case UnhandledPromptBehavior::Ignore:
226         reportUnexpectedAlertOpen(WTFMove(completionHandler));
227         break;
228     }
229 }
230
231 void Session::dismissAndNotifyAlert(Function<void (CommandResult&&)>&& completionHandler)
232 {
233     reportUnexpectedAlertOpen([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
234         dismissAlert([this, errorResult = WTFMove(result), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
235             if (result.isError()) {
236                 completionHandler(WTFMove(result));
237                 return;
238             }
239             completionHandler(WTFMove(errorResult));
240         });
241     });
242 }
243
244 void Session::acceptAndNotifyAlert(Function<void (CommandResult&&)>&& completionHandler)
245 {
246     reportUnexpectedAlertOpen([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
247         acceptAlert([this, errorResult = WTFMove(result), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
248             if (result.isError()) {
249                 completionHandler(WTFMove(result));
250                 return;
251             }
252             completionHandler(WTFMove(errorResult));
253         });
254     });
255 }
256
257 void Session::reportUnexpectedAlertOpen(Function<void (CommandResult&&)>&& completionHandler)
258 {
259     getAlertText([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) {
260         std::optional<String> alertText;
261         if (!result.isError()) {
262             String valueString;
263             if (result.result()->asString(valueString))
264                 alertText = valueString;
265         }
266         auto errorResult = CommandResult::fail(CommandResult::ErrorCode::UnexpectedAlertOpen);
267         if (alertText) {
268             RefPtr<JSON::Object> additonalData = JSON::Object::create();
269             additonalData->setString(ASCIILiteral("text"), alertText.value());
270             errorResult.setAdditionalErrorData(WTFMove(additonalData));
271         }
272         completionHandler(WTFMove(errorResult));
273     });
274 }
275
276 void Session::go(const String& url, Function<void (CommandResult&&)>&& completionHandler)
277 {
278     if (!m_toplevelBrowsingContext) {
279         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
280         return;
281     }
282
283     handleUserPrompts([this, url, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
284         if (result.isError()) {
285             completionHandler(WTFMove(result));
286             return;
287         }
288
289         RefPtr<JSON::Object> parameters = JSON::Object::create();
290         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
291         parameters->setString(ASCIILiteral("url"), url);
292         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_pageLoadTimeout.millisecondsAs<int>());
293         if (auto pageLoadStrategy = pageLoadStrategyString())
294             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
295         m_host->sendCommandToBackend(ASCIILiteral("navigateBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
296             if (response.isError) {
297                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
298                 return;
299             }
300             switchToBrowsingContext(std::nullopt);
301             completionHandler(CommandResult::success());
302         });
303     });
304 }
305
306 void Session::getCurrentURL(Function<void (CommandResult&&)>&& completionHandler)
307 {
308     if (!m_toplevelBrowsingContext) {
309         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
310         return;
311     }
312
313     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
314         if (result.isError()) {
315             completionHandler(WTFMove(result));
316             return;
317         }
318
319         RefPtr<JSON::Object> parameters = JSON::Object::create();
320         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
321         m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
322             if (response.isError || !response.responseObject) {
323                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
324                 return;
325             }
326             RefPtr<JSON::Object> browsingContext;
327             if (!response.responseObject->getObject("context", browsingContext)) {
328                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
329                 return;
330             }
331             String url;
332             if (!browsingContext->getString("url", url)) {
333                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
334                 return;
335             }
336             completionHandler(CommandResult::success(JSON::Value::create(url)));
337         });
338     });
339 }
340
341 void Session::back(Function<void (CommandResult&&)>&& completionHandler)
342 {
343     if (!m_toplevelBrowsingContext) {
344         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
345         return;
346     }
347
348     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
349         if (result.isError()) {
350             completionHandler(WTFMove(result));
351             return;
352         }
353         RefPtr<JSON::Object> parameters = JSON::Object::create();
354         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
355         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_pageLoadTimeout.millisecondsAs<int>());
356         if (auto pageLoadStrategy = pageLoadStrategyString())
357             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
358         m_host->sendCommandToBackend(ASCIILiteral("goBackInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
359             if (response.isError) {
360                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
361                 return;
362             }
363             switchToBrowsingContext(std::nullopt);
364             completionHandler(CommandResult::success());
365         });
366     });
367 }
368
369 void Session::forward(Function<void (CommandResult&&)>&& completionHandler)
370 {
371     if (!m_toplevelBrowsingContext) {
372         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
373         return;
374     }
375
376     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
377         if (result.isError()) {
378             completionHandler(WTFMove(result));
379             return;
380         }
381         RefPtr<JSON::Object> parameters = JSON::Object::create();
382         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
383         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_pageLoadTimeout.millisecondsAs<int>());
384         if (auto pageLoadStrategy = pageLoadStrategyString())
385             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
386         m_host->sendCommandToBackend(ASCIILiteral("goForwardInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
387             if (response.isError) {
388                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
389                 return;
390             }
391             switchToBrowsingContext(std::nullopt);
392             completionHandler(CommandResult::success());
393         });
394     });
395 }
396
397 void Session::refresh(Function<void (CommandResult&&)>&& completionHandler)
398 {
399     if (!m_toplevelBrowsingContext) {
400         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
401         return;
402     }
403
404     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
405         if (result.isError()) {
406             completionHandler(WTFMove(result));
407             return;
408         }
409         RefPtr<JSON::Object> parameters = JSON::Object::create();
410         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
411         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_pageLoadTimeout.millisecondsAs<int>());
412         if (auto pageLoadStrategy = pageLoadStrategyString())
413             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
414         m_host->sendCommandToBackend(ASCIILiteral("reloadBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
415             if (response.isError) {
416                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
417                 return;
418             }
419             switchToBrowsingContext(std::nullopt);
420             completionHandler(CommandResult::success());
421         });
422     });
423 }
424
425 void Session::getTitle(Function<void (CommandResult&&)>&& completionHandler)
426 {
427     if (!m_toplevelBrowsingContext) {
428         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
429         return;
430     }
431
432     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
433         if (result.isError()) {
434             completionHandler(WTFMove(result));
435             return;
436         }
437         RefPtr<JSON::Object> parameters = JSON::Object::create();
438         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
439         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function() { return document.title; }"));
440         parameters->setArray(ASCIILiteral("arguments"), JSON::Array::create());
441         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
442             if (response.isError || !response.responseObject) {
443                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
444                 return;
445             }
446             String valueString;
447             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
448                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
449                 return;
450             }
451             RefPtr<JSON::Value> resultValue;
452             if (!JSON::Value::parseJSON(valueString, resultValue)) {
453                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
454                 return;
455             }
456             completionHandler(CommandResult::success(WTFMove(resultValue)));
457         });
458     });
459 }
460
461 void Session::getWindowHandle(Function<void (CommandResult&&)>&& completionHandler)
462 {
463     if (!m_toplevelBrowsingContext) {
464         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
465         return;
466     }
467
468     RefPtr<JSON::Object> parameters = JSON::Object::create();
469     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
470     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
471         if (response.isError || !response.responseObject) {
472             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
473             return;
474         }
475         RefPtr<JSON::Object> browsingContext;
476         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
477             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
478             return;
479         }
480         String handle;
481         if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
482             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
483             return;
484         }
485         completionHandler(CommandResult::success(JSON::Value::create(handle)));
486     });
487 }
488
489 void Session::closeTopLevelBrowsingContext(const String& toplevelBrowsingContext, Function<void (CommandResult&&)>&& completionHandler)
490 {
491     RefPtr<JSON::Object> parameters = JSON::Object::create();
492     parameters->setString(ASCIILiteral("handle"), toplevelBrowsingContext);
493     m_host->sendCommandToBackend(ASCIILiteral("closeBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
494         if (!m_host->isConnected()) {
495             // Closing the browsing context made the browser quit.
496             completionHandler(CommandResult::success(JSON::Array::create()));
497             return;
498         }
499         if (response.isError) {
500             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
501             return;
502         }
503
504         getWindowHandles([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) {
505             if (!m_host->isConnected()) {
506                 // Closing the browsing context made the browser quit.
507                 completionHandler(CommandResult::success(JSON::Array::create()));
508                 return;
509             }
510             completionHandler(WTFMove(result));
511         });
512     });
513 }
514
515 void Session::closeWindow(Function<void (CommandResult&&)>&& completionHandler)
516 {
517     if (!m_toplevelBrowsingContext) {
518         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
519         return;
520     }
521
522     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
523         if (result.isError()) {
524             completionHandler(WTFMove(result));
525             return;
526         }
527         auto toplevelBrowsingContext = std::exchange(m_toplevelBrowsingContext, std::nullopt);
528         closeTopLevelBrowsingContext(toplevelBrowsingContext.value(), WTFMove(completionHandler));
529     });
530 }
531
532 void Session::switchToWindow(const String& windowHandle, Function<void (CommandResult&&)>&& completionHandler)
533 {
534     RefPtr<JSON::Object> parameters = JSON::Object::create();
535     parameters->setString(ASCIILiteral("browsingContextHandle"), windowHandle);
536     m_host->sendCommandToBackend(ASCIILiteral("switchToBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), windowHandle, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
537         if (response.isError) {
538             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
539             return;
540         }
541         switchToTopLevelBrowsingContext(windowHandle);
542         completionHandler(CommandResult::success());
543     });
544 }
545
546 void Session::getWindowHandles(Function<void (CommandResult&&)>&& completionHandler)
547 {
548     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContexts"), JSON::Object::create(), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
549         if (response.isError || !response.responseObject) {
550             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
551             return;
552         }
553         RefPtr<JSON::Array> browsingContextArray;
554         if (!response.responseObject->getArray(ASCIILiteral("contexts"), browsingContextArray)) {
555             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
556             return;
557         }
558         RefPtr<JSON::Array> windowHandles = JSON::Array::create();
559         for (unsigned i = 0; i < browsingContextArray->length(); ++i) {
560             RefPtr<JSON::Value> browsingContextValue = browsingContextArray->get(i);
561             RefPtr<JSON::Object> browsingContext;
562             if (!browsingContextValue->asObject(browsingContext)) {
563                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
564                 return;
565             }
566
567             String handle;
568             if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
569                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
570                 return;
571             }
572
573             windowHandles->pushString(handle);
574         }
575         completionHandler(CommandResult::success(WTFMove(windowHandles)));
576     });
577 }
578
579 void Session::switchToFrame(RefPtr<JSON::Value>&& frameID, Function<void (CommandResult&&)>&& completionHandler)
580 {
581     if (!m_toplevelBrowsingContext) {
582         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
583         return;
584     }
585
586     if (frameID->isNull()) {
587         switchToBrowsingContext(std::nullopt);
588         completionHandler(CommandResult::success());
589         return;
590     }
591
592     handleUserPrompts([this, frameID = WTFMove(frameID), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
593         if (result.isError()) {
594             completionHandler(WTFMove(result));
595             return;
596         }
597         RefPtr<JSON::Object> parameters = JSON::Object::create();
598         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
599         if (m_currentBrowsingContext)
600             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
601
602         int frameIndex;
603         if (frameID->asInteger(frameIndex)) {
604             if (frameIndex < 0 || frameIndex > USHRT_MAX) {
605                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
606                 return;
607             }
608             parameters->setInteger(ASCIILiteral("ordinal"), frameIndex);
609         } else {
610             String frameElementID = extractElementID(*frameID);
611             if (!frameElementID.isEmpty())
612                 parameters->setString(ASCIILiteral("nodeHandle"), frameElementID);
613             else {
614                 String frameName;
615                 if (!frameID->asString(frameName)) {
616                     completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
617                     return;
618                 }
619                 parameters->setString(ASCIILiteral("name"), frameName);
620             }
621         }
622
623         m_host->sendCommandToBackend(ASCIILiteral("resolveChildFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
624             if (response.isError || !response.responseObject) {
625                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
626                 return;
627             }
628             String frameHandle;
629             if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
630                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
631                 return;
632             }
633             switchToBrowsingContext(frameHandle);
634             completionHandler(CommandResult::success());
635         });
636     });
637 }
638
639 void Session::switchToParentFrame(Function<void (CommandResult&&)>&& completionHandler)
640 {
641     if (!m_toplevelBrowsingContext) {
642         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
643         return;
644     }
645
646     if (!m_currentBrowsingContext) {
647         completionHandler(CommandResult::success());
648         return;
649     }
650
651     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
652         if (result.isError()) {
653             completionHandler(WTFMove(result));
654             return;
655         }
656         RefPtr<JSON::Object> parameters = JSON::Object::create();
657         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
658         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
659         m_host->sendCommandToBackend(ASCIILiteral("resolveParentFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
660             if (response.isError || !response.responseObject) {
661                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
662                 return;
663             }
664             String frameHandle;
665             if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
666                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
667                 return;
668             }
669             switchToBrowsingContext(frameHandle);
670             completionHandler(CommandResult::success());
671         });
672     });
673 }
674
675 void Session::getToplevelBrowsingContextRect(Function<void (CommandResult&&)>&& completionHandler)
676 {
677     RefPtr<JSON::Object> parameters = JSON::Object::create();
678     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
679     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
680         if (response.isError || !response.responseObject) {
681             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
682             return;
683         }
684         RefPtr<JSON::Object> browsingContext;
685         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
686             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
687             return;
688         }
689         RefPtr<JSON::Object> windowOrigin;
690         double x, y;
691         if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)
692             || !windowOrigin->getDouble(ASCIILiteral("x"), x)
693             || !windowOrigin->getDouble(ASCIILiteral("y"), y)) {
694             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
695             return;
696         }
697         RefPtr<JSON::Object> windowSize;
698         double width, height;
699         if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)
700             || !windowSize->getDouble(ASCIILiteral("width"), width)
701             || !windowSize->getDouble(ASCIILiteral("height"), width)) {
702             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
703             return;
704         }
705         auto windowRect = JSON::Object::create();
706         windowRect->setDouble(ASCIILiteral("x"), x);
707         windowRect->setDouble(ASCIILiteral("y"), y);
708         windowRect->setDouble(ASCIILiteral("width"), width);
709         windowRect->setDouble(ASCIILiteral("height"), height);
710         completionHandler(CommandResult::success(WTFMove(windowRect)));
711     });
712 }
713
714 void Session::moveToplevelBrowsingContextWindow(double x, double y, Function<void (CommandResult&&)>&& completionHandler)
715 {
716     RefPtr<JSON::Object> parameters = JSON::Object::create();
717     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
718     RefPtr<JSON::Object> windowOrigin = JSON::Object::create();
719     windowOrigin->setDouble("x", x);
720     windowOrigin->setDouble("y", y);
721     parameters->setObject(ASCIILiteral("origin"), WTFMove(windowOrigin));
722     m_host->sendCommandToBackend(ASCIILiteral("moveWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
723         if (response.isError) {
724             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
725             return;
726         }
727         completionHandler(CommandResult::success());
728     });
729 }
730
731 void Session::resizeToplevelBrowsingContextWindow(double width, double height, Function<void (CommandResult&&)>&& completionHandler)
732 {
733     RefPtr<JSON::Object> parameters = JSON::Object::create();
734     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
735     RefPtr<JSON::Object> windowSize = JSON::Object::create();
736     windowSize->setDouble("width", width);
737     windowSize->setDouble("height", height);
738     parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize));
739     m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
740         if (response.isError) {
741             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
742             return;
743         }
744         completionHandler(CommandResult::success());
745     });
746 }
747
748 void Session::getWindowRect(Function<void (CommandResult&&)>&& completionHandler)
749 {
750     if (!m_toplevelBrowsingContext) {
751         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
752         return;
753     }
754
755     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
756         if (result.isError()) {
757             completionHandler(WTFMove(result));
758             return;
759         }
760         getToplevelBrowsingContextRect(WTFMove(completionHandler));
761     });
762 }
763
764 void Session::setWindowRect(std::optional<double> x, std::optional<double> y, std::optional<double> width, std::optional<double> height, Function<void (CommandResult&&)>&& completionHandler)
765 {
766     if (!m_toplevelBrowsingContext) {
767         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
768         return;
769     }
770
771     handleUserPrompts([this, x, y, width, height, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
772         if (result.isError()) {
773             completionHandler(WTFMove(result));
774             return;
775         }
776
777         if (width && height)  {
778             resizeToplevelBrowsingContextWindow(width.value(), height.value(), [this, x, y, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
779                 if (result.isError()) {
780                     completionHandler(WTFMove(result));
781                     return;
782                 }
783                 if (!x || !y) {
784                     getToplevelBrowsingContextRect(WTFMove(completionHandler));
785                     return;
786                 }
787
788                 moveToplevelBrowsingContextWindow(x.value(), y.value(), [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
789                     if (result.isError()) {
790                         completionHandler(WTFMove(result));
791                         return;
792                     }
793                     getToplevelBrowsingContextRect(WTFMove(completionHandler));
794                 });
795             });
796             return;
797         }
798
799         if (x && y) {
800             moveToplevelBrowsingContextWindow(x.value(), y.value(), [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
801                 if (result.isError()) {
802                     completionHandler(WTFMove(result));
803                     return;
804                 }
805                 getToplevelBrowsingContextRect(WTFMove(completionHandler));
806             });
807             return;
808         }
809
810         getToplevelBrowsingContextRect(WTFMove(completionHandler));
811     });
812 }
813
814 RefPtr<JSON::Object> Session::createElement(RefPtr<JSON::Value>&& value)
815 {
816     RefPtr<JSON::Object> valueObject;
817     if (!value->asObject(valueObject))
818         return nullptr;
819
820     String elementID;
821     if (!valueObject->getString("session-node-" + m_id, elementID))
822         return nullptr;
823
824     RefPtr<JSON::Object> elementObject = JSON::Object::create();
825     elementObject->setString(webElementIdentifier, elementID);
826     return elementObject;
827 }
828
829 RefPtr<JSON::Object> Session::createElement(const String& elementID)
830 {
831     RefPtr<JSON::Object> elementObject = JSON::Object::create();
832     elementObject->setString("session-node-" + m_id, elementID);
833     return elementObject;
834 }
835
836 RefPtr<JSON::Object> Session::extractElement(JSON::Value& value)
837 {
838     String elementID = extractElementID(value);
839     return !elementID.isEmpty() ? createElement(elementID) : nullptr;
840 }
841
842 String Session::extractElementID(JSON::Value& value)
843 {
844     RefPtr<JSON::Object> valueObject;
845     if (!value.asObject(valueObject))
846         return emptyString();
847
848     String elementID;
849     if (!valueObject->getString(webElementIdentifier, elementID))
850         return emptyString();
851
852     return elementID;
853 }
854
855 void Session::computeElementLayout(const String& elementID, OptionSet<ElementLayoutOption> options, Function<void (std::optional<Rect>&&, std::optional<Point>&&, bool, RefPtr<JSON::Object>&&)>&& completionHandler)
856 {
857     ASSERT(m_toplevelBrowsingContext.value());
858
859     RefPtr<JSON::Object> parameters = JSON::Object::create();
860     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
861     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value_or(emptyString()));
862     parameters->setString(ASCIILiteral("nodeHandle"), elementID);
863     parameters->setBoolean(ASCIILiteral("scrollIntoViewIfNeeded"), options.contains(ElementLayoutOption::ScrollIntoViewIfNeeded));
864     parameters->setString(ASCIILiteral("coordinateSystem"), options.contains(ElementLayoutOption::UseViewportCoordinates) ? ASCIILiteral("LayoutViewport") : ASCIILiteral("Page"));
865     m_host->sendCommandToBackend(ASCIILiteral("computeElementLayout"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
866         if (response.isError || !response.responseObject) {
867             completionHandler(std::nullopt, std::nullopt, false, WTFMove(response.responseObject));
868             return;
869         }
870         RefPtr<JSON::Object> rectObject;
871         if (!response.responseObject->getObject(ASCIILiteral("rect"), rectObject)) {
872             completionHandler(std::nullopt, std::nullopt, false, nullptr);
873             return;
874         }
875         std::optional<int> elementX;
876         std::optional<int> elementY;
877         RefPtr<JSON::Object> elementPosition;
878         if (rectObject->getObject(ASCIILiteral("origin"), elementPosition)) {
879             int x, y;
880             if (elementPosition->getInteger(ASCIILiteral("x"), x) && elementPosition->getInteger(ASCIILiteral("y"), y)) {
881                 elementX = x;
882                 elementY = y;
883             }
884         }
885         if (!elementX || !elementY) {
886             completionHandler(std::nullopt, std::nullopt, false, nullptr);
887             return;
888         }
889         std::optional<int> elementWidth;
890         std::optional<int> elementHeight;
891         RefPtr<JSON::Object> elementSize;
892         if (rectObject->getObject(ASCIILiteral("size"), elementSize)) {
893             int width, height;
894             if (elementSize->getInteger(ASCIILiteral("width"), width) && elementSize->getInteger(ASCIILiteral("height"), height)) {
895                 elementWidth = width;
896                 elementHeight = height;
897             }
898         }
899         if (!elementWidth || !elementHeight) {
900             completionHandler(std::nullopt, std::nullopt, false, nullptr);
901             return;
902         }
903         Rect rect = { { elementX.value(), elementY.value() }, { elementWidth.value(), elementHeight.value() } };
904
905         bool isObscured;
906         if (!response.responseObject->getBoolean(ASCIILiteral("isObscured"), isObscured)) {
907             completionHandler(std::nullopt, std::nullopt, false, nullptr);
908             return;
909         }
910         RefPtr<JSON::Object> inViewCenterPointObject;
911         if (!response.responseObject->getObject(ASCIILiteral("inViewCenterPoint"), inViewCenterPointObject)) {
912             completionHandler(rect, std::nullopt, isObscured, nullptr);
913             return;
914         }
915         int inViewCenterPointX, inViewCenterPointY;
916         if (!inViewCenterPointObject->getInteger(ASCIILiteral("x"), inViewCenterPointX)
917             || !inViewCenterPointObject->getInteger(ASCIILiteral("y"), inViewCenterPointY)) {
918             completionHandler(std::nullopt, std::nullopt, isObscured, nullptr);
919             return;
920         }
921         Point inViewCenterPoint = { inViewCenterPointX, inViewCenterPointY };
922         completionHandler(rect, inViewCenterPoint, isObscured, nullptr);
923     });
924 }
925
926 void Session::findElements(const String& strategy, const String& selector, FindElementsMode mode, const String& rootElementID, Function<void (CommandResult&&)>&& completionHandler)
927 {
928     if (!m_toplevelBrowsingContext) {
929         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
930         return;
931     }
932
933     RefPtr<JSON::Array> arguments = JSON::Array::create();
934     arguments->pushString(JSON::Value::create(strategy)->toJSONString());
935     if (rootElementID.isEmpty())
936         arguments->pushString(JSON::Value::null()->toJSONString());
937     else
938         arguments->pushString(createElement(rootElementID)->toJSONString());
939     arguments->pushString(JSON::Value::create(selector)->toJSONString());
940     arguments->pushString(JSON::Value::create(mode == FindElementsMode::Single)->toJSONString());
941     arguments->pushString(JSON::Value::create(m_implicitWaitTimeout.milliseconds())->toJSONString());
942
943     RefPtr<JSON::Object> parameters = JSON::Object::create();
944     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
945     if (m_currentBrowsingContext)
946         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
947     parameters->setString(ASCIILiteral("function"), FindNodesJavaScript);
948     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
949     parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
950     // If there's an implicit wait, use one second more as callback timeout.
951     if (m_implicitWaitTimeout)
952         parameters->setInteger(ASCIILiteral("callbackTimeout"), Seconds(m_implicitWaitTimeout + 1_s).millisecondsAs<int>());
953
954     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), mode, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
955         if (response.isError || !response.responseObject) {
956             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
957             return;
958         }
959         String valueString;
960         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
961             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
962             return;
963         }
964         RefPtr<JSON::Value> resultValue;
965         if (!JSON::Value::parseJSON(valueString, resultValue)) {
966             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
967             return;
968         }
969
970         switch (mode) {
971         case FindElementsMode::Single: {
972             RefPtr<JSON::Object> elementObject = createElement(WTFMove(resultValue));
973             if (!elementObject) {
974                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
975                 return;
976             }
977             completionHandler(CommandResult::success(WTFMove(elementObject)));
978             break;
979         }
980         case FindElementsMode::Multiple: {
981             RefPtr<JSON::Array> elementsArray;
982             if (!resultValue->asArray(elementsArray)) {
983                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
984                 return;
985             }
986             RefPtr<JSON::Array> elementObjectsArray = JSON::Array::create();
987             unsigned elementsArrayLength = elementsArray->length();
988             for (unsigned i = 0; i < elementsArrayLength; ++i) {
989                 if (auto elementObject = createElement(elementsArray->get(i)))
990                     elementObjectsArray->pushObject(WTFMove(elementObject));
991             }
992             completionHandler(CommandResult::success(WTFMove(elementObjectsArray)));
993             break;
994         }
995         }
996     });
997 }
998
999 void Session::getActiveElement(Function<void (CommandResult&&)>&& completionHandler)
1000 {
1001     if (!m_toplevelBrowsingContext) {
1002         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1003         return;
1004     }
1005
1006     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1007         if (result.isError()) {
1008             completionHandler(WTFMove(result));
1009             return;
1010         }
1011         RefPtr<JSON::Object> parameters = JSON::Object::create();
1012         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1013         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function() { return document.activeElement; }"));
1014         parameters->setArray(ASCIILiteral("arguments"), JSON::Array::create());
1015         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1016             if (response.isError || !response.responseObject) {
1017                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1018                 return;
1019             }
1020             String valueString;
1021             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1022                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1023                 return;
1024             }
1025             RefPtr<JSON::Value> resultValue;
1026             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1027                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1028                 return;
1029             }
1030             RefPtr<JSON::Object> elementObject = createElement(WTFMove(resultValue));
1031             if (!elementObject) {
1032                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
1033                 return;
1034             }
1035             completionHandler(CommandResult::success(WTFMove(elementObject)));
1036         });
1037     });
1038 }
1039
1040 void Session::isElementSelected(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1041 {
1042     if (!m_toplevelBrowsingContext) {
1043         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1044         return;
1045     }
1046
1047     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1048         if (result.isError()) {
1049             completionHandler(WTFMove(result));
1050             return;
1051         }
1052         RefPtr<JSON::Array> arguments = JSON::Array::create();
1053         arguments->pushString(createElement(elementID)->toJSONString());
1054         arguments->pushString(JSON::Value::create("selected")->toJSONString());
1055
1056         RefPtr<JSON::Object> parameters = JSON::Object::create();
1057         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1058         if (m_currentBrowsingContext)
1059             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1060         parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
1061         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1062         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1063             if (response.isError || !response.responseObject) {
1064                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1065                 return;
1066             }
1067             String valueString;
1068             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1069                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1070                 return;
1071             }
1072             RefPtr<JSON::Value> resultValue;
1073             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1074                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1075                 return;
1076             }
1077             if (resultValue->isNull()) {
1078                 completionHandler(CommandResult::success(JSON::Value::create(false)));
1079                 return;
1080             }
1081             String booleanResult;
1082             if (!resultValue->asString(booleanResult) || booleanResult != "true") {
1083                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1084                 return;
1085             }
1086             completionHandler(CommandResult::success(JSON::Value::create(true)));
1087         });
1088     });
1089 }
1090
1091 void Session::getElementText(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1092 {
1093     if (!m_toplevelBrowsingContext) {
1094         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1095         return;
1096     }
1097
1098     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1099         if (result.isError()) {
1100             completionHandler(WTFMove(result));
1101             return;
1102         }
1103         RefPtr<JSON::Array> arguments = JSON::Array::create();
1104         arguments->pushString(createElement(elementID)->toJSONString());
1105
1106         RefPtr<JSON::Object> parameters = JSON::Object::create();
1107         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1108         if (m_currentBrowsingContext)
1109             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1110         // FIXME: Add an atom to properly implement this instead of just using innerText.
1111         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.innerText.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g, '') }"));
1112         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1113         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1114             if (response.isError || !response.responseObject) {
1115                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1116                 return;
1117             }
1118             String valueString;
1119             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1120                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1121                 return;
1122             }
1123             RefPtr<JSON::Value> resultValue;
1124             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1125                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1126                 return;
1127             }
1128             completionHandler(CommandResult::success(WTFMove(resultValue)));
1129         });
1130     });
1131 }
1132
1133 void Session::getElementTagName(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1134 {
1135     if (!m_toplevelBrowsingContext) {
1136         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1137         return;
1138     }
1139
1140     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1141         if (result.isError()) {
1142             completionHandler(WTFMove(result));
1143             return;
1144         }
1145         RefPtr<JSON::Array> arguments = JSON::Array::create();
1146         arguments->pushString(createElement(elementID)->toJSONString());
1147
1148         RefPtr<JSON::Object> parameters = JSON::Object::create();
1149         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1150         if (m_currentBrowsingContext)
1151             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1152         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.tagName.toLowerCase() }"));
1153         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1154         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1155             if (response.isError || !response.responseObject) {
1156                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1157                 return;
1158             }
1159             String valueString;
1160             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1161                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1162                 return;
1163             }
1164             RefPtr<JSON::Value> resultValue;
1165             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1166                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1167                 return;
1168             }
1169             completionHandler(CommandResult::success(WTFMove(resultValue)));
1170         });
1171     });
1172 }
1173
1174 void Session::getElementRect(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1175 {
1176     if (!m_toplevelBrowsingContext) {
1177         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1178         return;
1179     }
1180
1181     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1182         if (result.isError()) {
1183             completionHandler(WTFMove(result));
1184             return;
1185         }
1186         computeElementLayout(elementID, { }, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&&, bool, RefPtr<JSON::Object>&& error) {
1187             if (!rect || error) {
1188                 completionHandler(CommandResult::fail(WTFMove(error)));
1189                 return;
1190             }
1191             RefPtr<JSON::Object> rectObject = JSON::Object::create();
1192             rectObject->setInteger(ASCIILiteral("x"), rect.value().origin.x);
1193             rectObject->setInteger(ASCIILiteral("y"), rect.value().origin.y);
1194             rectObject->setInteger(ASCIILiteral("width"), rect.value().size.width);
1195             rectObject->setInteger(ASCIILiteral("height"), rect.value().size.height);
1196             completionHandler(CommandResult::success(WTFMove(rectObject)));
1197         });
1198     });
1199 }
1200
1201 void Session::isElementEnabled(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1202 {
1203     if (!m_toplevelBrowsingContext) {
1204         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1205         return;
1206     }
1207
1208     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1209         if (result.isError()) {
1210             completionHandler(WTFMove(result));
1211             return;
1212         }
1213         RefPtr<JSON::Array> arguments = JSON::Array::create();
1214         arguments->pushString(createElement(elementID)->toJSONString());
1215
1216         RefPtr<JSON::Object> parameters = JSON::Object::create();
1217         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1218         if (m_currentBrowsingContext)
1219             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1220         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.disabled === undefined ? true : !element.disabled }"));
1221         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1222         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1223             if (response.isError || !response.responseObject) {
1224                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1225                 return;
1226             }
1227             String valueString;
1228             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1229                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1230                 return;
1231             }
1232             RefPtr<JSON::Value> resultValue;
1233             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1234                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1235                 return;
1236             }
1237             completionHandler(CommandResult::success(WTFMove(resultValue)));
1238         });
1239     });
1240 }
1241
1242 void Session::isElementDisplayed(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1243 {
1244     if (!m_toplevelBrowsingContext) {
1245         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1246         return;
1247     }
1248
1249     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1250         if (result.isError()) {
1251             completionHandler(WTFMove(result));
1252             return;
1253         }
1254         RefPtr<JSON::Array> arguments = JSON::Array::create();
1255         arguments->pushString(createElement(elementID)->toJSONString());
1256
1257         RefPtr<JSON::Object> parameters = JSON::Object::create();
1258         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1259         if (m_currentBrowsingContext)
1260             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1261         parameters->setString(ASCIILiteral("function"), ElementDisplayedJavaScript);
1262         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1263         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1264             if (response.isError || !response.responseObject) {
1265                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1266                 return;
1267             }
1268             String valueString;
1269             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1270                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1271                 return;
1272             }
1273             RefPtr<JSON::Value> resultValue;
1274             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1275                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1276                 return;
1277             }
1278             completionHandler(CommandResult::success(WTFMove(resultValue)));
1279         });
1280     });
1281 }
1282
1283 void Session::getElementAttribute(const String& elementID, const String& attribute, Function<void (CommandResult&&)>&& completionHandler)
1284 {
1285     if (!m_toplevelBrowsingContext) {
1286         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1287         return;
1288     }
1289
1290     handleUserPrompts([this, elementID, attribute, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1291         if (result.isError()) {
1292             completionHandler(WTFMove(result));
1293             return;
1294         }
1295         RefPtr<JSON::Array> arguments = JSON::Array::create();
1296         arguments->pushString(createElement(elementID)->toJSONString());
1297         arguments->pushString(JSON::Value::create(attribute)->toJSONString());
1298
1299         RefPtr<JSON::Object> parameters = JSON::Object::create();
1300         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1301         if (m_currentBrowsingContext)
1302             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1303         parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
1304         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1305         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1306             if (response.isError || !response.responseObject) {
1307                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1308                 return;
1309             }
1310             String valueString;
1311             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1312                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1313                 return;
1314             }
1315             RefPtr<JSON::Value> resultValue;
1316             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1317                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1318                 return;
1319             }
1320             completionHandler(CommandResult::success(WTFMove(resultValue)));
1321         });
1322     });
1323 }
1324
1325 void Session::getElementProperty(const String& elementID, const String& property, Function<void (CommandResult&&)>&& completionHandler)
1326 {
1327     if (!m_toplevelBrowsingContext) {
1328         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1329         return;
1330     }
1331
1332     handleUserPrompts([this, elementID, property, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1333         if (result.isError()) {
1334             completionHandler(WTFMove(result));
1335             return;
1336         }
1337         RefPtr<JSON::Array> arguments = JSON::Array::create();
1338         arguments->pushString(createElement(elementID)->toJSONString());
1339
1340         RefPtr<JSON::Object> parameters = JSON::Object::create();
1341         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1342         if (m_currentBrowsingContext)
1343             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1344         parameters->setString(ASCIILiteral("function"), makeString("function(element) { return element.", property, "; }"));
1345         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1346         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1347             if (response.isError || !response.responseObject) {
1348                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1349                 return;
1350             }
1351             String valueString;
1352             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1353                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1354                 return;
1355             }
1356             RefPtr<JSON::Value> resultValue;
1357             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1358                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1359                 return;
1360             }
1361             completionHandler(CommandResult::success(WTFMove(resultValue)));
1362         });
1363     });
1364 }
1365
1366 void Session::waitForNavigationToComplete(Function<void (CommandResult&&)>&& completionHandler)
1367 {
1368     if (!m_toplevelBrowsingContext) {
1369         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1370         return;
1371     }
1372
1373     RefPtr<JSON::Object> parameters = JSON::Object::create();
1374     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1375     if (m_currentBrowsingContext)
1376         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1377     parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_pageLoadTimeout.millisecondsAs<int>());
1378     if (auto pageLoadStrategy = pageLoadStrategyString())
1379         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
1380     m_host->sendCommandToBackend(ASCIILiteral("waitForNavigationToComplete"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1381         if (response.isError) {
1382             auto result = CommandResult::fail(WTFMove(response.responseObject));
1383             if (result.errorCode() == CommandResult::ErrorCode::NoSuchFrame) {
1384                 // Navigation destroyed the current frame, switch to top level browsing context and ignore the error.
1385                 switchToBrowsingContext(std::nullopt);
1386             } else {
1387                 completionHandler(WTFMove(result));
1388                 return;
1389             }
1390         }
1391         completionHandler(CommandResult::success());
1392     });
1393 }
1394
1395 void Session::selectOptionElement(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1396 {
1397     RefPtr<JSON::Object> parameters = JSON::Object::create();
1398     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1399     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value_or(emptyString()));
1400     parameters->setString(ASCIILiteral("nodeHandle"), elementID);
1401     m_host->sendCommandToBackend(ASCIILiteral("selectOptionElement"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1402         if (response.isError) {
1403             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1404             return;
1405         }
1406         completionHandler(CommandResult::success());
1407     });
1408 }
1409
1410 void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1411 {
1412     if (!m_toplevelBrowsingContext) {
1413         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1414         return;
1415     }
1416
1417     OptionSet<ElementLayoutOption> options = ElementLayoutOption::ScrollIntoViewIfNeeded;
1418     options |= ElementLayoutOption::UseViewportCoordinates;
1419     computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), elementID, completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<JSON::Object>&& error) mutable {
1420         if (!rect || error) {
1421             completionHandler(CommandResult::fail(WTFMove(error)));
1422             return;
1423         }
1424         if (isObscured) {
1425             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementClickIntercepted));
1426             return;
1427         }
1428         if (!inViewCenter) {
1429             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementNotInteractable));
1430             return;
1431         }
1432
1433         getElementTagName(elementID, [this, elementID, inViewCenter = WTFMove(inViewCenter), isObscured, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1434             bool isOptionElement = false;
1435             if (!result.isError()) {
1436                 String tagName;
1437                 if (result.result()->asString(tagName))
1438                     isOptionElement = tagName == "option";
1439             }
1440
1441             Function<void (CommandResult&&)> continueAfterClickFunction = [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1442                 if (result.isError()) {
1443                     completionHandler(WTFMove(result));
1444                     return;
1445                 }
1446
1447                 waitForNavigationToComplete(WTFMove(completionHandler));
1448             };
1449             if (isOptionElement)
1450                 selectOptionElement(elementID, WTFMove(continueAfterClickFunction));
1451             else
1452                 performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(continueAfterClickFunction));
1453         });
1454     });
1455 }
1456
1457 void Session::elementClear(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1458 {
1459     if (!m_toplevelBrowsingContext) {
1460         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1461         return;
1462     }
1463
1464     RefPtr<JSON::Array> arguments = JSON::Array::create();
1465     arguments->pushString(createElement(elementID)->toJSONString());
1466
1467     RefPtr<JSON::Object> parameters = JSON::Object::create();
1468     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1469     if (m_currentBrowsingContext)
1470         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1471     parameters->setString(ASCIILiteral("function"), FormElementClearJavaScript);
1472     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1473     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1474         if (response.isError) {
1475             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1476             return;
1477         }
1478         completionHandler(CommandResult::success());
1479     });
1480 }
1481
1482 String Session::virtualKeyForKeySequence(const String& keySequence, KeyModifier& modifier)
1483 {
1484     // ยง17.4.2 Keyboard Actions.
1485     // https://www.w3.org/TR/webdriver/#keyboard-actions
1486     modifier = KeyModifier::None;
1487     switch (keySequence[0]) {
1488     case 0xE001U:
1489         return ASCIILiteral("Cancel");
1490     case 0xE002U:
1491         return ASCIILiteral("Help");
1492     case 0xE003U:
1493         return ASCIILiteral("Backspace");
1494     case 0xE004U:
1495         return ASCIILiteral("Tab");
1496     case 0xE005U:
1497         return ASCIILiteral("Clear");
1498     case 0xE006U:
1499         return ASCIILiteral("Return");
1500     case 0xE007U:
1501         return ASCIILiteral("Enter");
1502     case 0xE008U:
1503         modifier = KeyModifier::Shift;
1504         return ASCIILiteral("Shift");
1505     case 0xE009U:
1506         modifier = KeyModifier::Control;
1507         return ASCIILiteral("Control");
1508     case 0xE00AU:
1509         modifier = KeyModifier::Alternate;
1510         return ASCIILiteral("Alternate");
1511     case 0xE00BU:
1512         return ASCIILiteral("Pause");
1513     case 0xE00CU:
1514         return ASCIILiteral("Escape");
1515     case 0xE00DU:
1516         return ASCIILiteral("Space");
1517     case 0xE00EU:
1518         return ASCIILiteral("PageUp");
1519     case 0xE00FU:
1520         return ASCIILiteral("PageDown");
1521     case 0xE010U:
1522         return ASCIILiteral("End");
1523     case 0xE011U:
1524         return ASCIILiteral("Home");
1525     case 0xE012U:
1526         return ASCIILiteral("LeftArrow");
1527     case 0xE013U:
1528         return ASCIILiteral("UpArrow");
1529     case 0xE014U:
1530         return ASCIILiteral("RightArrow");
1531     case 0xE015U:
1532         return ASCIILiteral("DownArrow");
1533     case 0xE016U:
1534         return ASCIILiteral("Insert");
1535     case 0xE017U:
1536         return ASCIILiteral("Delete");
1537     case 0xE018U:
1538         return ASCIILiteral("Semicolon");
1539     case 0xE019U:
1540         return ASCIILiteral("Equals");
1541     case 0xE01AU:
1542         return ASCIILiteral("NumberPad0");
1543     case 0xE01BU:
1544         return ASCIILiteral("NumberPad1");
1545     case 0xE01CU:
1546         return ASCIILiteral("NumberPad2");
1547     case 0xE01DU:
1548         return ASCIILiteral("NumberPad3");
1549     case 0xE01EU:
1550         return ASCIILiteral("NumberPad4");
1551     case 0xE01FU:
1552         return ASCIILiteral("NumberPad5");
1553     case 0xE020U:
1554         return ASCIILiteral("NumberPad6");
1555     case 0xE021U:
1556         return ASCIILiteral("NumberPad7");
1557     case 0xE022U:
1558         return ASCIILiteral("NumberPad8");
1559     case 0xE023U:
1560         return ASCIILiteral("NumberPad9");
1561     case 0xE024U:
1562         return ASCIILiteral("NumberPadMultiply");
1563     case 0xE025U:
1564         return ASCIILiteral("NumberPadAdd");
1565     case 0xE026U:
1566         return ASCIILiteral("NumberPadSeparator");
1567     case 0xE027U:
1568         return ASCIILiteral("NumberPadSubtract");
1569     case 0xE028U:
1570         return ASCIILiteral("NumberPadDecimal");
1571     case 0xE029U:
1572         return ASCIILiteral("NumberPadDivide");
1573     case 0xE031U:
1574         return ASCIILiteral("Function1");
1575     case 0xE032U:
1576         return ASCIILiteral("Function2");
1577     case 0xE033U:
1578         return ASCIILiteral("Function3");
1579     case 0xE034U:
1580         return ASCIILiteral("Function4");
1581     case 0xE035U:
1582         return ASCIILiteral("Function5");
1583     case 0xE036U:
1584         return ASCIILiteral("Function6");
1585     case 0xE037U:
1586         return ASCIILiteral("Function7");
1587     case 0xE038U:
1588         return ASCIILiteral("Function8");
1589     case 0xE039U:
1590         return ASCIILiteral("Function9");
1591     case 0xE03AU:
1592         return ASCIILiteral("Function10");
1593     case 0xE03BU:
1594         return ASCIILiteral("Function11");
1595     case 0xE03CU:
1596         return ASCIILiteral("Function12");
1597     case 0xE03DU:
1598         modifier = KeyModifier::Meta;
1599         return ASCIILiteral("Meta");
1600     default:
1601         break;
1602     }
1603     return String();
1604 }
1605
1606 void Session::elementSendKeys(const String& elementID, Vector<String>&& keys, Function<void (CommandResult&&)>&& completionHandler)
1607 {
1608     if (!m_toplevelBrowsingContext) {
1609         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1610         return;
1611     }
1612
1613     handleUserPrompts([this, elementID, keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1614         if (result.isError()) {
1615             completionHandler(WTFMove(result));
1616             return;
1617         }
1618         // FIXME: move this to an atom.
1619         static const char focusScript[] =
1620             "function focus(element) {"
1621             "    var doc = element.ownerDocument || element;"
1622             "    var prevActiveElement = doc.activeElement;"
1623             "    if (element != prevActiveElement && prevActiveElement)"
1624             "        prevActiveElement.blur();"
1625             "    element.focus();"
1626             "    if (element != prevActiveElement && element.value && element.value.length && element.setSelectionRange)"
1627             "        element.setSelectionRange(element.value.length, element.value.length);"
1628             "    if (element != doc.activeElement)"
1629             "        throw new Error('cannot focus element');"
1630             "}";
1631
1632         RefPtr<JSON::Array> arguments = JSON::Array::create();
1633         arguments->pushString(createElement(elementID)->toJSONString());
1634         RefPtr<JSON::Object> parameters = JSON::Object::create();
1635         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1636         if (m_currentBrowsingContext)
1637             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1638         parameters->setString(ASCIILiteral("function"), focusScript);
1639         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1640         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
1641             if (response.isError || !response.responseObject) {
1642                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1643                 return;
1644             }
1645
1646             unsigned stickyModifiers = 0;
1647             Vector<KeyboardInteraction> interactions;
1648             interactions.reserveInitialCapacity(keys.size());
1649             for (const auto& key : keys) {
1650                 KeyboardInteraction interaction;
1651                 KeyModifier modifier;
1652                 auto virtualKey = virtualKeyForKeySequence(key, modifier);
1653                 if (!virtualKey.isNull()) {
1654                     interaction.key = virtualKey;
1655                     if (modifier != KeyModifier::None) {
1656                         stickyModifiers ^= modifier;
1657                         if (stickyModifiers & modifier)
1658                             interaction.type = KeyboardInteractionType::KeyPress;
1659                         else
1660                             interaction.type = KeyboardInteractionType::KeyRelease;
1661                     }
1662                 } else
1663                     interaction.text = key;
1664                 interactions.uncheckedAppend(WTFMove(interaction));
1665             }
1666
1667             // Reset sticky modifiers if needed.
1668             if (stickyModifiers) {
1669                 if (stickyModifiers & KeyModifier::Shift)
1670                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Shift")) });
1671                 if (stickyModifiers & KeyModifier::Control)
1672                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Control")) });
1673                 if (stickyModifiers & KeyModifier::Alternate)
1674                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Alternate")) });
1675                 if (stickyModifiers & KeyModifier::Meta)
1676                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Meta")) });
1677             }
1678
1679             performKeyboardInteractions(WTFMove(interactions), WTFMove(completionHandler));
1680         });
1681     });
1682 }
1683
1684 RefPtr<JSON::Value> Session::handleScriptResult(RefPtr<JSON::Value>&& resultValue)
1685 {
1686     RefPtr<JSON::Array> resultArray;
1687     if (resultValue->asArray(resultArray)) {
1688         RefPtr<JSON::Array> returnValueArray = JSON::Array::create();
1689         unsigned resultArrayLength = resultArray->length();
1690         for (unsigned i = 0; i < resultArrayLength; ++i)
1691             returnValueArray->pushValue(handleScriptResult(resultArray->get(i)));
1692         return returnValueArray;
1693     }
1694
1695     if (auto element = createElement(RefPtr<JSON::Value>(resultValue)))
1696         return element;
1697
1698     RefPtr<JSON::Object> resultObject;
1699     if (resultValue->asObject(resultObject)) {
1700         RefPtr<JSON::Object> returnValueObject = JSON::Object::create();
1701         auto end = resultObject->end();
1702         for (auto it = resultObject->begin(); it != end; ++it)
1703             returnValueObject->setValue(it->key, handleScriptResult(WTFMove(it->value)));
1704         return returnValueObject;
1705     }
1706
1707     return resultValue;
1708 }
1709
1710 void Session::executeScript(const String& script, RefPtr<JSON::Array>&& argumentsArray, ExecuteScriptMode mode, Function<void (CommandResult&&)>&& completionHandler)
1711 {
1712     if (!m_toplevelBrowsingContext) {
1713         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1714         return;
1715     }
1716
1717     handleUserPrompts([this, script, argumentsArray = WTFMove(argumentsArray), mode, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1718         if (result.isError()) {
1719             completionHandler(WTFMove(result));
1720             return;
1721         }
1722         RefPtr<JSON::Array> arguments = JSON::Array::create();
1723         unsigned argumentsLength = argumentsArray->length();
1724         for (unsigned i = 0; i < argumentsLength; ++i) {
1725             if (auto argument = argumentsArray->get(i)) {
1726                 if (auto element = extractElement(*argument))
1727                     arguments->pushString(element->toJSONString());
1728                 else
1729                     arguments->pushString(argument->toJSONString());
1730             }
1731         }
1732
1733         RefPtr<JSON::Object> parameters = JSON::Object::create();
1734         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1735         if (m_currentBrowsingContext)
1736             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1737         parameters->setString(ASCIILiteral("function"), "function(){" + script + '}');
1738         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1739         if (mode == ExecuteScriptMode::Async) {
1740             parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
1741             if (m_scriptTimeout)
1742                 parameters->setInteger(ASCIILiteral("callbackTimeout"), m_scriptTimeout.millisecondsAs<int>());
1743         }
1744         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
1745             if (response.isError || !response.responseObject) {
1746                 auto result = CommandResult::fail(WTFMove(response.responseObject));
1747                 if (result.errorCode() == CommandResult::ErrorCode::UnexpectedAlertOpen)
1748                     handleUnexpectedAlertOpen(WTFMove(completionHandler));
1749                 else
1750                     completionHandler(WTFMove(result));
1751                 return;
1752             }
1753             String valueString;
1754             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1755                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1756                 return;
1757             }
1758             if (valueString.isEmpty()) {
1759                 completionHandler(CommandResult::success());
1760                 return;
1761             }
1762             RefPtr<JSON::Value> resultValue;
1763             if (!JSON::Value::parseJSON(valueString, resultValue)) {
1764                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1765                 return;
1766             }
1767             completionHandler(CommandResult::success(handleScriptResult(WTFMove(resultValue))));
1768         });
1769     });
1770 }
1771
1772 void Session::performMouseInteraction(int x, int y, MouseButton button, MouseInteraction interaction, Function<void (CommandResult&&)>&& completionHandler)
1773 {
1774     RefPtr<JSON::Object> parameters = JSON::Object::create();
1775     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1776     RefPtr<JSON::Object> position = JSON::Object::create();
1777     position->setInteger(ASCIILiteral("x"), x);
1778     position->setInteger(ASCIILiteral("y"), y);
1779     parameters->setObject(ASCIILiteral("position"), WTFMove(position));
1780     switch (button) {
1781     case MouseButton::None:
1782         parameters->setString(ASCIILiteral("button"), ASCIILiteral("None"));
1783         break;
1784     case MouseButton::Left:
1785         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Left"));
1786         break;
1787     case MouseButton::Middle:
1788         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Middle"));
1789         break;
1790     case MouseButton::Right:
1791         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Right"));
1792         break;
1793     }
1794     switch (interaction) {
1795     case MouseInteraction::Move:
1796         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Move"));
1797         break;
1798     case MouseInteraction::Down:
1799         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Down"));
1800         break;
1801     case MouseInteraction::Up:
1802         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Up"));
1803         break;
1804     case MouseInteraction::SingleClick:
1805         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("SingleClick"));
1806         break;
1807     case MouseInteraction::DoubleClick:
1808         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("DoubleClick"));
1809         break;
1810     }
1811     parameters->setArray(ASCIILiteral("modifiers"), JSON::Array::create());
1812     m_host->sendCommandToBackend(ASCIILiteral("performMouseInteraction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1813         if (response.isError) {
1814             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1815             return;
1816         }
1817         completionHandler(CommandResult::success());
1818     });
1819 }
1820
1821 void Session::performKeyboardInteractions(Vector<KeyboardInteraction>&& interactions, Function<void (CommandResult&&)>&& completionHandler)
1822 {
1823     RefPtr<JSON::Object> parameters = JSON::Object::create();
1824     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1825     RefPtr<JSON::Array> interactionsArray = JSON::Array::create();
1826     for (const auto& interaction : interactions) {
1827         RefPtr<JSON::Object> interactionObject = JSON::Object::create();
1828         switch (interaction.type) {
1829         case KeyboardInteractionType::KeyPress:
1830             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyPress"));
1831             break;
1832         case KeyboardInteractionType::KeyRelease:
1833             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyRelease"));
1834             break;
1835         case KeyboardInteractionType::InsertByKey:
1836             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("InsertByKey"));
1837             break;
1838         }
1839         if (interaction.key)
1840             interactionObject->setString(ASCIILiteral("key"), interaction.key.value());
1841         if (interaction.text)
1842             interactionObject->setString(ASCIILiteral("text"), interaction.text.value());
1843         interactionsArray->pushObject(WTFMove(interactionObject));
1844     }
1845     parameters->setArray(ASCIILiteral("interactions"), WTFMove(interactionsArray));
1846     m_host->sendCommandToBackend(ASCIILiteral("performKeyboardInteractions"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1847         if (response.isError) {
1848             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1849             return;
1850         }
1851         completionHandler(CommandResult::success());
1852     });
1853 }
1854
1855 static std::optional<Session::Cookie> parseAutomationCookie(const JSON::Object& cookieObject)
1856 {
1857     Session::Cookie cookie;
1858     if (!cookieObject.getString(ASCIILiteral("name"), cookie.name))
1859         return std::nullopt;
1860     if (!cookieObject.getString(ASCIILiteral("value"), cookie.value))
1861         return std::nullopt;
1862
1863     String path;
1864     if (cookieObject.getString(ASCIILiteral("path"), path))
1865         cookie.path = path;
1866     String domain;
1867     if (cookieObject.getString(ASCIILiteral("domain"), domain))
1868         cookie.domain = domain;
1869     bool secure;
1870     if (cookieObject.getBoolean(ASCIILiteral("secure"), secure))
1871         cookie.secure = secure;
1872     bool httpOnly;
1873     if (cookieObject.getBoolean(ASCIILiteral("httpOnly"), httpOnly))
1874         cookie.httpOnly = httpOnly;
1875     bool session = false;
1876     cookieObject.getBoolean(ASCIILiteral("session"), session);
1877     if (!session) {
1878         double expiry;
1879         if (cookieObject.getDouble(ASCIILiteral("expires"), expiry))
1880             cookie.expiry = expiry;
1881     }
1882
1883     return cookie;
1884 }
1885
1886 static RefPtr<JSON::Object> builtAutomationCookie(const Session::Cookie& cookie)
1887 {
1888     RefPtr<JSON::Object> cookieObject = JSON::Object::create();
1889     cookieObject->setString(ASCIILiteral("name"), cookie.name);
1890     cookieObject->setString(ASCIILiteral("value"), cookie.value);
1891     cookieObject->setString(ASCIILiteral("path"), cookie.path.value_or("/"));
1892     cookieObject->setString(ASCIILiteral("domain"), cookie.domain.value_or(emptyString()));
1893     cookieObject->setBoolean(ASCIILiteral("secure"), cookie.secure.value_or(false));
1894     cookieObject->setBoolean(ASCIILiteral("httpOnly"), cookie.httpOnly.value_or(false));
1895     cookieObject->setBoolean(ASCIILiteral("session"), !cookie.expiry);
1896     cookieObject->setDouble(ASCIILiteral("expires"), cookie.expiry.value_or(0));
1897     return cookieObject;
1898 }
1899
1900 static RefPtr<JSON::Object> serializeCookie(const Session::Cookie& cookie)
1901 {
1902     RefPtr<JSON::Object> cookieObject = JSON::Object::create();
1903     cookieObject->setString(ASCIILiteral("name"), cookie.name);
1904     cookieObject->setString(ASCIILiteral("value"), cookie.value);
1905     if (cookie.path)
1906         cookieObject->setString(ASCIILiteral("path"), cookie.path.value());
1907     if (cookie.domain)
1908         cookieObject->setString(ASCIILiteral("domain"), cookie.domain.value());
1909     if (cookie.secure)
1910         cookieObject->setBoolean(ASCIILiteral("secure"), cookie.secure.value());
1911     if (cookie.httpOnly)
1912         cookieObject->setBoolean(ASCIILiteral("httpOnly"), cookie.httpOnly.value());
1913     if (cookie.expiry)
1914         cookieObject->setInteger(ASCIILiteral("expiry"), cookie.expiry.value());
1915     return cookieObject;
1916 }
1917
1918 void Session::getAllCookies(Function<void (CommandResult&&)>&& completionHandler)
1919 {
1920     if (!m_toplevelBrowsingContext) {
1921         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1922         return;
1923     }
1924
1925     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1926         if (result.isError()) {
1927             completionHandler(WTFMove(result));
1928             return;
1929         }
1930
1931         RefPtr<JSON::Object> parameters = JSON::Object::create();
1932         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1933         m_host->sendCommandToBackend(ASCIILiteral("getAllCookies"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
1934             if (response.isError || !response.responseObject) {
1935                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1936                 return;
1937             }
1938             RefPtr<JSON::Array> cookiesArray;
1939             if (!response.responseObject->getArray(ASCIILiteral("cookies"), cookiesArray)) {
1940                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1941                 return;
1942             }
1943             RefPtr<JSON::Array> cookies = JSON::Array::create();
1944             for (unsigned i = 0; i < cookiesArray->length(); ++i) {
1945                 RefPtr<JSON::Value> cookieValue = cookiesArray->get(i);
1946                 RefPtr<JSON::Object> cookieObject;
1947                 if (!cookieValue->asObject(cookieObject)) {
1948                     completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1949                     return;
1950                 }
1951
1952                 auto cookie = parseAutomationCookie(*cookieObject);
1953                 if (!cookie) {
1954                     completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1955                     return;
1956                 }
1957                 cookies->pushObject(serializeCookie(cookie.value()));
1958             }
1959             completionHandler(CommandResult::success(WTFMove(cookies)));
1960         });
1961     });
1962 }
1963
1964 void Session::getNamedCookie(const String& name, Function<void (CommandResult&&)>&& completionHandler)
1965 {
1966     getAllCookies([this, name, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1967         if (result.isError()) {
1968             completionHandler(WTFMove(result));
1969             return;
1970         }
1971         RefPtr<JSON::Array> cookiesArray;
1972         result.result()->asArray(cookiesArray);
1973         for (unsigned i = 0; i < cookiesArray->length(); ++i) {
1974             RefPtr<JSON::Value> cookieValue = cookiesArray->get(i);
1975             RefPtr<JSON::Object> cookieObject;
1976             cookieValue->asObject(cookieObject);
1977             String cookieName;
1978             cookieObject->getString(ASCIILiteral("name"), cookieName);
1979             if (cookieName == name) {
1980                 completionHandler(CommandResult::success(WTFMove(cookieObject)));
1981                 return;
1982             }
1983         }
1984         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchCookie));
1985     });
1986 }
1987
1988 void Session::addCookie(const Cookie& cookie, Function<void (CommandResult&&)>&& completionHandler)
1989 {
1990     if (!m_toplevelBrowsingContext) {
1991         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1992         return;
1993     }
1994
1995     handleUserPrompts([this, cookie = builtAutomationCookie(cookie), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1996         if (result.isError()) {
1997             completionHandler(WTFMove(result));
1998             return;
1999         }
2000         RefPtr<JSON::Object> parameters = JSON::Object::create();
2001         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
2002         parameters->setObject(ASCIILiteral("cookie"), WTFMove(cookie));
2003         m_host->sendCommandToBackend(ASCIILiteral("addSingleCookie"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
2004             if (response.isError) {
2005                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2006                 return;
2007             }
2008             completionHandler(CommandResult::success());
2009         });
2010     });
2011 }
2012
2013 void Session::deleteCookie(const String& name, Function<void (CommandResult&&)>&& completionHandler)
2014 {
2015     if (!m_toplevelBrowsingContext) {
2016         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
2017         return;
2018     }
2019
2020     handleUserPrompts([this, name, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
2021         if (result.isError()) {
2022             completionHandler(WTFMove(result));
2023             return;
2024         }
2025         RefPtr<JSON::Object> parameters = JSON::Object::create();
2026         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
2027         parameters->setString(ASCIILiteral("cookieName"), name);
2028         m_host->sendCommandToBackend(ASCIILiteral("deleteSingleCookie"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
2029             if (response.isError) {
2030                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2031                 return;
2032             }
2033             completionHandler(CommandResult::success());
2034         });
2035     });
2036 }
2037
2038 void Session::deleteAllCookies(Function<void (CommandResult&&)>&& completionHandler)
2039 {
2040     if (!m_toplevelBrowsingContext) {
2041         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
2042         return;
2043     }
2044
2045     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
2046         if (result.isError()) {
2047             completionHandler(WTFMove(result));
2048             return;
2049         }
2050         RefPtr<JSON::Object> parameters = JSON::Object::create();
2051         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
2052         m_host->sendCommandToBackend(ASCIILiteral("deleteAllCookies"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
2053             if (response.isError) {
2054                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2055                 return;
2056             }
2057             completionHandler(CommandResult::success());
2058         });
2059     });
2060 }
2061
2062 void Session::dismissAlert(Function<void (CommandResult&&)>&& completionHandler)
2063 {
2064     if (!m_toplevelBrowsingContext) {
2065         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
2066         return;
2067     }
2068
2069     RefPtr<JSON::Object> parameters = JSON::Object::create();
2070     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
2071     m_host->sendCommandToBackend(ASCIILiteral("dismissCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
2072         if (response.isError) {
2073             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2074             return;
2075         }
2076         completionHandler(CommandResult::success());
2077     });
2078 }
2079
2080 void Session::acceptAlert(Function<void (CommandResult&&)>&& completionHandler)
2081 {
2082     if (!m_toplevelBrowsingContext) {
2083         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
2084         return;
2085     }
2086
2087     RefPtr<JSON::Object> parameters = JSON::Object::create();
2088     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
2089     m_host->sendCommandToBackend(ASCIILiteral("acceptCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
2090         if (response.isError) {
2091             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2092             return;
2093         }
2094         completionHandler(CommandResult::success());
2095     });
2096 }
2097
2098 void Session::getAlertText(Function<void (CommandResult&&)>&& completionHandler)
2099 {
2100     if (!m_toplevelBrowsingContext) {
2101         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
2102         return;
2103     }
2104
2105     RefPtr<JSON::Object> parameters = JSON::Object::create();
2106     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
2107     m_host->sendCommandToBackend(ASCIILiteral("messageOfCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
2108         if (response.isError || !response.responseObject) {
2109             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2110             return;
2111         }
2112         String valueString;
2113         if (!response.responseObject->getString(ASCIILiteral("message"), valueString)) {
2114             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
2115             return;
2116         }
2117         completionHandler(CommandResult::success(JSON::Value::create(valueString)));
2118     });
2119 }
2120
2121 void Session::sendAlertText(const String& text, Function<void (CommandResult&&)>&& completionHandler)
2122 {
2123     if (!m_toplevelBrowsingContext) {
2124         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
2125         return;
2126     }
2127
2128     RefPtr<JSON::Object> parameters = JSON::Object::create();
2129     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
2130     parameters->setString(ASCIILiteral("userInput"), text);
2131     m_host->sendCommandToBackend(ASCIILiteral("setUserInputForCurrentJavaScriptPrompt"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
2132         if (response.isError) {
2133             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2134             return;
2135         }
2136         completionHandler(CommandResult::success());
2137     });
2138 }
2139
2140 void Session::takeScreenshot(std::optional<String> elementID, std::optional<bool> scrollIntoView, Function<void (CommandResult&&)>&& completionHandler)
2141 {
2142     if (!m_toplevelBrowsingContext) {
2143         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
2144         return;
2145     }
2146
2147     handleUserPrompts([this, elementID, scrollIntoView, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
2148         if (result.isError()) {
2149             completionHandler(WTFMove(result));
2150             return;
2151         }
2152         RefPtr<JSON::Object> parameters = JSON::Object::create();
2153         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
2154         if (m_currentBrowsingContext)
2155             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
2156         if (elementID)
2157             parameters->setString(ASCIILiteral("nodeHandle"), elementID.value());
2158         else
2159             parameters->setBoolean(ASCIILiteral("clipToViewport"), true);
2160         if (scrollIntoView.value_or(false))
2161             parameters->setBoolean(ASCIILiteral("scrollIntoViewIfNeeded"), true);
2162         m_host->sendCommandToBackend(ASCIILiteral("takeScreenshot"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
2163             if (response.isError || !response.responseObject) {
2164                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
2165                 return;
2166             }
2167             String data;
2168             if (!response.responseObject->getString(ASCIILiteral("data"), data)) {
2169                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
2170                 return;
2171             }
2172             completionHandler(CommandResult::success(JSON::Value::create(data)));
2173         });
2174     });
2175 }
2176
2177 } // namespace WebDriver