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