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