3ffe3b316a7abe7bf52f5037d668eb6e9516191f
[WebKit-https.git] / Source / WebKit / UIProcess / Automation / WebAutomationSession.h
1 /*
2  * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
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 #pragma once
27
28 #include "APIObject.h"
29 #include "AutomationBackendDispatchers.h"
30 #include "AutomationFrontendDispatchers.h"
31 #include "Connection.h"
32 #include "ShareableBitmap.h"
33 #include "SimulatedInputDispatcher.h"
34 #include "WebEvent.h"
35 #include <wtf/CompletionHandler.h>
36 #include <wtf/Forward.h>
37 #include <wtf/RunLoop.h>
38
39 #if ENABLE(REMOTE_INSPECTOR)
40 #include <JavaScriptCore/RemoteAutomationTarget.h>
41 #endif
42
43 namespace API {
44 class AutomationSessionClient;
45 }
46
47 namespace Inspector {
48 class BackendDispatcher;
49 class FrontendRouter;
50 }
51
52 namespace WebCore {
53 class IntPoint;
54 class IntRect;
55
56 struct Cookie;
57 }
58
59 #if PLATFORM(COCOA)
60 OBJC_CLASS NSArray;
61 typedef unsigned short unichar;
62 #endif
63
64 #if USE(APPKIT)
65 OBJC_CLASS NSEvent;
66 #endif
67
68 namespace API {
69 class OpenPanelParameters;
70 }
71
72 namespace WebKit {
73
74 class WebAutomationSessionClient;
75 class WebFrameProxy;
76 class WebOpenPanelResultListenerProxy;
77 class WebPageProxy;
78 class WebProcessPool;
79
80 class AutomationCommandError {
81 public:
82     Inspector::Protocol::Automation::ErrorMessage type;
83     std::optional<String> message { std::nullopt };
84     
85     AutomationCommandError(Inspector::Protocol::Automation::ErrorMessage type)
86         : type(type) { }
87
88     AutomationCommandError(Inspector::Protocol::Automation::ErrorMessage type, const String& message)
89         : type(type)
90         , message(message) { }
91     
92     String toProtocolString();
93 };
94
95 using AutomationCompletionHandler = WTF::CompletionHandler<void(std::optional<AutomationCommandError>)>;
96
97 class WebAutomationSession final : public API::ObjectImpl<API::Object::Type::AutomationSession>, public IPC::MessageReceiver
98 #if ENABLE(REMOTE_INSPECTOR)
99     , public Inspector::RemoteAutomationTarget
100 #endif
101     , public Inspector::AutomationBackendDispatcherHandler
102     , public SimulatedInputDispatcher::Client
103 {
104 public:
105     WebAutomationSession();
106     ~WebAutomationSession();
107
108     void setClient(std::unique_ptr<API::AutomationSessionClient>&&);
109
110     void setSessionIdentifier(const String& sessionIdentifier) { m_sessionIdentifier = sessionIdentifier; }
111     String sessionIdentifier() const { return m_sessionIdentifier; }
112
113     WebProcessPool* processPool() const { return m_processPool; }
114     void setProcessPool(WebProcessPool*);
115
116     void navigationOccurredForFrame(const WebFrameProxy&);
117     void documentLoadedForFrame(const WebFrameProxy&);
118     void inspectorFrontendLoaded(const WebPageProxy&);
119     void keyboardEventsFlushedForPage(const WebPageProxy&);
120     void mouseEventsFlushedForPage(const WebPageProxy&);
121     void willClosePage(const WebPageProxy&);
122     void handleRunOpenPanel(const WebPageProxy&, const WebFrameProxy&, const API::OpenPanelParameters&, WebOpenPanelResultListenerProxy&);
123     void willShowJavaScriptDialog(WebPageProxy&);
124     void didEnterFullScreenForPage(const WebPageProxy&);
125     void didExitFullScreenForPage(const WebPageProxy&);
126
127     bool shouldAllowGetUserMediaForPage(const WebPageProxy&) const;
128
129 #if ENABLE(REMOTE_INSPECTOR)
130     // Inspector::RemoteAutomationTarget API
131     String name() const override { return m_sessionIdentifier; }
132     void dispatchMessageFromRemote(const String& message) override;
133     void connect(Inspector::FrontendChannel*, bool isAutomaticConnection = false, bool immediatelyPause = false) override;
134     void disconnect(Inspector::FrontendChannel*) override;
135 #endif
136     void terminate();
137
138     // SimulatedInputDispatcher::Client API
139     void simulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, AutomationCompletionHandler&&) final;
140     void simulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, std::optional<VirtualKey>, std::optional<CharKey>, AutomationCompletionHandler&&) final;
141     void viewportInViewCenterPointOfElement(WebPageProxy&, uint64_t frameID, const String& nodeHandle, Function<void (std::optional<WebCore::IntPoint>, std::optional<AutomationCommandError>)>&&) final;
142
143     // Inspector::AutomationBackendDispatcherHandler API
144     // NOTE: the set of declarations included in this interface depend on the "platform" property in Automation.json
145     // and the --platform argument passed to the protocol bindings generator.
146
147     // Platform: Generic
148     void getBrowsingContexts(Ref<GetBrowsingContextsCallback>&&) final;
149     void getBrowsingContext(const String&, Ref<GetBrowsingContextCallback>&&) final;
150     void createBrowsingContext(const bool* preferNewTab, Ref<CreateBrowsingContextCallback>&&) final;
151     void closeBrowsingContext(Inspector::ErrorString&, const String&) final;
152     void switchToBrowsingContext(const String& browsingContextHandle, const String* optionalFrameHandle, Ref<SwitchToBrowsingContextCallback>&&) final;
153     void setWindowFrameOfBrowsingContext(const String& handle, const JSON::Object* origin, const JSON::Object* size, Ref<SetWindowFrameOfBrowsingContextCallback>&&) final;
154     void hideWindowOfBrowsingContext(const String& handle, Ref<HideWindowOfBrowsingContextCallback>&&) final;
155     void navigateBrowsingContext(const String& handle, const String& url, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<NavigateBrowsingContextCallback>&&) override;
156     void goBackInBrowsingContext(const String&, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<GoBackInBrowsingContextCallback>&&) override;
157     void goForwardInBrowsingContext(const String&, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<GoForwardInBrowsingContextCallback>&&) override;
158     void reloadBrowsingContext(const String&, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<ReloadBrowsingContextCallback>&&) override;
159     void waitForNavigationToComplete(const String& browsingContextHandle, const String* optionalFrameHandle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<WaitForNavigationToCompleteCallback>&&) override;
160     void evaluateJavaScriptFunction(const String& browsingContextHandle, const String* optionalFrameHandle, const String& function, const JSON::Array& arguments, const bool* optionalExpectsImplicitCallbackArgument, const int* optionalCallbackTimeout, Ref<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>&&) override;
161     void performMouseInteraction(const String& handle, const JSON::Object& requestedPosition, const String& mouseButton, const String& mouseInteraction, const JSON::Array& keyModifiers, Ref<PerformMouseInteractionCallback>&&) final;
162     void performKeyboardInteractions(const String& handle, const JSON::Array& interactions, Ref<PerformKeyboardInteractionsCallback>&&) override;
163     void performInteractionSequence(const String& handle, const String* optionalFrameHandle, const JSON::Array& sources, const JSON::Array& steps, Ref<PerformInteractionSequenceCallback>&&) override;
164     void cancelInteractionSequence(const String& handle, const String* optionalFrameHandle, Ref<CancelInteractionSequenceCallback>&&) override;
165     void takeScreenshot(const String& handle, const String* optionalFrameHandle, const String* optionalNodeHandle, const bool* optionalScrollIntoViewIfNeeded, const bool* optionalClipToViewport, Ref<TakeScreenshotCallback>&&) override;
166     void resolveChildFrameHandle(const String& browsingContextHandle, const String* optionalFrameHandle, const int* optionalOrdinal, const String* optionalName, const String* optionalNodeHandle, Ref<ResolveChildFrameHandleCallback>&&) override;
167     void resolveParentFrameHandle(const String& browsingContextHandle, const String& frameHandle, Ref<ResolveParentFrameHandleCallback>&&) override;
168     void computeElementLayout(const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, const bool* optionalScrollIntoViewIfNeeded, const String& coordinateSystem, Ref<Inspector::AutomationBackendDispatcherHandler::ComputeElementLayoutCallback>&&) override;
169     void selectOptionElement(const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, Ref<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>&&) override;
170     void isShowingJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle, bool* result) override;
171     void dismissCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle) override;
172     void acceptCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle) override;
173     void messageOfCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle, String* text) override;
174     void setUserInputForCurrentJavaScriptPrompt(Inspector::ErrorString&, const String& browsingContextHandle, const String& text) override;
175     void setFilesToSelectForFileUpload(Inspector::ErrorString&, const String& browsingContextHandle, const JSON::Array& filenames) override;
176     void getAllCookies(const String& browsingContextHandle, Ref<GetAllCookiesCallback>&&) override;
177     void deleteSingleCookie(const String& browsingContextHandle, const String& cookieName, Ref<DeleteSingleCookieCallback>&&) override;
178     void addSingleCookie(const String& browsingContextHandle, const JSON::Object& cookie, Ref<AddSingleCookieCallback>&&) override;
179     void deleteAllCookies(Inspector::ErrorString&, const String& browsingContextHandle) override;
180     void getSessionPermissions(Inspector::ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::Automation::SessionPermissionData>>& out_permissions) override;
181     void setSessionPermissions(Inspector::ErrorString&, const JSON::Array& in_permissions) override;
182
183     // Platform: macOS
184 #if PLATFORM(MAC)
185     void inspectBrowsingContext(const String&, const bool* optionalEnableAutoCapturing, Ref<InspectBrowsingContextCallback>&&) override;
186 #endif
187
188     // Event Simulation Support.
189     bool isSimulatingUserInteraction() const;
190     SimulatedInputDispatcher& inputDispatcherForPage(WebPageProxy&);
191     SimulatedInputSource* inputSourceForType(SimulatedInputSourceType) const;
192
193 #if PLATFORM(MAC)
194     bool wasEventSynthesizedForAutomation(NSEvent *);
195     void markEventAsSynthesizedForAutomation(NSEvent *);
196 #endif
197
198 private:
199     WebPageProxy* webPageProxyForHandle(const String&);
200     String handleForWebPageProxy(const WebPageProxy&);
201     Ref<Inspector::Protocol::Automation::BrowsingContext> buildBrowsingContextForPage(WebPageProxy&, WebCore::FloatRect windowFrame);
202     void getNextContext(Ref<WebAutomationSession>&&, Vector<Ref<WebPageProxy>>&&, Ref<JSON::ArrayOf<Inspector::Protocol::Automation::BrowsingContext>>, Ref<WebAutomationSession::GetBrowsingContextsCallback>&&);
203
204     std::optional<uint64_t> webFrameIDForHandle(const String&);
205     String handleForWebFrameID(uint64_t frameID);
206     String handleForWebFrameProxy(const WebFrameProxy&);
207
208     void waitForNavigationToCompleteOnPage(WebPageProxy&, Inspector::Protocol::Automation::PageLoadStrategy, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
209     void waitForNavigationToCompleteOnFrame(WebFrameProxy&, Inspector::Protocol::Automation::PageLoadStrategy, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
210     void respondToPendingPageNavigationCallbacksWithTimeout(HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>>&);
211     void respondToPendingFrameNavigationCallbacksWithTimeout(HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>>&);
212     void loadTimerFired();
213
214     void exitFullscreenWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
215     void restoreWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
216     void hideWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
217
218     // Implemented in generated WebAutomationSessionMessageReceiver.cpp.
219     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
220
221     // Called by WebAutomationSession messages.
222     void didEvaluateJavaScriptFunction(uint64_t callbackID, const String& result, const String& errorType);
223     void didResolveChildFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
224     void didResolveParentFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
225     void didComputeElementLayout(uint64_t callbackID, WebCore::IntRect, std::optional<WebCore::IntPoint>, bool isObscured, const String& errorType);
226     void didSelectOptionElement(uint64_t callbackID, const String& errorType);
227     void didTakeScreenshot(uint64_t callbackID, const ShareableBitmap::Handle&, const String& errorType);
228     void didGetCookiesForFrame(uint64_t callbackID, Vector<WebCore::Cookie>, const String& errorType);
229     void didDeleteCookie(uint64_t callbackID, const String& errorType);
230
231     // Platform-dependent implementations.
232     void platformSimulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, WebEvent::Modifiers keyModifiers);
233     // Simulates a single virtual or char key being pressed/released, such as 'a', Control, F-keys, Numpad keys, etc. as allowed by the protocol.
234     void platformSimulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, std::optional<VirtualKey>, std::optional<CharKey>);
235     // Simulates key presses to produce the codepoints in a string. One or more code points are delivered atomically at grapheme cluster boundaries.
236     void platformSimulateKeySequence(WebPageProxy&, const String&);
237     // Get base64 encoded PNG data from a bitmap.
238     std::optional<String> platformGetBase64EncodedPNGData(const ShareableBitmap::Handle&);
239
240 #if PLATFORM(COCOA)
241     // The type parameter of the NSArray argument is platform-dependent.
242     void sendSynthesizedEventsToPage(WebPageProxy&, NSArray *eventsToSend);
243
244     std::optional<unichar> charCodeForVirtualKey(Inspector::Protocol::Automation::VirtualKey) const;
245     std::optional<unichar> charCodeIgnoringModifiersForVirtualKey(Inspector::Protocol::Automation::VirtualKey) const;
246 #endif
247
248     WebProcessPool* m_processPool { nullptr };
249
250     std::unique_ptr<API::AutomationSessionClient> m_client;
251     String m_sessionIdentifier { ASCIILiteral("Untitled Session") };
252     Ref<Inspector::FrontendRouter> m_frontendRouter;
253     Ref<Inspector::BackendDispatcher> m_backendDispatcher;
254     Ref<Inspector::AutomationBackendDispatcher> m_domainDispatcher;
255     std::unique_ptr<Inspector::AutomationFrontendDispatcher> m_domainNotifier;
256
257     HashMap<uint64_t, String> m_webPageHandleMap;
258     HashMap<String, uint64_t> m_handleWebPageMap;
259
260     HashMap<uint64_t, String> m_webFrameHandleMap;
261     HashMap<String, uint64_t> m_handleWebFrameMap;
262
263     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNormalNavigationInBrowsingContextCallbacksPerPage;
264     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingEagerNavigationInBrowsingContextCallbacksPerPage;
265     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNormalNavigationInBrowsingContextCallbacksPerFrame;
266     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingEagerNavigationInBrowsingContextCallbacksPerFrame;
267     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingInspectorCallbacksPerPage;
268     HashMap<uint64_t, Function<void(std::optional<AutomationCommandError>)>> m_pendingKeyboardEventsFlushedCallbacksPerPage;
269     HashMap<uint64_t, Function<void(std::optional<AutomationCommandError>)>> m_pendingMouseEventsFlushedCallbacksPerPage;
270
271     uint64_t m_nextEvaluateJavaScriptCallbackID { 1 };
272     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>> m_evaluateJavaScriptFunctionCallbacks;
273
274     uint64_t m_nextResolveFrameCallbackID { 1 };
275     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ResolveChildFrameHandleCallback>> m_resolveChildFrameHandleCallbacks;
276
277     uint64_t m_nextResolveParentFrameCallbackID { 1 };
278     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ResolveParentFrameHandleCallback>> m_resolveParentFrameHandleCallbacks;
279
280     // Start at 2 and use only even numbers to not conflict with m_nextViewportInViewCenterPointOfElementCallbackID.
281     uint64_t m_nextComputeElementLayoutCallbackID { 2 };
282     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ComputeElementLayoutCallback>> m_computeElementLayoutCallbacks;
283
284     // Start at 3 and use only odd numbers to not conflict with m_nextComputeElementLayoutCallbackID.
285     uint64_t m_nextViewportInViewCenterPointOfElementCallbackID { 3 };
286     HashMap<uint64_t, Function<void(std::optional<WebCore::IntPoint>, std::optional<AutomationCommandError>)>> m_viewportInViewCenterPointOfElementCallbacks;
287
288     uint64_t m_nextScreenshotCallbackID { 1 };
289     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::TakeScreenshotCallback>> m_screenshotCallbacks;
290
291     uint64_t m_nextGetCookiesCallbackID { 1 };
292     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::GetAllCookiesCallback>> m_getCookieCallbacks;
293
294     uint64_t m_nextDeleteCookieCallbackID { 1 };
295     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::DeleteSingleCookieCallback>> m_deleteCookieCallbacks;
296
297     uint64_t m_nextSelectOptionElementCallbackID { 1 };
298     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>> m_selectOptionElementCallbacks;
299
300     enum class WindowTransitionedToState {
301         Fullscreen,
302         Unfullscreen,
303     };
304     Function<void(WindowTransitionedToState)> m_windowStateTransitionCallback { };
305
306     RunLoop::Timer<WebAutomationSession> m_loadTimer;
307     Vector<String> m_filesToSelectForFileUpload;
308
309     bool m_permissionForGetUserMedia { true };
310
311     // Keep track of currently active modifiers across multiple keystrokes.
312     // Most platforms do not track current modifiers from synthesized events.
313     unsigned m_currentModifiers { 0 };
314
315     // SimulatedInputDispatcher APIs take a set of input sources. We also intern these
316     // so that previous input source state is used as initial state for later commands.
317     HashSet<Ref<SimulatedInputSource>> m_inputSources;
318     HashMap<uint64_t, Ref<SimulatedInputDispatcher>> m_inputDispatchersByPage;
319
320 #if ENABLE(REMOTE_INSPECTOR)
321     Inspector::FrontendChannel* m_remoteChannel { nullptr };
322 #endif
323
324 };
325
326 } // namespace WebKit