7ed56961917666266fe1645acb074c38afc305d0
[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 <inspector/InspectorValues.h>
33 #include <wtf/CryptographicallyRandomNumber.h>
34 #include <wtf/HexNumber.h>
35 #include <wtf/UUID.h>
36
37 using namespace Inspector;
38
39 namespace WebDriver {
40
41 // The web element identifier is a constant defined by the spec in Section 11 Elements.
42 // https://www.w3.org/TR/webdriver/#elements
43 static const String webElementIdentifier = ASCIILiteral("element-6066-11e4-a52e-4f735466cecf");
44
45 Session::Session(std::unique_ptr<SessionHost>&& host)
46     : m_host(WTFMove(host))
47     , m_id(createCanonicalUUIDString())
48 {
49 }
50
51 Session::~Session()
52 {
53 }
54
55 const Capabilities& Session::capabilities() const
56 {
57     return m_host->capabilities();
58 }
59
60 void Session::close(Function<void (CommandResult&&)>&& completionHandler)
61 {
62     if (!m_toplevelBrowsingContext) {
63         completionHandler(CommandResult::success());
64         return;
65     }
66
67     RefPtr<InspectorObject> parameters = InspectorObject::create();
68     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
69     m_host->sendCommandToBackend(ASCIILiteral("closeBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
70         if (response.isError) {
71             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
72             return;
73         }
74         switchToTopLevelBrowsingContext(std::nullopt);
75         completionHandler(CommandResult::success());
76     });
77 }
78
79 void Session::setTimeouts(const Timeouts& timeouts, Function<void (CommandResult&&)>&& completionHandler)
80 {
81     if (timeouts.script)
82         m_timeouts.script = timeouts.script;
83     if (timeouts.pageLoad)
84         m_timeouts.pageLoad = timeouts.pageLoad;
85     if (timeouts.implicit)
86         m_timeouts.implicit = timeouts.implicit;
87     completionHandler(CommandResult::success());
88 }
89
90 void Session::switchToTopLevelBrowsingContext(std::optional<String> toplevelBrowsingContext)
91 {
92     m_toplevelBrowsingContext = toplevelBrowsingContext;
93     m_currentBrowsingContext = std::nullopt;
94 }
95
96 void Session::switchToBrowsingContext(std::optional<String> browsingContext)
97 {
98     // Automation sends empty strings for main frame.
99     if (!browsingContext || browsingContext.value().isEmpty())
100         m_currentBrowsingContext = std::nullopt;
101     else
102         m_currentBrowsingContext = browsingContext;
103 }
104
105 std::optional<String> Session::pageLoadStrategyString() const
106 {
107     if (!capabilities().pageLoadStrategy)
108         return std::nullopt;
109
110     switch (capabilities().pageLoadStrategy.value()) {
111     case PageLoadStrategy::None:
112         return String("None");
113     case PageLoadStrategy::Normal:
114         return String("Normal");
115     case PageLoadStrategy::Eager:
116         return String("Eager");
117     }
118
119     return std::nullopt;
120 }
121
122 void Session::createTopLevelBrowsingContext(Function<void (CommandResult&&)>&& completionHandler)
123 {
124     ASSERT(!m_toplevelBrowsingContext.value());
125     m_host->startAutomationSession(m_id, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<String> errorMessage) mutable {
126         if (errorMessage) {
127             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError, errorMessage.value()));
128             return;
129         }
130         m_host->sendCommandToBackend(ASCIILiteral("createBrowsingContext"), nullptr, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
131             if (response.isError || !response.responseObject) {
132                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
133                 return;
134             }
135             String handle;
136             if (!response.responseObject->getString(ASCIILiteral("handle"), handle)) {
137                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
138                 return;
139             }
140             switchToTopLevelBrowsingContext(handle);
141             completionHandler(CommandResult::success());
142         });
143     });
144 }
145
146 void Session::handleUserPrompts(Function<void (CommandResult&&)>&& completionHandler)
147 {
148     RefPtr<InspectorObject> parameters = InspectorObject::create();
149     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
150     m_host->sendCommandToBackend(ASCIILiteral("isShowingJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
151         if (response.isError || !response.responseObject) {
152             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
153             return;
154         }
155         bool isShowingJavaScriptDialog;
156         if (!response.responseObject->getBoolean("result", isShowingJavaScriptDialog)) {
157             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
158             return;
159         }
160
161         if (!isShowingJavaScriptDialog) {
162             completionHandler(CommandResult::success());
163             return;
164         }
165
166         if (!capabilities().unhandledPromptBehavior) {
167             reportUnexpectedAlertOpen([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
168                 dismissAlert([this, errorResult = WTFMove(result), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
169                     if (result.isError()) {
170                         completionHandler(WTFMove(result));
171                         return;
172                     }
173                     completionHandler(WTFMove(errorResult));
174                 });
175             });
176             return;
177         }
178
179         switch (capabilities().unhandledPromptBehavior.value()) {
180         case UnhandledPromptBehavior::Dismiss:
181             dismissAlert(WTFMove(completionHandler));
182             break;
183         case UnhandledPromptBehavior::Accept:
184             acceptAlert(WTFMove(completionHandler));
185             break;
186         case UnhandledPromptBehavior::Ignore:
187             reportUnexpectedAlertOpen(WTFMove(completionHandler));
188             break;
189         }
190     });
191 }
192
193 void Session::reportUnexpectedAlertOpen(Function<void (CommandResult&&)>&& completionHandler)
194 {
195     getAlertText([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) {
196         std::optional<String> alertText;
197         if (!result.isError()) {
198             String valueString;
199             if (result.result()->asString(valueString))
200                 alertText = valueString;
201         }
202         auto errorResult = CommandResult::fail(CommandResult::ErrorCode::UnexpectedAlertOpen);
203         if (alertText) {
204             RefPtr<InspectorObject> additonalData = InspectorObject::create();
205             additonalData->setString(ASCIILiteral("text"), alertText.value());
206             errorResult.setAdditionalErrorData(WTFMove(additonalData));
207         }
208         completionHandler(WTFMove(errorResult));
209     });
210 }
211
212 void Session::go(const String& url, Function<void (CommandResult&&)>&& completionHandler)
213 {
214     if (!m_toplevelBrowsingContext) {
215         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
216         return;
217     }
218
219     handleUserPrompts([this, url, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
220         if (result.isError()) {
221             completionHandler(WTFMove(result));
222             return;
223         }
224
225         RefPtr<InspectorObject> parameters = InspectorObject::create();
226         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
227         parameters->setString(ASCIILiteral("url"), url);
228         if (m_timeouts.pageLoad)
229             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
230         if (auto pageLoadStrategy = pageLoadStrategyString())
231             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
232         m_host->sendCommandToBackend(ASCIILiteral("navigateBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
233             if (response.isError) {
234                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
235                 return;
236             }
237             switchToBrowsingContext(std::nullopt);
238             completionHandler(CommandResult::success());
239         });
240     });
241 }
242
243 void Session::getCurrentURL(Function<void (CommandResult&&)>&& completionHandler)
244 {
245     if (!m_toplevelBrowsingContext) {
246         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
247         return;
248     }
249
250     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
251         if (result.isError()) {
252             completionHandler(WTFMove(result));
253             return;
254         }
255
256         RefPtr<InspectorObject> parameters = InspectorObject::create();
257         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
258         m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
259             if (response.isError || !response.responseObject) {
260                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
261                 return;
262             }
263             RefPtr<InspectorObject> browsingContext;
264             if (!response.responseObject->getObject("context", browsingContext)) {
265                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
266                 return;
267             }
268             String url;
269             if (!browsingContext->getString("url", url)) {
270                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
271                 return;
272             }
273             completionHandler(CommandResult::success(InspectorValue::create(url)));
274         });
275     });
276 }
277
278 void Session::back(Function<void (CommandResult&&)>&& completionHandler)
279 {
280     if (!m_toplevelBrowsingContext) {
281         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
282         return;
283     }
284
285     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
286         if (result.isError()) {
287             completionHandler(WTFMove(result));
288             return;
289         }
290         RefPtr<InspectorObject> parameters = InspectorObject::create();
291         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
292         if (m_timeouts.pageLoad)
293             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
294         if (auto pageLoadStrategy = pageLoadStrategyString())
295             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
296         m_host->sendCommandToBackend(ASCIILiteral("goBackInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
297             if (response.isError) {
298                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
299                 return;
300             }
301             switchToBrowsingContext(std::nullopt);
302             completionHandler(CommandResult::success());
303         });
304     });
305 }
306
307 void Session::forward(Function<void (CommandResult&&)>&& completionHandler)
308 {
309     if (!m_toplevelBrowsingContext) {
310         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
311         return;
312     }
313
314     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
315         if (result.isError()) {
316             completionHandler(WTFMove(result));
317             return;
318         }
319         RefPtr<InspectorObject> parameters = InspectorObject::create();
320         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
321         if (m_timeouts.pageLoad)
322             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
323         if (auto pageLoadStrategy = pageLoadStrategyString())
324             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
325         m_host->sendCommandToBackend(ASCIILiteral("goForwardInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
326             if (response.isError) {
327                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
328                 return;
329             }
330             switchToBrowsingContext(std::nullopt);
331             completionHandler(CommandResult::success());
332         });
333     });
334 }
335
336 void Session::refresh(Function<void (CommandResult&&)>&& completionHandler)
337 {
338     if (!m_toplevelBrowsingContext) {
339         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
340         return;
341     }
342
343     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
344         if (result.isError()) {
345             completionHandler(WTFMove(result));
346             return;
347         }
348         RefPtr<InspectorObject> parameters = InspectorObject::create();
349         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
350         if (m_timeouts.pageLoad)
351             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
352         if (auto pageLoadStrategy = pageLoadStrategyString())
353             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
354         m_host->sendCommandToBackend(ASCIILiteral("reloadBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
355             if (response.isError) {
356                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
357                 return;
358             }
359             switchToBrowsingContext(std::nullopt);
360             completionHandler(CommandResult::success());
361         });
362     });
363 }
364
365 void Session::getTitle(Function<void (CommandResult&&)>&& completionHandler)
366 {
367     if (!m_toplevelBrowsingContext) {
368         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
369         return;
370     }
371
372     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
373         if (result.isError()) {
374             completionHandler(WTFMove(result));
375             return;
376         }
377         RefPtr<InspectorObject> parameters = InspectorObject::create();
378         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
379         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function() { return document.title; }"));
380         parameters->setArray(ASCIILiteral("arguments"), InspectorArray::create());
381         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
382             if (response.isError || !response.responseObject) {
383                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
384                 return;
385             }
386             String valueString;
387             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
388                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
389                 return;
390             }
391             RefPtr<InspectorValue> resultValue;
392             if (!InspectorValue::parseJSON(valueString, resultValue)) {
393                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
394                 return;
395             }
396             completionHandler(CommandResult::success(WTFMove(resultValue)));
397         });
398     });
399 }
400
401 void Session::getWindowHandle(Function<void (CommandResult&&)>&& completionHandler)
402 {
403     if (!m_toplevelBrowsingContext) {
404         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
405         return;
406     }
407
408     RefPtr<InspectorObject> parameters = InspectorObject::create();
409     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
410     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
411         if (response.isError || !response.responseObject) {
412             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
413             return;
414         }
415         RefPtr<InspectorObject> browsingContext;
416         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
417             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
418             return;
419         }
420         String handle;
421         if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
422             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
423             return;
424         }
425         completionHandler(CommandResult::success(InspectorValue::create(handle)));
426     });
427 }
428
429 void Session::closeWindow(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         close(WTFMove(completionHandler));
442     });
443 }
444
445 void Session::switchToWindow(const String& windowHandle, Function<void (CommandResult&&)>&& completionHandler)
446 {
447     RefPtr<InspectorObject> parameters = InspectorObject::create();
448     parameters->setString(ASCIILiteral("browsingContextHandle"), windowHandle);
449     m_host->sendCommandToBackend(ASCIILiteral("switchToBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), windowHandle, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
450         if (response.isError) {
451             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
452             return;
453         }
454         switchToTopLevelBrowsingContext(windowHandle);
455         completionHandler(CommandResult::success());
456     });
457 }
458
459 void Session::getWindowHandles(Function<void (CommandResult&&)>&& completionHandler)
460 {
461     if (!m_toplevelBrowsingContext) {
462         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
463         return;
464     }
465
466     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContexts"), InspectorObject::create(), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
467         if (response.isError || !response.responseObject) {
468             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
469             return;
470         }
471         RefPtr<InspectorArray> browsingContextArray;
472         if (!response.responseObject->getArray(ASCIILiteral("contexts"), browsingContextArray)) {
473             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
474             return;
475         }
476         RefPtr<InspectorArray> windowHandles = InspectorArray::create();
477         for (unsigned i = 0; i < browsingContextArray->length(); ++i) {
478             RefPtr<InspectorValue> browsingContextValue = browsingContextArray->get(i);
479             RefPtr<InspectorObject> browsingContext;
480             if (!browsingContextValue->asObject(browsingContext)) {
481                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
482                 return;
483             }
484
485             String handle;
486             if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
487                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
488                 return;
489             }
490
491             windowHandles->pushString(handle);
492         }
493         completionHandler(CommandResult::success(WTFMove(windowHandles)));
494     });
495 }
496
497 void Session::switchToFrame(RefPtr<InspectorValue>&& frameID, Function<void (CommandResult&&)>&& completionHandler)
498 {
499     if (!m_toplevelBrowsingContext) {
500         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
501         return;
502     }
503
504     if (frameID->isNull()) {
505         switchToBrowsingContext(std::nullopt);
506         completionHandler(CommandResult::success());
507         return;
508     }
509
510     handleUserPrompts([this, frameID = WTFMove(frameID), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
511         if (result.isError()) {
512             completionHandler(WTFMove(result));
513             return;
514         }
515         RefPtr<InspectorObject> parameters = InspectorObject::create();
516         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
517         if (m_currentBrowsingContext)
518             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
519
520         int frameIndex;
521         if (frameID->asInteger(frameIndex)) {
522             if (frameIndex < 0 || frameIndex > USHRT_MAX) {
523                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
524                 return;
525             }
526             parameters->setInteger(ASCIILiteral("ordinal"), frameIndex);
527         } else {
528             String frameElementID = extractElementID(*frameID);
529             if (!frameElementID.isEmpty())
530                 parameters->setString(ASCIILiteral("nodeHandle"), frameElementID);
531             else {
532                 String frameName;
533                 if (!frameID->asString(frameName)) {
534                     completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
535                     return;
536                 }
537                 parameters->setString(ASCIILiteral("name"), frameName);
538             }
539         }
540
541         m_host->sendCommandToBackend(ASCIILiteral("resolveChildFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
542             if (response.isError || !response.responseObject) {
543                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
544                 return;
545             }
546             String frameHandle;
547             if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
548                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
549                 return;
550             }
551             switchToBrowsingContext(frameHandle);
552             completionHandler(CommandResult::success());
553         });
554     });
555 }
556
557 void Session::switchToParentFrame(Function<void (CommandResult&&)>&& completionHandler)
558 {
559     if (!m_toplevelBrowsingContext) {
560         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
561         return;
562     }
563
564     if (!m_currentBrowsingContext) {
565         completionHandler(CommandResult::success());
566         return;
567     }
568
569     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
570         if (result.isError()) {
571             completionHandler(WTFMove(result));
572             return;
573         }
574         RefPtr<InspectorObject> parameters = InspectorObject::create();
575         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
576         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
577         m_host->sendCommandToBackend(ASCIILiteral("resolveParentFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
578             if (response.isError || !response.responseObject) {
579                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
580                 return;
581             }
582             String frameHandle;
583             if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
584                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
585                 return;
586             }
587             switchToBrowsingContext(frameHandle);
588             completionHandler(CommandResult::success());
589         });
590     });
591 }
592
593 void Session::getWindowPosition(Function<void (CommandResult&&)>&& completionHandler)
594 {
595     if (!m_toplevelBrowsingContext) {
596         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
597         return;
598     }
599
600     RefPtr<InspectorObject> parameters = InspectorObject::create();
601     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
602     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
603         if (response.isError || !response.responseObject) {
604             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
605             return;
606         }
607         RefPtr<InspectorObject> browsingContext;
608         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
609             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
610             return;
611         }
612         RefPtr<InspectorObject> windowOrigin;
613         if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)) {
614             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
615             return;
616         }
617         completionHandler(CommandResult::success(WTFMove(windowOrigin)));
618     });
619 }
620
621 void Session::setWindowPosition(int windowX, int windowY, Function<void (CommandResult&&)>&& completionHandler)
622 {
623     if (!m_toplevelBrowsingContext) {
624         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
625         return;
626     }
627
628     RefPtr<InspectorObject> parameters = InspectorObject::create();
629     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
630     RefPtr<InspectorObject> windowOrigin = InspectorObject::create();
631     windowOrigin->setInteger("x", windowX);
632     windowOrigin->setInteger("y", windowY);
633     parameters->setObject(ASCIILiteral("origin"), WTFMove(windowOrigin));
634     m_host->sendCommandToBackend(ASCIILiteral("moveWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
635         if (response.isError) {
636             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
637             return;
638         }
639         completionHandler(CommandResult::success());
640     });
641 }
642
643 void Session::getWindowSize(Function<void (CommandResult&&)>&& completionHandler)
644 {
645     if (!m_toplevelBrowsingContext) {
646         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
647         return;
648     }
649
650     RefPtr<InspectorObject> parameters = InspectorObject::create();
651     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
652     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
653         if (response.isError || !response.responseObject) {
654             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
655             return;
656         }
657         RefPtr<InspectorObject> browsingContext;
658         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
659             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
660             return;
661         }
662         RefPtr<InspectorObject> windowSize;
663         if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)) {
664             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
665             return;
666         }
667         completionHandler(CommandResult::success(WTFMove(windowSize)));
668     });
669 }
670
671 void Session::setWindowSize(int windowWidth, int windowHeight, Function<void (CommandResult&&)>&& completionHandler)
672 {
673     if (!m_toplevelBrowsingContext) {
674         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
675         return;
676     }
677
678     RefPtr<InspectorObject> parameters = InspectorObject::create();
679     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
680     RefPtr<InspectorObject> windowSize = InspectorObject::create();
681     windowSize->setInteger("width", windowWidth);
682     windowSize->setInteger("height", windowHeight);
683     parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize));
684     m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
685         if (response.isError) {
686             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
687             return;
688         }
689         completionHandler(CommandResult::success());
690     });
691 }
692
693 RefPtr<InspectorObject> Session::createElement(RefPtr<InspectorValue>&& value)
694 {
695     RefPtr<InspectorObject> valueObject;
696     if (!value->asObject(valueObject))
697         return nullptr;
698
699     String elementID;
700     if (!valueObject->getString("session-node-" + m_id, elementID))
701         return nullptr;
702
703     RefPtr<InspectorObject> elementObject = InspectorObject::create();
704     elementObject->setString(webElementIdentifier, elementID);
705     return elementObject;
706 }
707
708 RefPtr<InspectorObject> Session::createElement(const String& elementID)
709 {
710     RefPtr<InspectorObject> elementObject = InspectorObject::create();
711     elementObject->setString("session-node-" + m_id, elementID);
712     return elementObject;
713 }
714
715 RefPtr<InspectorObject> Session::extractElement(InspectorValue& value)
716 {
717     String elementID = extractElementID(value);
718     return !elementID.isEmpty() ? createElement(elementID) : nullptr;
719 }
720
721 String Session::extractElementID(InspectorValue& value)
722 {
723     RefPtr<InspectorObject> valueObject;
724     if (!value.asObject(valueObject))
725         return emptyString();
726
727     String elementID;
728     if (!valueObject->getString(webElementIdentifier, elementID))
729         return emptyString();
730
731     return elementID;
732 }
733
734 void Session::computeElementLayout(const String& elementID, OptionSet<ElementLayoutOption> options, Function<void (std::optional<Rect>&&, std::optional<Point>&&, bool, RefPtr<InspectorObject>&&)>&& completionHandler)
735 {
736     ASSERT(m_toplevelBrowsingContext.value());
737
738     RefPtr<InspectorObject> parameters = InspectorObject::create();
739     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
740     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
741     parameters->setString(ASCIILiteral("nodeHandle"), elementID);
742     parameters->setBoolean(ASCIILiteral("scrollIntoViewIfNeeded"), options.contains(ElementLayoutOption::ScrollIntoViewIfNeeded));
743     parameters->setBoolean(ASCIILiteral("useViewportCoordinates"), options.contains(ElementLayoutOption::UseViewportCoordinates));
744     m_host->sendCommandToBackend(ASCIILiteral("computeElementLayout"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
745         if (response.isError || !response.responseObject) {
746             completionHandler(std::nullopt, std::nullopt, false, WTFMove(response.responseObject));
747             return;
748         }
749         RefPtr<InspectorObject> rectObject;
750         if (!response.responseObject->getObject(ASCIILiteral("rect"), rectObject)) {
751             completionHandler(std::nullopt, std::nullopt, false, nullptr);
752             return;
753         }
754         std::optional<int> elementX;
755         std::optional<int> elementY;
756         RefPtr<InspectorObject> elementPosition;
757         if (rectObject->getObject(ASCIILiteral("origin"), elementPosition)) {
758             int x, y;
759             if (elementPosition->getInteger(ASCIILiteral("x"), x) && elementPosition->getInteger(ASCIILiteral("y"), y)) {
760                 elementX = x;
761                 elementY = y;
762             }
763         }
764         if (!elementX || !elementY) {
765             completionHandler(std::nullopt, std::nullopt, false, nullptr);
766             return;
767         }
768         std::optional<int> elementWidth;
769         std::optional<int> elementHeight;
770         RefPtr<InspectorObject> elementSize;
771         if (rectObject->getObject(ASCIILiteral("size"), elementSize)) {
772             int width, height;
773             if (elementSize->getInteger(ASCIILiteral("width"), width) && elementSize->getInteger(ASCIILiteral("height"), height)) {
774                 elementWidth = width;
775                 elementHeight = height;
776             }
777         }
778         if (!elementWidth || !elementHeight) {
779             completionHandler(std::nullopt, std::nullopt, false, nullptr);
780             return;
781         }
782         Rect rect = { { elementX.value(), elementY.value() }, { elementWidth.value(), elementHeight.value() } };
783
784         bool isObscured;
785         if (!response.responseObject->getBoolean(ASCIILiteral("isObscured"), isObscured)) {
786             completionHandler(std::nullopt, std::nullopt, false, nullptr);
787             return;
788         }
789         RefPtr<InspectorObject> inViewCenterPointObject;
790         if (!response.responseObject->getObject(ASCIILiteral("inViewCenterPoint"), inViewCenterPointObject)) {
791             completionHandler(rect, std::nullopt, isObscured, nullptr);
792             return;
793         }
794         int inViewCenterPointX, inViewCenterPointY;
795         if (!inViewCenterPointObject->getInteger(ASCIILiteral("x"), inViewCenterPointX)
796             || !inViewCenterPointObject->getInteger(ASCIILiteral("y"), inViewCenterPointY)) {
797             completionHandler(std::nullopt, std::nullopt, isObscured, nullptr);
798             return;
799         }
800         Point inViewCenterPoint = { inViewCenterPointX, inViewCenterPointY };
801         completionHandler(rect, inViewCenterPoint, isObscured, nullptr);
802     });
803 }
804
805 void Session::findElements(const String& strategy, const String& selector, FindElementsMode mode, const String& rootElementID, Function<void (CommandResult&&)>&& completionHandler)
806 {
807     if (!m_toplevelBrowsingContext) {
808         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
809         return;
810     }
811
812     auto implicitWait = m_timeouts.implicit.value_or(0_s);
813     RefPtr<InspectorArray> arguments = InspectorArray::create();
814     arguments->pushString(InspectorValue::create(strategy)->toJSONString());
815     if (rootElementID.isEmpty())
816         arguments->pushString(InspectorValue::null()->toJSONString());
817     else
818         arguments->pushString(createElement(rootElementID)->toJSONString());
819     arguments->pushString(InspectorValue::create(selector)->toJSONString());
820     arguments->pushString(InspectorValue::create(mode == FindElementsMode::Single)->toJSONString());
821     arguments->pushString(InspectorValue::create(implicitWait.milliseconds())->toJSONString());
822
823     RefPtr<InspectorObject> parameters = InspectorObject::create();
824     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
825     if (m_currentBrowsingContext)
826         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
827     parameters->setString(ASCIILiteral("function"), FindNodesJavaScript);
828     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
829     parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
830     // If there's an implicit wait, use one second more as callback timeout.
831     if (implicitWait)
832         parameters->setInteger(ASCIILiteral("callbackTimeout"), Seconds(implicitWait + 1_s).millisecondsAs<int>());
833
834     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), mode, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
835         if (response.isError || !response.responseObject) {
836             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
837             return;
838         }
839         String valueString;
840         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
841             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
842             return;
843         }
844         RefPtr<InspectorValue> resultValue;
845         if (!InspectorValue::parseJSON(valueString, resultValue)) {
846             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
847             return;
848         }
849
850         switch (mode) {
851         case FindElementsMode::Single: {
852             RefPtr<InspectorObject> elementObject = createElement(WTFMove(resultValue));
853             if (!elementObject) {
854                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
855                 return;
856             }
857             completionHandler(CommandResult::success(WTFMove(elementObject)));
858             break;
859         }
860         case FindElementsMode::Multiple: {
861             RefPtr<InspectorArray> elementsArray;
862             if (!resultValue->asArray(elementsArray)) {
863                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
864                 return;
865             }
866             RefPtr<InspectorArray> elementObjectsArray = InspectorArray::create();
867             unsigned elementsArrayLength = elementsArray->length();
868             for (unsigned i = 0; i < elementsArrayLength; ++i) {
869                 if (auto elementObject = createElement(elementsArray->get(i)))
870                     elementObjectsArray->pushObject(WTFMove(elementObject));
871             }
872             completionHandler(CommandResult::success(WTFMove(elementObjectsArray)));
873             break;
874         }
875         }
876     });
877 }
878
879 void Session::isElementSelected(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
880 {
881     if (!m_toplevelBrowsingContext) {
882         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
883         return;
884     }
885
886     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
887         if (result.isError()) {
888             completionHandler(WTFMove(result));
889             return;
890         }
891         RefPtr<InspectorArray> arguments = InspectorArray::create();
892         arguments->pushString(createElement(elementID)->toJSONString());
893         arguments->pushString(InspectorValue::create("selected")->toJSONString());
894
895         RefPtr<InspectorObject> parameters = InspectorObject::create();
896         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
897         if (m_currentBrowsingContext)
898             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
899         parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
900         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
901         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
902             if (response.isError || !response.responseObject) {
903                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
904                 return;
905             }
906             String valueString;
907             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
908                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
909                 return;
910             }
911             RefPtr<InspectorValue> resultValue;
912             if (!InspectorValue::parseJSON(valueString, resultValue)) {
913                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
914                 return;
915             }
916             if (resultValue->isNull()) {
917                 completionHandler(CommandResult::success(InspectorValue::create(false)));
918                 return;
919             }
920             String booleanResult;
921             if (!resultValue->asString(booleanResult) || booleanResult != "true") {
922                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
923                 return;
924             }
925             completionHandler(CommandResult::success(InspectorValue::create(true)));
926         });
927     });
928 }
929
930 void Session::getElementText(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
931 {
932     if (!m_toplevelBrowsingContext) {
933         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
934         return;
935     }
936
937     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
938         if (result.isError()) {
939             completionHandler(WTFMove(result));
940             return;
941         }
942         RefPtr<InspectorArray> arguments = InspectorArray::create();
943         arguments->pushString(createElement(elementID)->toJSONString());
944
945         RefPtr<InspectorObject> parameters = InspectorObject::create();
946         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
947         if (m_currentBrowsingContext)
948             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
949         // FIXME: Add an atom to properly implement this instead of just using innerText.
950         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.innerText.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g, '') }"));
951         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
952         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
953             if (response.isError || !response.responseObject) {
954                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
955                 return;
956             }
957             String valueString;
958             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
959                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
960                 return;
961             }
962             RefPtr<InspectorValue> resultValue;
963             if (!InspectorValue::parseJSON(valueString, resultValue)) {
964                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
965                 return;
966             }
967             completionHandler(CommandResult::success(WTFMove(resultValue)));
968         });
969     });
970 }
971
972 void Session::getElementTagName(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
973 {
974     if (!m_toplevelBrowsingContext) {
975         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
976         return;
977     }
978
979     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
980         if (result.isError()) {
981             completionHandler(WTFMove(result));
982             return;
983         }
984         RefPtr<InspectorArray> arguments = InspectorArray::create();
985         arguments->pushString(createElement(elementID)->toJSONString());
986
987         RefPtr<InspectorObject> parameters = InspectorObject::create();
988         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
989         if (m_currentBrowsingContext)
990             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
991         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.tagName.toLowerCase() }"));
992         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
993         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
994             if (response.isError || !response.responseObject) {
995                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
996                 return;
997             }
998             String valueString;
999             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1000                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1001                 return;
1002             }
1003             RefPtr<InspectorValue> resultValue;
1004             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1005                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1006                 return;
1007             }
1008             completionHandler(CommandResult::success(WTFMove(resultValue)));
1009         });
1010     });
1011 }
1012
1013 void Session::getElementRect(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1014 {
1015     if (!m_toplevelBrowsingContext) {
1016         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1017         return;
1018     }
1019
1020     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1021         if (result.isError()) {
1022             completionHandler(WTFMove(result));
1023             return;
1024         }
1025         computeElementLayout(elementID, { }, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&&, bool, RefPtr<InspectorObject>&& error) {
1026             if (!rect || error) {
1027                 completionHandler(CommandResult::fail(WTFMove(error)));
1028                 return;
1029             }
1030             RefPtr<InspectorObject> rectObject = InspectorObject::create();
1031             rectObject->setInteger(ASCIILiteral("x"), rect.value().origin.x);
1032             rectObject->setInteger(ASCIILiteral("y"), rect.value().origin.y);
1033             rectObject->setInteger(ASCIILiteral("width"), rect.value().size.width);
1034             rectObject->setInteger(ASCIILiteral("height"), rect.value().size.height);
1035             completionHandler(CommandResult::success(WTFMove(rectObject)));
1036         });
1037     });
1038 }
1039
1040 void Session::isElementEnabled(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1041 {
1042     if (!m_toplevelBrowsingContext) {
1043         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1044         return;
1045     }
1046
1047     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1048         if (result.isError()) {
1049             completionHandler(WTFMove(result));
1050             return;
1051         }
1052         RefPtr<InspectorArray> arguments = InspectorArray::create();
1053         arguments->pushString(createElement(elementID)->toJSONString());
1054
1055         RefPtr<InspectorObject> parameters = InspectorObject::create();
1056         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1057         if (m_currentBrowsingContext)
1058             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1059         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.disabled === undefined ? true : !element.disabled }"));
1060         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1061         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1062             if (response.isError || !response.responseObject) {
1063                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1064                 return;
1065             }
1066             String valueString;
1067             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1068                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1069                 return;
1070             }
1071             RefPtr<InspectorValue> resultValue;
1072             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1073                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1074                 return;
1075             }
1076             completionHandler(CommandResult::success(WTFMove(resultValue)));
1077         });
1078     });
1079 }
1080
1081 void Session::isElementDisplayed(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1082 {
1083     if (!m_toplevelBrowsingContext) {
1084         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1085         return;
1086     }
1087
1088     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1089         if (result.isError()) {
1090             completionHandler(WTFMove(result));
1091             return;
1092         }
1093         RefPtr<InspectorArray> arguments = InspectorArray::create();
1094         arguments->pushString(createElement(elementID)->toJSONString());
1095
1096         RefPtr<InspectorObject> parameters = InspectorObject::create();
1097         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1098         if (m_currentBrowsingContext)
1099             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1100         parameters->setString(ASCIILiteral("function"), ElementDisplayedJavaScript);
1101         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1102         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1103             if (response.isError || !response.responseObject) {
1104                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1105                 return;
1106             }
1107             String valueString;
1108             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1109                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1110                 return;
1111             }
1112             RefPtr<InspectorValue> resultValue;
1113             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1114                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1115                 return;
1116             }
1117             completionHandler(CommandResult::success(WTFMove(resultValue)));
1118         });
1119     });
1120 }
1121
1122 void Session::getElementAttribute(const String& elementID, const String& attribute, Function<void (CommandResult&&)>&& completionHandler)
1123 {
1124     if (!m_toplevelBrowsingContext) {
1125         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1126         return;
1127     }
1128
1129     handleUserPrompts([this, elementID, attribute, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1130         if (result.isError()) {
1131             completionHandler(WTFMove(result));
1132             return;
1133         }
1134         RefPtr<InspectorArray> arguments = InspectorArray::create();
1135         arguments->pushString(createElement(elementID)->toJSONString());
1136         arguments->pushString(InspectorValue::create(attribute)->toJSONString());
1137
1138         RefPtr<InspectorObject> parameters = InspectorObject::create();
1139         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1140         if (m_currentBrowsingContext)
1141             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1142         parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
1143         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1144         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1145             if (response.isError || !response.responseObject) {
1146                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1147                 return;
1148             }
1149             String valueString;
1150             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1151                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1152                 return;
1153             }
1154             RefPtr<InspectorValue> resultValue;
1155             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1156                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1157                 return;
1158             }
1159             completionHandler(CommandResult::success(WTFMove(resultValue)));
1160         });
1161     });
1162 }
1163
1164 void Session::waitForNavigationToComplete(Function<void (CommandResult&&)>&& completionHandler)
1165 {
1166     if (!m_toplevelBrowsingContext) {
1167         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1168         return;
1169     }
1170
1171     RefPtr<InspectorObject> parameters = InspectorObject::create();
1172     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1173     if (m_currentBrowsingContext)
1174         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1175     if (m_timeouts.pageLoad)
1176         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
1177     if (auto pageLoadStrategy = pageLoadStrategyString())
1178         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
1179     m_host->sendCommandToBackend(ASCIILiteral("waitForNavigationToComplete"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1180         if (response.isError) {
1181             auto result = CommandResult::fail(WTFMove(response.responseObject));
1182             if (result.errorCode() == CommandResult::ErrorCode::NoSuchFrame) {
1183                 // Navigation destroyed the current frame, switch to top level browsing context and ignore the error.
1184                 switchToBrowsingContext(std::nullopt);
1185             } else {
1186                 completionHandler(WTFMove(result));
1187                 return;
1188             }
1189         }
1190         completionHandler(CommandResult::success());
1191     });
1192 }
1193
1194 void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1195 {
1196     if (!m_toplevelBrowsingContext) {
1197         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1198         return;
1199     }
1200
1201     OptionSet<ElementLayoutOption> options = ElementLayoutOption::ScrollIntoViewIfNeeded;
1202     options |= ElementLayoutOption::UseViewportCoordinates;
1203     computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<InspectorObject>&& error) mutable {
1204         if (!rect || error) {
1205             completionHandler(CommandResult::fail(WTFMove(error)));
1206             return;
1207         }
1208         if (isObscured) {
1209             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementClickIntercepted));
1210             return;
1211         }
1212         if (!inViewCenter) {
1213             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementNotInteractable));
1214             return;
1215         }
1216
1217         performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(completionHandler));
1218
1219         waitForNavigationToComplete(WTFMove(completionHandler));
1220     });
1221 }
1222
1223 void Session::elementClear(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1224 {
1225     if (!m_toplevelBrowsingContext) {
1226         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1227         return;
1228     }
1229
1230     RefPtr<InspectorArray> arguments = InspectorArray::create();
1231     arguments->pushString(createElement(elementID)->toJSONString());
1232
1233     RefPtr<InspectorObject> parameters = InspectorObject::create();
1234     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1235     if (m_currentBrowsingContext)
1236         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1237     parameters->setString(ASCIILiteral("function"), FormElementClearJavaScript);
1238     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1239     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1240         if (response.isError) {
1241             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1242             return;
1243         }
1244         completionHandler(CommandResult::success());
1245     });
1246 }
1247
1248 String Session::virtualKeyForKeySequence(const String& keySequence, KeyModifier& modifier)
1249 {
1250     // ยง17.4.2 Keyboard Actions.
1251     // https://www.w3.org/TR/webdriver/#keyboard-actions
1252     modifier = KeyModifier::None;
1253     switch (keySequence[0]) {
1254     case 0xE001U:
1255         return ASCIILiteral("Cancel");
1256     case 0xE002U:
1257         return ASCIILiteral("Help");
1258     case 0xE003U:
1259         return ASCIILiteral("Backspace");
1260     case 0xE004U:
1261         return ASCIILiteral("Tab");
1262     case 0xE005U:
1263         return ASCIILiteral("Clear");
1264     case 0xE006U:
1265         return ASCIILiteral("Return");
1266     case 0xE007U:
1267         return ASCIILiteral("Enter");
1268     case 0xE008U:
1269         modifier = KeyModifier::Shift;
1270         return ASCIILiteral("Shift");
1271     case 0xE009U:
1272         modifier = KeyModifier::Control;
1273         return ASCIILiteral("Control");
1274     case 0xE00AU:
1275         modifier = KeyModifier::Alternate;
1276         return ASCIILiteral("Alternate");
1277     case 0xE00BU:
1278         return ASCIILiteral("Pause");
1279     case 0xE00CU:
1280         return ASCIILiteral("Escape");
1281     case 0xE00DU:
1282         return ASCIILiteral("Space");
1283     case 0xE00EU:
1284         return ASCIILiteral("PageUp");
1285     case 0xE00FU:
1286         return ASCIILiteral("PageDown");
1287     case 0xE010U:
1288         return ASCIILiteral("End");
1289     case 0xE011U:
1290         return ASCIILiteral("Home");
1291     case 0xE012U:
1292         return ASCIILiteral("LeftArrow");
1293     case 0xE013U:
1294         return ASCIILiteral("UpArrow");
1295     case 0xE014U:
1296         return ASCIILiteral("RightArrow");
1297     case 0xE015U:
1298         return ASCIILiteral("DownArrow");
1299     case 0xE016U:
1300         return ASCIILiteral("Insert");
1301     case 0xE017U:
1302         return ASCIILiteral("Delete");
1303     case 0xE018U:
1304         return ASCIILiteral("Semicolon");
1305     case 0xE019U:
1306         return ASCIILiteral("Equals");
1307     case 0xE01AU:
1308         return ASCIILiteral("NumberPad0");
1309     case 0xE01BU:
1310         return ASCIILiteral("NumberPad1");
1311     case 0xE01CU:
1312         return ASCIILiteral("NumberPad2");
1313     case 0xE01DU:
1314         return ASCIILiteral("NumberPad3");
1315     case 0xE01EU:
1316         return ASCIILiteral("NumberPad4");
1317     case 0xE01FU:
1318         return ASCIILiteral("NumberPad5");
1319     case 0xE020U:
1320         return ASCIILiteral("NumberPad6");
1321     case 0xE021U:
1322         return ASCIILiteral("NumberPad7");
1323     case 0xE022U:
1324         return ASCIILiteral("NumberPad8");
1325     case 0xE023U:
1326         return ASCIILiteral("NumberPad9");
1327     case 0xE024U:
1328         return ASCIILiteral("NumberPadMultiply");
1329     case 0xE025U:
1330         return ASCIILiteral("NumberPadAdd");
1331     case 0xE026U:
1332         return ASCIILiteral("NumberPadSeparator");
1333     case 0xE027U:
1334         return ASCIILiteral("NumberPadSubtract");
1335     case 0xE028U:
1336         return ASCIILiteral("NumberPadDecimal");
1337     case 0xE029U:
1338         return ASCIILiteral("NumberPadDivide");
1339     case 0xE031U:
1340         return ASCIILiteral("Function1");
1341     case 0xE032U:
1342         return ASCIILiteral("Function2");
1343     case 0xE033U:
1344         return ASCIILiteral("Function3");
1345     case 0xE034U:
1346         return ASCIILiteral("Function4");
1347     case 0xE035U:
1348         return ASCIILiteral("Function5");
1349     case 0xE036U:
1350         return ASCIILiteral("Function6");
1351     case 0xE037U:
1352         return ASCIILiteral("Function7");
1353     case 0xE038U:
1354         return ASCIILiteral("Function8");
1355     case 0xE039U:
1356         return ASCIILiteral("Function9");
1357     case 0xE03AU:
1358         return ASCIILiteral("Function10");
1359     case 0xE03BU:
1360         return ASCIILiteral("Function11");
1361     case 0xE03CU:
1362         return ASCIILiteral("Function12");
1363     case 0xE03DU:
1364         modifier = KeyModifier::Meta;
1365         return ASCIILiteral("Meta");
1366     default:
1367         break;
1368     }
1369     return String();
1370 }
1371
1372 void Session::elementSendKeys(const String& elementID, Vector<String>&& keys, Function<void (CommandResult&&)>&& completionHandler)
1373 {
1374     if (!m_toplevelBrowsingContext) {
1375         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1376         return;
1377     }
1378
1379     handleUserPrompts([this, elementID, keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1380         if (result.isError()) {
1381             completionHandler(WTFMove(result));
1382             return;
1383         }
1384         // FIXME: move this to an atom.
1385         static const char focusScript[] =
1386             "function focus(element) {"
1387             "    var doc = element.ownerDocument || element;"
1388             "    var prevActiveElement = doc.activeElement;"
1389             "    if (element != prevActiveElement && prevActiveElement)"
1390             "        prevActiveElement.blur();"
1391             "    element.focus();"
1392             "    if (element != prevActiveElement && element.value && element.value.length && element.setSelectionRange)"
1393             "        element.setSelectionRange(element.value.length, element.value.length);"
1394             "    if (element != doc.activeElement)"
1395             "        throw new Error('cannot focus element');"
1396             "}";
1397
1398         RefPtr<InspectorArray> arguments = InspectorArray::create();
1399         arguments->pushString(createElement(elementID)->toJSONString());
1400         RefPtr<InspectorObject> parameters = InspectorObject::create();
1401         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1402         if (m_currentBrowsingContext)
1403             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1404         parameters->setString(ASCIILiteral("function"), focusScript);
1405         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1406         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
1407             if (response.isError || !response.responseObject) {
1408                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1409                 return;
1410             }
1411
1412             unsigned stickyModifiers = 0;
1413             Vector<KeyboardInteraction> interactions;
1414             interactions.reserveInitialCapacity(keys.size());
1415             for (const auto& key : keys) {
1416                 KeyboardInteraction interaction;
1417                 KeyModifier modifier;
1418                 auto virtualKey = virtualKeyForKeySequence(key, modifier);
1419                 if (!virtualKey.isNull()) {
1420                     interaction.key = virtualKey;
1421                     if (modifier != KeyModifier::None) {
1422                         stickyModifiers ^= modifier;
1423                         if (stickyModifiers & modifier)
1424                             interaction.type = KeyboardInteractionType::KeyPress;
1425                         else
1426                             interaction.type = KeyboardInteractionType::KeyRelease;
1427                     }
1428                 } else
1429                     interaction.text = key;
1430                 interactions.uncheckedAppend(WTFMove(interaction));
1431             }
1432
1433             // Reset sticky modifiers if needed.
1434             if (stickyModifiers) {
1435                 if (stickyModifiers & KeyModifier::Shift)
1436                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Shift")) });
1437                 if (stickyModifiers & KeyModifier::Control)
1438                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Control")) });
1439                 if (stickyModifiers & KeyModifier::Alternate)
1440                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Alternate")) });
1441                 if (stickyModifiers & KeyModifier::Meta)
1442                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Meta")) });
1443             }
1444
1445             performKeyboardInteractions(WTFMove(interactions), WTFMove(completionHandler));
1446         });
1447     });
1448 }
1449
1450 void Session::elementSubmit(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1451 {
1452     if (!m_toplevelBrowsingContext) {
1453         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1454         return;
1455     }
1456
1457     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1458         if (result.isError()) {
1459             completionHandler(WTFMove(result));
1460             return;
1461         }
1462         RefPtr<InspectorArray> arguments = InspectorArray::create();
1463         arguments->pushString(createElement(elementID)->toJSONString());
1464
1465         RefPtr<InspectorObject> parameters = InspectorObject::create();
1466         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1467         if (m_currentBrowsingContext)
1468             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1469         parameters->setString(ASCIILiteral("function"), FormSubmitJavaScript);
1470         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1471         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1472             if (response.isError) {
1473                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1474                 return;
1475             }
1476             completionHandler(CommandResult::success());
1477         });
1478     });
1479 }
1480
1481 RefPtr<InspectorValue> Session::handleScriptResult(RefPtr<InspectorValue>&& resultValue)
1482 {
1483     RefPtr<InspectorArray> resultArray;
1484     if (resultValue->asArray(resultArray)) {
1485         RefPtr<InspectorArray> returnValueArray = InspectorArray::create();
1486         unsigned resultArrayLength = resultArray->length();
1487         for (unsigned i = 0; i < resultArrayLength; ++i)
1488             returnValueArray->pushValue(handleScriptResult(resultArray->get(i)));
1489         return returnValueArray;
1490     }
1491
1492     if (auto element = createElement(RefPtr<InspectorValue>(resultValue)))
1493         return element;
1494
1495     RefPtr<InspectorObject> resultObject;
1496     if (resultValue->asObject(resultObject)) {
1497         RefPtr<InspectorObject> returnValueObject = InspectorObject::create();
1498         auto end = resultObject->end();
1499         for (auto it = resultObject->begin(); it != end; ++it)
1500             returnValueObject->setValue(it->key, handleScriptResult(WTFMove(it->value)));
1501         return returnValueObject;
1502     }
1503
1504     return resultValue;
1505 }
1506
1507 void Session::executeScript(const String& script, RefPtr<InspectorArray>&& argumentsArray, ExecuteScriptMode mode, Function<void (CommandResult&&)>&& completionHandler)
1508 {
1509     if (!m_toplevelBrowsingContext) {
1510         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1511         return;
1512     }
1513
1514     handleUserPrompts([this, script, argumentsArray = WTFMove(argumentsArray), mode, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1515         if (result.isError()) {
1516             completionHandler(WTFMove(result));
1517             return;
1518         }
1519         RefPtr<InspectorArray> arguments = InspectorArray::create();
1520         unsigned argumentsLength = argumentsArray->length();
1521         for (unsigned i = 0; i < argumentsLength; ++i) {
1522             if (auto argument = argumentsArray->get(i)) {
1523                 if (auto element = extractElement(*argument))
1524                     arguments->pushString(element->toJSONString());
1525                 else
1526                     arguments->pushString(argument->toJSONString());
1527             }
1528         }
1529
1530         RefPtr<InspectorObject> parameters = InspectorObject::create();
1531         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1532         if (m_currentBrowsingContext)
1533             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1534         parameters->setString(ASCIILiteral("function"), "function(){" + script + '}');
1535         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1536         if (mode == ExecuteScriptMode::Async) {
1537             parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
1538             if (m_timeouts.script)
1539                 parameters->setInteger(ASCIILiteral("callbackTimeout"), m_timeouts.script.value().millisecondsAs<int>());
1540         }
1541         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1542             if (response.isError || !response.responseObject) {
1543                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1544                 return;
1545             }
1546             String valueString;
1547             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1548                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1549                 return;
1550             }
1551             if (valueString.isEmpty()) {
1552                 completionHandler(CommandResult::success());
1553                 return;
1554             }
1555             RefPtr<InspectorValue> resultValue;
1556             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1557                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1558                 return;
1559             }
1560             completionHandler(CommandResult::success(handleScriptResult(WTFMove(resultValue))));
1561         });
1562     });
1563 }
1564
1565 void Session::performMouseInteraction(int x, int y, MouseButton button, MouseInteraction interaction, Function<void (CommandResult&&)>&& completionHandler)
1566 {
1567     RefPtr<InspectorObject> parameters = InspectorObject::create();
1568     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1569     RefPtr<InspectorObject> position = InspectorObject::create();
1570     position->setInteger(ASCIILiteral("x"), x);
1571     position->setInteger(ASCIILiteral("y"), y);
1572     parameters->setObject(ASCIILiteral("position"), WTFMove(position));
1573     switch (button) {
1574     case MouseButton::None:
1575         parameters->setString(ASCIILiteral("button"), ASCIILiteral("None"));
1576         break;
1577     case MouseButton::Left:
1578         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Left"));
1579         break;
1580     case MouseButton::Middle:
1581         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Middle"));
1582         break;
1583     case MouseButton::Right:
1584         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Right"));
1585         break;
1586     }
1587     switch (interaction) {
1588     case MouseInteraction::Move:
1589         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Move"));
1590         break;
1591     case MouseInteraction::Down:
1592         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Down"));
1593         break;
1594     case MouseInteraction::Up:
1595         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Up"));
1596         break;
1597     case MouseInteraction::SingleClick:
1598         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("SingleClick"));
1599         break;
1600     case MouseInteraction::DoubleClick:
1601         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("DoubleClick"));
1602         break;
1603     }
1604     parameters->setArray(ASCIILiteral("modifiers"), InspectorArray::create());
1605     m_host->sendCommandToBackend(ASCIILiteral("performMouseInteraction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1606         if (response.isError) {
1607             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1608             return;
1609         }
1610         completionHandler(CommandResult::success());
1611     });
1612 }
1613
1614 void Session::performKeyboardInteractions(Vector<KeyboardInteraction>&& interactions, Function<void (CommandResult&&)>&& completionHandler)
1615 {
1616     RefPtr<InspectorObject> parameters = InspectorObject::create();
1617     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1618     RefPtr<InspectorArray> interactionsArray = InspectorArray::create();
1619     for (const auto& interaction : interactions) {
1620         RefPtr<InspectorObject> interactionObject = InspectorObject::create();
1621         switch (interaction.type) {
1622         case KeyboardInteractionType::KeyPress:
1623             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyPress"));
1624             break;
1625         case KeyboardInteractionType::KeyRelease:
1626             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyRelease"));
1627             break;
1628         case KeyboardInteractionType::InsertByKey:
1629             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("InsertByKey"));
1630             break;
1631         }
1632         if (interaction.key)
1633             interactionObject->setString(ASCIILiteral("key"), interaction.key.value());
1634         if (interaction.text)
1635             interactionObject->setString(ASCIILiteral("text"), interaction.text.value());
1636         interactionsArray->pushObject(WTFMove(interactionObject));
1637     }
1638     parameters->setArray(ASCIILiteral("interactions"), WTFMove(interactionsArray));
1639     m_host->sendCommandToBackend(ASCIILiteral("performKeyboardInteractions"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1640         if (response.isError) {
1641             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1642             return;
1643         }
1644         completionHandler(CommandResult::success());
1645     });
1646 }
1647
1648 void Session::dismissAlert(Function<void (CommandResult&&)>&& completionHandler)
1649 {
1650     if (!m_toplevelBrowsingContext) {
1651         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1652         return;
1653     }
1654
1655     RefPtr<InspectorObject> parameters = InspectorObject::create();
1656     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1657     m_host->sendCommandToBackend(ASCIILiteral("dismissCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1658         if (response.isError) {
1659             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1660             return;
1661         }
1662         completionHandler(CommandResult::success());
1663     });
1664 }
1665
1666 void Session::acceptAlert(Function<void (CommandResult&&)>&& completionHandler)
1667 {
1668     if (!m_toplevelBrowsingContext) {
1669         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1670         return;
1671     }
1672
1673     RefPtr<InspectorObject> parameters = InspectorObject::create();
1674     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1675     m_host->sendCommandToBackend(ASCIILiteral("acceptCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1676         if (response.isError) {
1677             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1678             return;
1679         }
1680         completionHandler(CommandResult::success());
1681     });
1682 }
1683
1684 void Session::getAlertText(Function<void (CommandResult&&)>&& completionHandler)
1685 {
1686     if (!m_toplevelBrowsingContext) {
1687         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1688         return;
1689     }
1690
1691     RefPtr<InspectorObject> parameters = InspectorObject::create();
1692     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1693     m_host->sendCommandToBackend(ASCIILiteral("messageOfCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1694         if (response.isError || !response.responseObject) {
1695             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1696             return;
1697         }
1698         String valueString;
1699         if (!response.responseObject->getString(ASCIILiteral("message"), valueString)) {
1700             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1701             return;
1702         }
1703         completionHandler(CommandResult::success(InspectorValue::create(valueString)));
1704     });
1705 }
1706
1707 void Session::sendAlertText(const String& text, Function<void (CommandResult&&)>&& completionHandler)
1708 {
1709     if (!m_toplevelBrowsingContext) {
1710         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1711         return;
1712     }
1713
1714     RefPtr<InspectorObject> parameters = InspectorObject::create();
1715     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1716     parameters->setString(ASCIILiteral("userInput"), text);
1717     m_host->sendCommandToBackend(ASCIILiteral("setUserInputForCurrentJavaScriptPrompt"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1718         if (response.isError) {
1719             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1720             return;
1721         }
1722         completionHandler(CommandResult::success());
1723     });
1724 }
1725
1726 } // namespace WebDriver