8a8f105c0abe6d7cc10d08293975337280257bd5
[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 void Session::createTopLevelBrowsingContext(Function<void (CommandResult&&)>&& completionHandler)
106 {
107     ASSERT(!m_toplevelBrowsingContext.value());
108     m_host->startAutomationSession(m_id, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
109         m_host->sendCommandToBackend(ASCIILiteral("createBrowsingContext"), nullptr, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
110             if (response.isError || !response.responseObject) {
111                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
112                 return;
113             }
114             String handle;
115             if (!response.responseObject->getString(ASCIILiteral("handle"), handle)) {
116                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
117                 return;
118             }
119             switchToTopLevelBrowsingContext(handle);
120             completionHandler(CommandResult::success());
121         });
122     });
123 }
124
125 void Session::go(const String& url, Function<void (CommandResult&&)>&& completionHandler)
126 {
127     if (!m_toplevelBrowsingContext) {
128         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
129         return;
130     }
131
132     RefPtr<InspectorObject> parameters = InspectorObject::create();
133     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
134     parameters->setString(ASCIILiteral("url"), url);
135     if (m_timeouts.pageLoad)
136         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
137     m_host->sendCommandToBackend(ASCIILiteral("navigateBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
138         if (response.isError) {
139             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
140             return;
141         }
142         switchToBrowsingContext(std::nullopt);
143         completionHandler(CommandResult::success());
144     });
145 }
146
147 void Session::getCurrentURL(Function<void (CommandResult&&)>&& completionHandler)
148 {
149     if (!m_toplevelBrowsingContext) {
150         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
151         return;
152     }
153
154     RefPtr<InspectorObject> parameters = InspectorObject::create();
155     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
156     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
157         if (response.isError || !response.responseObject) {
158             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
159             return;
160         }
161         RefPtr<InspectorObject> browsingContext;
162         if (!response.responseObject->getObject("context", browsingContext)) {
163             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
164             return;
165         }
166         String url;
167         if (!browsingContext->getString("url", url)) {
168             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
169             return;
170         }
171         completionHandler(CommandResult::success(InspectorValue::create(url)));
172     });
173 }
174
175 void Session::back(Function<void (CommandResult&&)>&& completionHandler)
176 {
177     if (!m_toplevelBrowsingContext) {
178         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
179         return;
180     }
181
182     RefPtr<InspectorObject> parameters = InspectorObject::create();
183     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
184     if (m_timeouts.pageLoad)
185         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
186     m_host->sendCommandToBackend(ASCIILiteral("goBackInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
187         if (response.isError) {
188             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
189             return;
190         }
191         switchToBrowsingContext(std::nullopt);
192         completionHandler(CommandResult::success());
193     });
194 }
195
196 void Session::forward(Function<void (CommandResult&&)>&& completionHandler)
197 {
198     if (!m_toplevelBrowsingContext) {
199         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
200         return;
201     }
202
203     RefPtr<InspectorObject> parameters = InspectorObject::create();
204     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
205     if (m_timeouts.pageLoad)
206         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
207     m_host->sendCommandToBackend(ASCIILiteral("goForwardInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
208         if (response.isError) {
209             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
210             return;
211         }
212         switchToBrowsingContext(std::nullopt);
213         completionHandler(CommandResult::success());
214     });
215 }
216
217 void Session::refresh(Function<void (CommandResult&&)>&& completionHandler)
218 {
219     if (!m_toplevelBrowsingContext) {
220         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
221         return;
222     }
223
224     RefPtr<InspectorObject> parameters = InspectorObject::create();
225     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
226     if (m_timeouts.pageLoad)
227         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
228     m_host->sendCommandToBackend(ASCIILiteral("reloadBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
229         if (response.isError) {
230             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
231             return;
232         }
233         switchToBrowsingContext(std::nullopt);
234         completionHandler(CommandResult::success());
235     });
236 }
237
238 void Session::getTitle(Function<void (CommandResult&&)>&& completionHandler)
239 {
240     if (!m_toplevelBrowsingContext) {
241         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
242         return;
243     }
244
245     RefPtr<InspectorObject> parameters = InspectorObject::create();
246     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
247     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function() { return document.title; }"));
248     parameters->setArray(ASCIILiteral("arguments"), InspectorArray::create());
249     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
250         if (response.isError || !response.responseObject) {
251             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
252             return;
253         }
254         String valueString;
255         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
256             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
257             return;
258         }
259         RefPtr<InspectorValue> resultValue;
260         if (!InspectorValue::parseJSON(valueString, resultValue)) {
261             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
262             return;
263         }
264         completionHandler(CommandResult::success(WTFMove(resultValue)));
265     });
266 }
267
268 void Session::getWindowHandle(Function<void (CommandResult&&)>&& completionHandler)
269 {
270     if (!m_toplevelBrowsingContext) {
271         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
272         return;
273     }
274
275     RefPtr<InspectorObject> parameters = InspectorObject::create();
276     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
277     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
278         if (response.isError || !response.responseObject) {
279             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
280             return;
281         }
282         RefPtr<InspectorObject> browsingContext;
283         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
284             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
285             return;
286         }
287         String handle;
288         if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
289             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
290             return;
291         }
292         completionHandler(CommandResult::success(InspectorValue::create(handle)));
293     });
294 }
295
296 void Session::closeWindow(Function<void (CommandResult&&)>&& completionHandler)
297 {
298     if (!m_toplevelBrowsingContext) {
299         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
300         return;
301     }
302
303     close(WTFMove(completionHandler));
304 }
305
306 void Session::switchToWindow(const String& windowHandle, Function<void (CommandResult&&)>&& completionHandler)
307 {
308     RefPtr<InspectorObject> parameters = InspectorObject::create();
309     parameters->setString(ASCIILiteral("browsingContextHandle"), windowHandle);
310     m_host->sendCommandToBackend(ASCIILiteral("switchToBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), windowHandle, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
311         if (response.isError) {
312             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
313             return;
314         }
315         switchToTopLevelBrowsingContext(windowHandle);
316         completionHandler(CommandResult::success());
317     });
318 }
319
320 void Session::getWindowHandles(Function<void (CommandResult&&)>&& completionHandler)
321 {
322     if (!m_toplevelBrowsingContext) {
323         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
324         return;
325     }
326
327     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContexts"), InspectorObject::create(), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
328         if (response.isError || !response.responseObject) {
329             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
330             return;
331         }
332         RefPtr<InspectorArray> browsingContextArray;
333         if (!response.responseObject->getArray(ASCIILiteral("contexts"), browsingContextArray)) {
334             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
335             return;
336         }
337         RefPtr<InspectorArray> windowHandles = InspectorArray::create();
338         for (unsigned i = 0; i < browsingContextArray->length(); ++i) {
339             RefPtr<InspectorValue> browsingContextValue = browsingContextArray->get(i);
340             RefPtr<InspectorObject> browsingContext;
341             if (!browsingContextValue->asObject(browsingContext)) {
342                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
343                 return;
344             }
345
346             String handle;
347             if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
348                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
349                 return;
350             }
351
352             windowHandles->pushString(handle);
353         }
354         completionHandler(CommandResult::success(WTFMove(windowHandles)));
355     });
356 }
357
358 void Session::switchToFrame(RefPtr<InspectorValue>&& frameID, Function<void (CommandResult&&)>&& completionHandler)
359 {
360     if (!m_toplevelBrowsingContext) {
361         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
362         return;
363     }
364
365     if (frameID->isNull()) {
366         switchToBrowsingContext(std::nullopt);
367         completionHandler(CommandResult::success());
368         return;
369     }
370
371     RefPtr<InspectorObject> parameters = InspectorObject::create();
372     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
373     if (m_currentBrowsingContext)
374         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
375
376     int frameIndex;
377     if (frameID->asInteger(frameIndex)) {
378         if (frameIndex < 0 || frameIndex > USHRT_MAX) {
379             completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
380             return;
381         }
382         parameters->setInteger(ASCIILiteral("ordinal"), frameIndex);
383     } else {
384         String frameElementID = extractElementID(*frameID);
385         if (!frameElementID.isEmpty())
386             parameters->setString(ASCIILiteral("nodeHandle"), frameElementID);
387         else {
388             String frameName;
389             if (!frameID->asString(frameName)) {
390                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
391                 return;
392             }
393             parameters->setString(ASCIILiteral("name"), frameName);
394         }
395     }
396
397     m_host->sendCommandToBackend(ASCIILiteral("resolveChildFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
398         if (response.isError || !response.responseObject) {
399             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
400             return;
401         }
402         String frameHandle;
403         if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
404             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
405             return;
406         }
407         switchToBrowsingContext(frameHandle);
408         completionHandler(CommandResult::success());
409     });
410 }
411
412 void Session::switchToParentFrame(Function<void (CommandResult&&)>&& completionHandler)
413 {
414     if (!m_toplevelBrowsingContext) {
415         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
416         return;
417     }
418
419     if (!m_currentBrowsingContext) {
420         completionHandler(CommandResult::success());
421         return;
422     }
423
424     RefPtr<InspectorObject> parameters = InspectorObject::create();
425     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
426     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
427     m_host->sendCommandToBackend(ASCIILiteral("resolveParentFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
428         if (response.isError || !response.responseObject) {
429             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
430             return;
431         }
432         String frameHandle;
433         if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
434             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
435             return;
436         }
437         switchToBrowsingContext(frameHandle);
438         completionHandler(CommandResult::success());
439     });
440 }
441
442 void Session::getWindowPosition(Function<void (CommandResult&&)>&& completionHandler)
443 {
444     if (!m_toplevelBrowsingContext) {
445         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
446         return;
447     }
448
449     RefPtr<InspectorObject> parameters = InspectorObject::create();
450     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
451     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
452         if (response.isError || !response.responseObject) {
453             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
454             return;
455         }
456         RefPtr<InspectorObject> browsingContext;
457         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
458             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
459             return;
460         }
461         RefPtr<InspectorObject> windowOrigin;
462         if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)) {
463             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
464             return;
465         }
466         completionHandler(CommandResult::success(WTFMove(windowOrigin)));
467     });
468 }
469
470 void Session::setWindowPosition(int windowX, int windowY, Function<void (CommandResult&&)>&& completionHandler)
471 {
472     if (!m_toplevelBrowsingContext) {
473         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
474         return;
475     }
476
477     RefPtr<InspectorObject> parameters = InspectorObject::create();
478     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
479     RefPtr<InspectorObject> windowOrigin = InspectorObject::create();
480     windowOrigin->setInteger("x", windowX);
481     windowOrigin->setInteger("y", windowY);
482     parameters->setObject(ASCIILiteral("origin"), WTFMove(windowOrigin));
483     m_host->sendCommandToBackend(ASCIILiteral("moveWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
484         if (response.isError) {
485             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
486             return;
487         }
488         completionHandler(CommandResult::success());
489     });
490 }
491
492 void Session::getWindowSize(Function<void (CommandResult&&)>&& completionHandler)
493 {
494     if (!m_toplevelBrowsingContext) {
495         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
496         return;
497     }
498
499     RefPtr<InspectorObject> parameters = InspectorObject::create();
500     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
501     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
502         if (response.isError || !response.responseObject) {
503             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
504             return;
505         }
506         RefPtr<InspectorObject> browsingContext;
507         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
508             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
509             return;
510         }
511         RefPtr<InspectorObject> windowSize;
512         if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)) {
513             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
514             return;
515         }
516         completionHandler(CommandResult::success(WTFMove(windowSize)));
517     });
518 }
519
520 void Session::setWindowSize(int windowWidth, int windowHeight, Function<void (CommandResult&&)>&& completionHandler)
521 {
522     if (!m_toplevelBrowsingContext) {
523         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
524         return;
525     }
526
527     RefPtr<InspectorObject> parameters = InspectorObject::create();
528     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
529     RefPtr<InspectorObject> windowSize = InspectorObject::create();
530     windowSize->setInteger("width", windowWidth);
531     windowSize->setInteger("height", windowHeight);
532     parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize));
533     m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
534         if (response.isError) {
535             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
536             return;
537         }
538         completionHandler(CommandResult::success());
539     });
540 }
541
542 RefPtr<InspectorObject> Session::createElement(RefPtr<InspectorValue>&& value)
543 {
544     RefPtr<InspectorObject> valueObject;
545     if (!value->asObject(valueObject))
546         return nullptr;
547
548     String elementID;
549     if (!valueObject->getString("session-node-" + m_id, elementID))
550         return nullptr;
551
552     RefPtr<InspectorObject> elementObject = InspectorObject::create();
553     elementObject->setString(webElementIdentifier, elementID);
554     return elementObject;
555 }
556
557 RefPtr<InspectorObject> Session::createElement(const String& elementID)
558 {
559     RefPtr<InspectorObject> elementObject = InspectorObject::create();
560     elementObject->setString("session-node-" + m_id, elementID);
561     return elementObject;
562 }
563
564 RefPtr<InspectorObject> Session::extractElement(InspectorValue& value)
565 {
566     String elementID = extractElementID(value);
567     return !elementID.isEmpty() ? createElement(elementID) : nullptr;
568 }
569
570 String Session::extractElementID(InspectorValue& value)
571 {
572     RefPtr<InspectorObject> valueObject;
573     if (!value.asObject(valueObject))
574         return emptyString();
575
576     String elementID;
577     if (!valueObject->getString(webElementIdentifier, elementID))
578         return emptyString();
579
580     return elementID;
581 }
582
583 void Session::computeElementLayout(const String& elementID, OptionSet<ElementLayoutOption> options, Function<void (std::optional<Rect>&&, std::optional<Point>&&, bool, RefPtr<InspectorObject>&&)>&& completionHandler)
584 {
585     ASSERT(m_toplevelBrowsingContext.value());
586
587     RefPtr<InspectorObject> parameters = InspectorObject::create();
588     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
589     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
590     parameters->setString(ASCIILiteral("nodeHandle"), elementID);
591     parameters->setBoolean(ASCIILiteral("scrollIntoViewIfNeeded"), options.contains(ElementLayoutOption::ScrollIntoViewIfNeeded));
592     parameters->setBoolean(ASCIILiteral("useViewportCoordinates"), options.contains(ElementLayoutOption::UseViewportCoordinates));
593     m_host->sendCommandToBackend(ASCIILiteral("computeElementLayout"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
594         if (response.isError || !response.responseObject) {
595             completionHandler(std::nullopt, std::nullopt, false, WTFMove(response.responseObject));
596             return;
597         }
598         RefPtr<InspectorObject> rectObject;
599         if (!response.responseObject->getObject(ASCIILiteral("rect"), rectObject)) {
600             completionHandler(std::nullopt, std::nullopt, false, nullptr);
601             return;
602         }
603         std::optional<int> elementX;
604         std::optional<int> elementY;
605         RefPtr<InspectorObject> elementPosition;
606         if (rectObject->getObject(ASCIILiteral("origin"), elementPosition)) {
607             int x, y;
608             if (elementPosition->getInteger(ASCIILiteral("x"), x) && elementPosition->getInteger(ASCIILiteral("y"), y)) {
609                 elementX = x;
610                 elementY = y;
611             }
612         }
613         if (!elementX || !elementY) {
614             completionHandler(std::nullopt, std::nullopt, false, nullptr);
615             return;
616         }
617         std::optional<int> elementWidth;
618         std::optional<int> elementHeight;
619         RefPtr<InspectorObject> elementSize;
620         if (rectObject->getObject(ASCIILiteral("size"), elementSize)) {
621             int width, height;
622             if (elementSize->getInteger(ASCIILiteral("width"), width) && elementSize->getInteger(ASCIILiteral("height"), height)) {
623                 elementWidth = width;
624                 elementHeight = height;
625             }
626         }
627         if (!elementWidth || !elementHeight) {
628             completionHandler(std::nullopt, std::nullopt, false, nullptr);
629             return;
630         }
631         Rect rect = { { elementX.value(), elementY.value() }, { elementWidth.value(), elementHeight.value() } };
632
633         bool isObscured;
634         if (!response.responseObject->getBoolean(ASCIILiteral("isObscured"), isObscured)) {
635             completionHandler(std::nullopt, std::nullopt, false, nullptr);
636             return;
637         }
638         RefPtr<InspectorObject> inViewCenterPointObject;
639         if (!response.responseObject->getObject(ASCIILiteral("inViewCenterPoint"), inViewCenterPointObject)) {
640             completionHandler(rect, std::nullopt, isObscured, nullptr);
641             return;
642         }
643         int inViewCenterPointX, inViewCenterPointY;
644         if (!inViewCenterPointObject->getInteger(ASCIILiteral("x"), inViewCenterPointX)
645             || !inViewCenterPointObject->getInteger(ASCIILiteral("y"), inViewCenterPointY)) {
646             completionHandler(std::nullopt, std::nullopt, isObscured, nullptr);
647             return;
648         }
649         Point inViewCenterPoint = { inViewCenterPointX, inViewCenterPointY };
650         completionHandler(rect, inViewCenterPoint, isObscured, nullptr);
651     });
652 }
653
654 void Session::findElements(const String& strategy, const String& selector, FindElementsMode mode, const String& rootElementID, Function<void (CommandResult&&)>&& completionHandler)
655 {
656     if (!m_toplevelBrowsingContext) {
657         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
658         return;
659     }
660
661     auto implicitWait = m_timeouts.implicit.value_or(0_s);
662     RefPtr<InspectorArray> arguments = InspectorArray::create();
663     arguments->pushString(InspectorValue::create(strategy)->toJSONString());
664     if (rootElementID.isEmpty())
665         arguments->pushString(InspectorValue::null()->toJSONString());
666     else
667         arguments->pushString(createElement(rootElementID)->toJSONString());
668     arguments->pushString(InspectorValue::create(selector)->toJSONString());
669     arguments->pushString(InspectorValue::create(mode == FindElementsMode::Single)->toJSONString());
670     arguments->pushString(InspectorValue::create(implicitWait.milliseconds())->toJSONString());
671
672     RefPtr<InspectorObject> parameters = InspectorObject::create();
673     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
674     if (m_currentBrowsingContext)
675         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
676     parameters->setString(ASCIILiteral("function"), FindNodesJavaScript);
677     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
678     parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
679     // If there's an implicit wait, use one second more as callback timeout.
680     if (implicitWait)
681         parameters->setInteger(ASCIILiteral("callbackTimeout"), Seconds(implicitWait + 1_s).millisecondsAs<int>());
682
683     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), mode, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
684         if (response.isError || !response.responseObject) {
685             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
686             return;
687         }
688         String valueString;
689         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
690             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
691             return;
692         }
693         RefPtr<InspectorValue> resultValue;
694         if (!InspectorValue::parseJSON(valueString, resultValue)) {
695             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
696             return;
697         }
698
699         switch (mode) {
700         case FindElementsMode::Single: {
701             RefPtr<InspectorObject> elementObject = createElement(WTFMove(resultValue));
702             if (!elementObject) {
703                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
704                 return;
705             }
706             completionHandler(CommandResult::success(WTFMove(elementObject)));
707             break;
708         }
709         case FindElementsMode::Multiple: {
710             RefPtr<InspectorArray> elementsArray;
711             if (!resultValue->asArray(elementsArray)) {
712                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
713                 return;
714             }
715             RefPtr<InspectorArray> elementObjectsArray = InspectorArray::create();
716             unsigned elementsArrayLength = elementsArray->length();
717             for (unsigned i = 0; i < elementsArrayLength; ++i) {
718                 if (auto elementObject = createElement(elementsArray->get(i)))
719                     elementObjectsArray->pushObject(WTFMove(elementObject));
720             }
721             completionHandler(CommandResult::success(WTFMove(elementObjectsArray)));
722             break;
723         }
724         }
725     });
726 }
727
728 void Session::isElementSelected(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
729 {
730     if (!m_toplevelBrowsingContext) {
731         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
732         return;
733     }
734
735     RefPtr<InspectorArray> arguments = InspectorArray::create();
736     arguments->pushString(createElement(elementID)->toJSONString());
737     arguments->pushString(InspectorValue::create("selected")->toJSONString());
738
739     RefPtr<InspectorObject> parameters = InspectorObject::create();
740     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
741     if (m_currentBrowsingContext)
742         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
743     parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
744     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
745     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
746         if (response.isError || !response.responseObject) {
747             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
748             return;
749         }
750         String valueString;
751         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
752             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
753             return;
754         }
755         RefPtr<InspectorValue> resultValue;
756         if (!InspectorValue::parseJSON(valueString, resultValue)) {
757             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
758             return;
759         }
760         if (resultValue->isNull()) {
761             completionHandler(CommandResult::success(InspectorValue::create(false)));
762             return;
763         }
764         String booleanResult;
765         if (!resultValue->asString(booleanResult) || booleanResult != "true") {
766             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
767             return;
768         }
769         completionHandler(CommandResult::success(InspectorValue::create(true)));
770     });
771 }
772
773 void Session::getElementText(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
774 {
775     if (!m_toplevelBrowsingContext) {
776         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
777         return;
778     }
779
780     RefPtr<InspectorArray> arguments = InspectorArray::create();
781     arguments->pushString(createElement(elementID)->toJSONString());
782
783     RefPtr<InspectorObject> parameters = InspectorObject::create();
784     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
785     if (m_currentBrowsingContext)
786         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
787     // FIXME: Add an atom to properly implement this instead of just using innerText.
788     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.innerText.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g, '') }"));
789     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
790     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
791         if (response.isError || !response.responseObject) {
792             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
793             return;
794         }
795         String valueString;
796         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
797             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
798             return;
799         }
800         RefPtr<InspectorValue> resultValue;
801         if (!InspectorValue::parseJSON(valueString, resultValue)) {
802             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
803             return;
804         }
805         completionHandler(CommandResult::success(WTFMove(resultValue)));
806     });
807 }
808
809 void Session::getElementTagName(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
810 {
811     if (!m_toplevelBrowsingContext) {
812         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
813         return;
814     }
815
816     RefPtr<InspectorArray> arguments = InspectorArray::create();
817     arguments->pushString(createElement(elementID)->toJSONString());
818
819     RefPtr<InspectorObject> parameters = InspectorObject::create();
820     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
821     if (m_currentBrowsingContext)
822         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
823     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.tagName.toLowerCase() }"));
824     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
825     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
826         if (response.isError || !response.responseObject) {
827             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
828             return;
829         }
830         String valueString;
831         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
832             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
833             return;
834         }
835         RefPtr<InspectorValue> resultValue;
836         if (!InspectorValue::parseJSON(valueString, resultValue)) {
837             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
838             return;
839         }
840         completionHandler(CommandResult::success(WTFMove(resultValue)));
841     });
842 }
843
844 void Session::getElementRect(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
845 {
846     if (!m_toplevelBrowsingContext) {
847         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
848         return;
849     }
850
851     computeElementLayout(elementID, { }, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&&, bool, RefPtr<InspectorObject>&& error) {
852         if (!rect || error) {
853             completionHandler(CommandResult::fail(WTFMove(error)));
854             return;
855         }
856         RefPtr<InspectorObject> rectObject = InspectorObject::create();
857         rectObject->setInteger(ASCIILiteral("x"), rect.value().origin.x);
858         rectObject->setInteger(ASCIILiteral("y"), rect.value().origin.y);
859         rectObject->setInteger(ASCIILiteral("width"), rect.value().size.width);
860         rectObject->setInteger(ASCIILiteral("height"), rect.value().size.height);
861         completionHandler(CommandResult::success(WTFMove(rectObject)));
862     });
863 }
864
865 void Session::isElementEnabled(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
866 {
867     if (!m_toplevelBrowsingContext) {
868         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
869         return;
870     }
871
872     RefPtr<InspectorArray> arguments = InspectorArray::create();
873     arguments->pushString(createElement(elementID)->toJSONString());
874
875     RefPtr<InspectorObject> parameters = InspectorObject::create();
876     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
877     if (m_currentBrowsingContext)
878         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
879     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.disabled === undefined ? true : !element.disabled }"));
880     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
881     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
882         if (response.isError || !response.responseObject) {
883             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
884             return;
885         }
886         String valueString;
887         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
888             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
889             return;
890         }
891         RefPtr<InspectorValue> resultValue;
892         if (!InspectorValue::parseJSON(valueString, resultValue)) {
893             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
894             return;
895         }
896         completionHandler(CommandResult::success(WTFMove(resultValue)));
897     });
898 }
899
900 void Session::isElementDisplayed(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
901 {
902     if (!m_toplevelBrowsingContext) {
903         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
904         return;
905     }
906
907     RefPtr<InspectorArray> arguments = InspectorArray::create();
908     arguments->pushString(createElement(elementID)->toJSONString());
909
910     RefPtr<InspectorObject> parameters = InspectorObject::create();
911     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
912     if (m_currentBrowsingContext)
913         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
914     parameters->setString(ASCIILiteral("function"), ElementDisplayedJavaScript);
915     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
916     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
917         if (response.isError || !response.responseObject) {
918             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
919             return;
920         }
921         String valueString;
922         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
923             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
924             return;
925         }
926         RefPtr<InspectorValue> resultValue;
927         if (!InspectorValue::parseJSON(valueString, resultValue)) {
928             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
929             return;
930         }
931         completionHandler(CommandResult::success(WTFMove(resultValue)));
932     });
933 }
934
935 void Session::getElementAttribute(const String& elementID, const String& attribute, Function<void (CommandResult&&)>&& completionHandler)
936 {
937     if (!m_toplevelBrowsingContext) {
938         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
939         return;
940     }
941
942     RefPtr<InspectorArray> arguments = InspectorArray::create();
943     arguments->pushString(createElement(elementID)->toJSONString());
944     arguments->pushString(InspectorValue::create(attribute)->toJSONString());
945
946     RefPtr<InspectorObject> parameters = InspectorObject::create();
947     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
948     if (m_currentBrowsingContext)
949         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
950     parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
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 void Session::waitForNavigationToComplete(Function<void (CommandResult&&)>&& completionHandler)
972 {
973     if (!m_toplevelBrowsingContext) {
974         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
975         return;
976     }
977
978     RefPtr<InspectorObject> parameters = InspectorObject::create();
979     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
980     if (m_currentBrowsingContext)
981         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
982     if (m_timeouts.pageLoad)
983         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
984     m_host->sendCommandToBackend(ASCIILiteral("waitForNavigationToComplete"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
985         if (response.isError) {
986             auto result = CommandResult::fail(WTFMove(response.responseObject));
987             if (result.errorCode() == CommandResult::ErrorCode::NoSuchFrame) {
988                 // Navigation destroyed the current frame, switch to top level browsing context and ignore the error.
989                 switchToBrowsingContext(std::nullopt);
990             } else {
991                 completionHandler(WTFMove(result));
992                 return;
993             }
994         }
995         completionHandler(CommandResult::success());
996     });
997 }
998
999 void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1000 {
1001     if (!m_toplevelBrowsingContext) {
1002         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1003         return;
1004     }
1005
1006     OptionSet<ElementLayoutOption> options = ElementLayoutOption::ScrollIntoViewIfNeeded;
1007     options |= ElementLayoutOption::UseViewportCoordinates;
1008     computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<InspectorObject>&& error) mutable {
1009         if (!rect || error) {
1010             completionHandler(CommandResult::fail(WTFMove(error)));
1011             return;
1012         }
1013         if (isObscured) {
1014             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementClickIntercepted));
1015             return;
1016         }
1017         if (!inViewCenter) {
1018             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementNotInteractable));
1019             return;
1020         }
1021
1022         performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(completionHandler));
1023
1024         waitForNavigationToComplete(WTFMove(completionHandler));
1025     });
1026 }
1027
1028 void Session::elementClear(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1029 {
1030     if (!m_toplevelBrowsingContext) {
1031         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1032         return;
1033     }
1034
1035     RefPtr<InspectorArray> arguments = InspectorArray::create();
1036     arguments->pushString(createElement(elementID)->toJSONString());
1037
1038     RefPtr<InspectorObject> parameters = InspectorObject::create();
1039     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1040     if (m_currentBrowsingContext)
1041         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1042     parameters->setString(ASCIILiteral("function"), FormElementClearJavaScript);
1043     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1044     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1045         if (response.isError) {
1046             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1047             return;
1048         }
1049         completionHandler(CommandResult::success());
1050     });
1051 }
1052
1053 String Session::virtualKeyForKeySequence(const String& keySequence, KeyModifier& modifier)
1054 {
1055     // ยง17.4.2 Keyboard Actions.
1056     // https://www.w3.org/TR/webdriver/#keyboard-actions
1057     modifier = KeyModifier::None;
1058     switch (keySequence[0]) {
1059     case 0xE001U:
1060         return ASCIILiteral("Cancel");
1061     case 0xE002U:
1062         return ASCIILiteral("Help");
1063     case 0xE003U:
1064         return ASCIILiteral("Backspace");
1065     case 0xE004U:
1066         return ASCIILiteral("Tab");
1067     case 0xE005U:
1068         return ASCIILiteral("Clear");
1069     case 0xE006U:
1070         return ASCIILiteral("Return");
1071     case 0xE007U:
1072         return ASCIILiteral("Enter");
1073     case 0xE008U:
1074         modifier = KeyModifier::Shift;
1075         return ASCIILiteral("Shift");
1076     case 0xE009U:
1077         modifier = KeyModifier::Control;
1078         return ASCIILiteral("Control");
1079     case 0xE00AU:
1080         modifier = KeyModifier::Alternate;
1081         return ASCIILiteral("Alternate");
1082     case 0xE00BU:
1083         return ASCIILiteral("Pause");
1084     case 0xE00CU:
1085         return ASCIILiteral("Escape");
1086     case 0xE00DU:
1087         return ASCIILiteral("Space");
1088     case 0xE00EU:
1089         return ASCIILiteral("PageUp");
1090     case 0xE00FU:
1091         return ASCIILiteral("PageDown");
1092     case 0xE010U:
1093         return ASCIILiteral("End");
1094     case 0xE011U:
1095         return ASCIILiteral("Home");
1096     case 0xE012U:
1097         return ASCIILiteral("LeftArrow");
1098     case 0xE013U:
1099         return ASCIILiteral("UpArrow");
1100     case 0xE014U:
1101         return ASCIILiteral("RightArrow");
1102     case 0xE015U:
1103         return ASCIILiteral("DownArrow");
1104     case 0xE016U:
1105         return ASCIILiteral("Insert");
1106     case 0xE017U:
1107         return ASCIILiteral("Delete");
1108     case 0xE018U:
1109         return ASCIILiteral("Semicolon");
1110     case 0xE019U:
1111         return ASCIILiteral("Equals");
1112     case 0xE01AU:
1113         return ASCIILiteral("NumberPad0");
1114     case 0xE01BU:
1115         return ASCIILiteral("NumberPad1");
1116     case 0xE01CU:
1117         return ASCIILiteral("NumberPad2");
1118     case 0xE01DU:
1119         return ASCIILiteral("NumberPad3");
1120     case 0xE01EU:
1121         return ASCIILiteral("NumberPad4");
1122     case 0xE01FU:
1123         return ASCIILiteral("NumberPad5");
1124     case 0xE020U:
1125         return ASCIILiteral("NumberPad6");
1126     case 0xE021U:
1127         return ASCIILiteral("NumberPad7");
1128     case 0xE022U:
1129         return ASCIILiteral("NumberPad8");
1130     case 0xE023U:
1131         return ASCIILiteral("NumberPad9");
1132     case 0xE024U:
1133         return ASCIILiteral("NumberPadMultiply");
1134     case 0xE025U:
1135         return ASCIILiteral("NumberPadAdd");
1136     case 0xE026U:
1137         return ASCIILiteral("NumberPadSeparator");
1138     case 0xE027U:
1139         return ASCIILiteral("NumberPadSubtract");
1140     case 0xE028U:
1141         return ASCIILiteral("NumberPadDecimal");
1142     case 0xE029U:
1143         return ASCIILiteral("NumberPadDivide");
1144     case 0xE031U:
1145         return ASCIILiteral("Function1");
1146     case 0xE032U:
1147         return ASCIILiteral("Function2");
1148     case 0xE033U:
1149         return ASCIILiteral("Function3");
1150     case 0xE034U:
1151         return ASCIILiteral("Function4");
1152     case 0xE035U:
1153         return ASCIILiteral("Function5");
1154     case 0xE036U:
1155         return ASCIILiteral("Function6");
1156     case 0xE037U:
1157         return ASCIILiteral("Function7");
1158     case 0xE038U:
1159         return ASCIILiteral("Function8");
1160     case 0xE039U:
1161         return ASCIILiteral("Function9");
1162     case 0xE03AU:
1163         return ASCIILiteral("Function10");
1164     case 0xE03BU:
1165         return ASCIILiteral("Function11");
1166     case 0xE03CU:
1167         return ASCIILiteral("Function12");
1168     case 0xE03DU:
1169         modifier = KeyModifier::Meta;
1170         return ASCIILiteral("Meta");
1171     default:
1172         break;
1173     }
1174     return String();
1175 }
1176
1177 void Session::elementSendKeys(const String& elementID, Vector<String>&& keys, Function<void (CommandResult&&)>&& completionHandler)
1178 {
1179     if (!m_toplevelBrowsingContext) {
1180         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1181         return;
1182     }
1183
1184     // FIXME: move this to an atom.
1185     static const char focusScript[] =
1186         "function focus(element) {"
1187         "    var doc = element.ownerDocument || element;"
1188         "    var prevActiveElement = doc.activeElement;"
1189         "    if (element != prevActiveElement && prevActiveElement)"
1190         "        prevActiveElement.blur();"
1191         "    element.focus();"
1192         "    if (element != prevActiveElement && element.value && element.value.length && element.setSelectionRange)"
1193         "        element.setSelectionRange(element.value.length, element.value.length);"
1194         "    if (element != doc.activeElement)"
1195         "        throw new Error('cannot focus element');"
1196         "}";
1197
1198     RefPtr<InspectorArray> arguments = InspectorArray::create();
1199     arguments->pushString(createElement(elementID)->toJSONString());
1200     RefPtr<InspectorObject> parameters = InspectorObject::create();
1201     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1202     if (m_currentBrowsingContext)
1203         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1204     parameters->setString(ASCIILiteral("function"), focusScript);
1205     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1206     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
1207         if (response.isError || !response.responseObject) {
1208             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1209             return;
1210         }
1211
1212         unsigned stickyModifiers = 0;
1213         Vector<KeyboardInteraction> interactions;
1214         interactions.reserveInitialCapacity(keys.size());
1215         for (const auto& key : keys) {
1216             KeyboardInteraction interaction;
1217             KeyModifier modifier;
1218             auto virtualKey = virtualKeyForKeySequence(key, modifier);
1219             if (!virtualKey.isNull()) {
1220                 interaction.key = virtualKey;
1221                 if (modifier != KeyModifier::None) {
1222                     stickyModifiers ^= modifier;
1223                     if (stickyModifiers & modifier)
1224                         interaction.type = KeyboardInteractionType::KeyPress;
1225                     else
1226                         interaction.type = KeyboardInteractionType::KeyRelease;
1227                 }
1228             } else
1229                 interaction.text = key;
1230             interactions.uncheckedAppend(WTFMove(interaction));
1231         }
1232
1233         // Reset sticky modifiers if needed.
1234         if (stickyModifiers) {
1235             if (stickyModifiers & KeyModifier::Shift)
1236                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Shift")) });
1237             if (stickyModifiers & KeyModifier::Control)
1238                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Control")) });
1239             if (stickyModifiers & KeyModifier::Alternate)
1240                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Alternate")) });
1241             if (stickyModifiers & KeyModifier::Meta)
1242                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Meta")) });
1243         }
1244
1245         performKeyboardInteractions(WTFMove(interactions), WTFMove(completionHandler));
1246     });
1247 }
1248
1249 void Session::elementSubmit(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1250 {
1251     if (!m_toplevelBrowsingContext) {
1252         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1253         return;
1254     }
1255
1256     RefPtr<InspectorArray> arguments = InspectorArray::create();
1257     arguments->pushString(createElement(elementID)->toJSONString());
1258
1259     RefPtr<InspectorObject> parameters = InspectorObject::create();
1260     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1261     if (m_currentBrowsingContext)
1262         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1263     parameters->setString(ASCIILiteral("function"), FormSubmitJavaScript);
1264     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1265     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1266         if (response.isError) {
1267             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1268             return;
1269         }
1270         completionHandler(CommandResult::success());
1271     });
1272 }
1273
1274 RefPtr<InspectorValue> Session::handleScriptResult(RefPtr<InspectorValue>&& resultValue)
1275 {
1276     RefPtr<InspectorArray> resultArray;
1277     if (resultValue->asArray(resultArray)) {
1278         RefPtr<InspectorArray> returnValueArray = InspectorArray::create();
1279         unsigned resultArrayLength = resultArray->length();
1280         for (unsigned i = 0; i < resultArrayLength; ++i)
1281             returnValueArray->pushValue(handleScriptResult(resultArray->get(i)));
1282         return returnValueArray;
1283     }
1284
1285     if (auto element = createElement(RefPtr<InspectorValue>(resultValue)))
1286         return element;
1287
1288     RefPtr<InspectorObject> resultObject;
1289     if (resultValue->asObject(resultObject)) {
1290         RefPtr<InspectorObject> returnValueObject = InspectorObject::create();
1291         auto end = resultObject->end();
1292         for (auto it = resultObject->begin(); it != end; ++it)
1293             returnValueObject->setValue(it->key, handleScriptResult(WTFMove(it->value)));
1294         return returnValueObject;
1295     }
1296
1297     return resultValue;
1298 }
1299
1300 void Session::executeScript(const String& script, RefPtr<InspectorArray>&& argumentsArray, ExecuteScriptMode mode, Function<void (CommandResult&&)>&& completionHandler)
1301 {
1302     if (!m_toplevelBrowsingContext) {
1303         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1304         return;
1305     }
1306
1307     RefPtr<InspectorArray> arguments = InspectorArray::create();
1308     unsigned argumentsLength = argumentsArray->length();
1309     for (unsigned i = 0; i < argumentsLength; ++i) {
1310         if (auto argument = argumentsArray->get(i)) {
1311             if (auto element = extractElement(*argument))
1312                 arguments->pushString(element->toJSONString());
1313             else
1314                 arguments->pushString(argument->toJSONString());
1315         }
1316     }
1317
1318     RefPtr<InspectorObject> parameters = InspectorObject::create();
1319     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1320     if (m_currentBrowsingContext)
1321         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1322     parameters->setString(ASCIILiteral("function"), "function(){" + script + '}');
1323     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1324     if (mode == ExecuteScriptMode::Async) {
1325         parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
1326         if (m_timeouts.script)
1327             parameters->setInteger(ASCIILiteral("callbackTimeout"), m_timeouts.script.value().millisecondsAs<int>());
1328     }
1329     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1330         if (response.isError || !response.responseObject) {
1331             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1332             return;
1333         }
1334         String valueString;
1335         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1336             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1337             return;
1338         }
1339         if (valueString.isEmpty()) {
1340             completionHandler(CommandResult::success());
1341             return;
1342         }
1343         RefPtr<InspectorValue> resultValue;
1344         if (!InspectorValue::parseJSON(valueString, resultValue)) {
1345             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1346             return;
1347         }
1348         completionHandler(CommandResult::success(handleScriptResult(WTFMove(resultValue))));
1349     });
1350 }
1351
1352 void Session::performMouseInteraction(int x, int y, MouseButton button, MouseInteraction interaction, Function<void (CommandResult&&)>&& completionHandler)
1353 {
1354     RefPtr<InspectorObject> parameters = InspectorObject::create();
1355     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1356     RefPtr<InspectorObject> position = InspectorObject::create();
1357     position->setInteger(ASCIILiteral("x"), x);
1358     position->setInteger(ASCIILiteral("y"), y);
1359     parameters->setObject(ASCIILiteral("position"), WTFMove(position));
1360     switch (button) {
1361     case MouseButton::None:
1362         parameters->setString(ASCIILiteral("button"), ASCIILiteral("None"));
1363         break;
1364     case MouseButton::Left:
1365         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Left"));
1366         break;
1367     case MouseButton::Middle:
1368         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Middle"));
1369         break;
1370     case MouseButton::Right:
1371         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Right"));
1372         break;
1373     }
1374     switch (interaction) {
1375     case MouseInteraction::Move:
1376         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Move"));
1377         break;
1378     case MouseInteraction::Down:
1379         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Down"));
1380         break;
1381     case MouseInteraction::Up:
1382         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Up"));
1383         break;
1384     case MouseInteraction::SingleClick:
1385         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("SingleClick"));
1386         break;
1387     case MouseInteraction::DoubleClick:
1388         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("DoubleClick"));
1389         break;
1390     }
1391     parameters->setArray(ASCIILiteral("modifiers"), InspectorArray::create());
1392     m_host->sendCommandToBackend(ASCIILiteral("performMouseInteraction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1393         if (response.isError) {
1394             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1395             return;
1396         }
1397         completionHandler(CommandResult::success());
1398     });
1399 }
1400
1401 void Session::performKeyboardInteractions(Vector<KeyboardInteraction>&& interactions, Function<void (CommandResult&&)>&& completionHandler)
1402 {
1403     RefPtr<InspectorObject> parameters = InspectorObject::create();
1404     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1405     RefPtr<InspectorArray> interactionsArray = InspectorArray::create();
1406     for (const auto& interaction : interactions) {
1407         RefPtr<InspectorObject> interactionObject = InspectorObject::create();
1408         switch (interaction.type) {
1409         case KeyboardInteractionType::KeyPress:
1410             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyPress"));
1411             break;
1412         case KeyboardInteractionType::KeyRelease:
1413             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyRelease"));
1414             break;
1415         case KeyboardInteractionType::InsertByKey:
1416             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("InsertByKey"));
1417             break;
1418         }
1419         if (interaction.key)
1420             interactionObject->setString(ASCIILiteral("key"), interaction.key.value());
1421         if (interaction.text)
1422             interactionObject->setString(ASCIILiteral("text"), interaction.text.value());
1423         interactionsArray->pushObject(WTFMove(interactionObject));
1424     }
1425     parameters->setArray(ASCIILiteral("interactions"), WTFMove(interactionsArray));
1426     m_host->sendCommandToBackend(ASCIILiteral("performKeyboardInteractions"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1427         if (response.isError) {
1428             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1429             return;
1430         }
1431         completionHandler(CommandResult::success());
1432     });
1433 }
1434
1435 } // namespace WebDriver