| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Defines the Chrome Extensions WebNavigation API functions for observing and |
| // intercepting navigation events, as specified in the extension JSON API. |
| |
| #ifndef CHROME_BROWSER_EXTENSIONS_API_WEB_NAVIGATION_WEB_NAVIGATION_API_H_ |
| #define CHROME_BROWSER_EXTENSIONS_API_WEB_NAVIGATION_WEB_NAVIGATION_API_H_ |
| |
| #include <map> |
| #include <set> |
| |
| #include "base/functional/callback.h" |
| #include "base/memory/raw_ptr.h" |
| #include "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser_tab_strip_tracker.h" |
| #include "chrome/browser/ui/browser_tab_strip_tracker_delegate.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "content/public/browser/web_contents_user_data.h" |
| #include "extensions/browser/browser_context_keyed_api_factory.h" |
| #include "extensions/browser/event_router.h" |
| #include "extensions/browser/extension_function.h" |
| #include "url/gurl.h" |
| |
| namespace extensions { |
| |
| // Tab contents observer that forwards navigation events to the event router. |
| class WebNavigationTabObserver |
| : public content::WebContentsObserver, |
| public content::WebContentsUserData<WebNavigationTabObserver> { |
| public: |
| WebNavigationTabObserver(const WebNavigationTabObserver&) = delete; |
| WebNavigationTabObserver& operator=(const WebNavigationTabObserver&) = delete; |
| |
| ~WebNavigationTabObserver() override; |
| |
| // Returns the object for the given |web_contents|. |
| static WebNavigationTabObserver* Get(content::WebContents* web_contents); |
| |
| // content::WebContentsObserver implementation. |
| void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; |
| void RenderFrameHostChanged(content::RenderFrameHost* old_host, |
| content::RenderFrameHost* new_host) override; |
| void DidStartNavigation( |
| content::NavigationHandle* navigation_handle) override; |
| void DidFinishNavigation( |
| content::NavigationHandle* navigation_handle) override; |
| void DOMContentLoaded(content::RenderFrameHost* render_frame_host) override; |
| void DidFinishLoad(content::RenderFrameHost* render_frame_host, |
| const GURL& validated_url) override; |
| void DidFailLoad(content::RenderFrameHost* render_frame_host, |
| const GURL& validated_url, |
| int error_code) override; |
| void DidOpenRequestedURL(content::WebContents* new_contents, |
| content::RenderFrameHost* source_render_frame_host, |
| const GURL& url, |
| const content::Referrer& referrer, |
| WindowOpenDisposition disposition, |
| ui::PageTransition transition, |
| bool started_from_context_menu, |
| bool renderer_initiated) override; |
| |
| // This method dispatches the already created onBeforeNavigate event. |
| void DispatchCachedOnBeforeNavigate(); |
| |
| private: |
| explicit WebNavigationTabObserver(content::WebContents* web_contents); |
| friend class content::WebContentsUserData<WebNavigationTabObserver>; |
| |
| void HandleCommit(content::NavigationHandle* navigation_handle); |
| void HandleError(content::NavigationHandle* navigation_handle); |
| |
| // True if the transition and target url correspond to a reference fragment |
| // navigation. |
| bool IsReferenceFragmentNavigation(content::RenderFrameHost* frame_host, |
| const GURL& url); |
| |
| // Called when a RenderFrameHost goes into pending deletion. Stop tracking it |
| // and its children. |
| void RenderFrameHostPendingDeletion(content::RenderFrameHost*); |
| |
| // The latest onBeforeNavigate event this frame has generated. It is stored |
| // as it might not be sent immediately, but delayed until the tab is added to |
| // the tab strip and is ready to dispatch events. |
| std::unique_ptr<Event> pending_on_before_navigate_event_; |
| |
| WEB_CONTENTS_USER_DATA_KEY_DECL(); |
| }; |
| |
| // Tracks new tab navigations and routes them as events to the extension system. |
| class WebNavigationEventRouter : public TabStripModelObserver, |
| public BrowserTabStripTrackerDelegate { |
| public: |
| explicit WebNavigationEventRouter(Profile* profile); |
| |
| WebNavigationEventRouter(const WebNavigationEventRouter&) = delete; |
| WebNavigationEventRouter& operator=(const WebNavigationEventRouter&) = delete; |
| |
| ~WebNavigationEventRouter() override; |
| |
| // Router level handler for the creation of WebContents. Stores information |
| // about the newly created WebContents. This information is later used when |
| // the WebContents for the tab is added to the tabstrip and we receive the |
| // TabStripModelChanged insertion. |
| void RecordNewWebContents(content::WebContents* source_web_contents, |
| int source_render_process_id, |
| int source_render_frame_id, |
| GURL target_url, |
| content::WebContents* target_web_contents, |
| bool not_yet_in_tabstrip); |
| |
| private: |
| // Used to cache the information about newly created WebContents objects. |
| // Will run |on_destroy_| if/when the target WebContents is destroyed. |
| class PendingWebContents : public content::WebContentsObserver { |
| public: |
| PendingWebContents(); |
| |
| PendingWebContents(const PendingWebContents&) = delete; |
| PendingWebContents& operator=(const PendingWebContents&) = delete; |
| |
| ~PendingWebContents() override; |
| |
| void Set(int source_tab_id, |
| int source_render_process_id, |
| int source_extension_frame_id, |
| content::WebContents* target_web_contents, |
| const GURL& target_url, |
| base::OnceCallback<void(content::WebContents*)> on_destroy); |
| |
| // content::WebContentsObserver: |
| void WebContentsDestroyed() override; |
| |
| int source_tab_id() const { return source_tab_id_; } |
| int source_render_process_id() const { return source_render_process_id_; } |
| int source_extension_frame_id() const { return source_extension_frame_id_; } |
| content::WebContents* target_web_contents() const { |
| return target_web_contents_; |
| } |
| GURL target_url() const { return target_url_; } |
| |
| private: |
| // The Extensions API ID for the source tab. |
| int source_tab_id_ = -1; |
| // The source frame's RenderProcessHost ID. |
| int source_render_process_id_ = -1; |
| // The Extensions API ID for the source frame. |
| int source_extension_frame_id_ = -1; |
| raw_ptr<content::WebContents> target_web_contents_ = nullptr; |
| GURL target_url_; |
| base::OnceCallback<void(content::WebContents*)> on_destroy_; |
| }; |
| |
| // BrowserTabStripTrackerDelegate implementation. |
| bool ShouldTrackBrowser(BrowserWindowInterface* browser) override; |
| |
| // TabStripModelObserver implementation. |
| void OnTabStripModelChanged( |
| TabStripModel* tab_strip_model, |
| const TabStripModelChange& change, |
| const TabStripSelectionChange& selection) override; |
| |
| // The method takes the details of such an event and creates a JSON formatted |
| // extension event from it. |
| void TabAdded(content::WebContents* tab); |
| |
| // Removes |tab| from |pending_web_contents_| if it is there. |
| void PendingWebContentsDestroyed(content::WebContents* tab); |
| |
| // Mapping pointers to WebContents objects to information about how they got |
| // created. |
| std::map<content::WebContents*, PendingWebContents> pending_web_contents_; |
| |
| // The profile that owns us via ExtensionService. |
| raw_ptr<Profile> profile_; |
| |
| BrowserTabStripTracker browser_tab_strip_tracker_; |
| }; |
| |
| // API function that returns the state of a given frame. |
| class WebNavigationGetFrameFunction : public ExtensionFunction { |
| ~WebNavigationGetFrameFunction() override = default; |
| ResponseAction Run() override; |
| DECLARE_EXTENSION_FUNCTION("webNavigation.getFrame", WEBNAVIGATION_GETFRAME) |
| }; |
| |
| // API function that returns the states of all frames in a given tab. |
| class WebNavigationGetAllFramesFunction : public ExtensionFunction { |
| ~WebNavigationGetAllFramesFunction() override = default; |
| ResponseAction Run() override; |
| DECLARE_EXTENSION_FUNCTION("webNavigation.getAllFrames", |
| WEBNAVIGATION_GETALLFRAMES) |
| }; |
| |
| class WebNavigationAPI : public BrowserContextKeyedAPI, |
| public extensions::EventRouter::Observer { |
| public: |
| explicit WebNavigationAPI(content::BrowserContext* context); |
| |
| WebNavigationAPI(const WebNavigationAPI&) = delete; |
| WebNavigationAPI& operator=(const WebNavigationAPI&) = delete; |
| |
| ~WebNavigationAPI() override; |
| |
| // KeyedService implementation. |
| void Shutdown() override; |
| |
| // BrowserContextKeyedAPI implementation. |
| static BrowserContextKeyedAPIFactory<WebNavigationAPI>* GetFactoryInstance(); |
| |
| // EventRouter::Observer implementation. |
| void OnListenerAdded(const extensions::EventListenerInfo& details) override; |
| |
| private: |
| friend class BrowserContextKeyedAPIFactory<WebNavigationAPI>; |
| friend class WebNavigationTabObserver; |
| |
| raw_ptr<content::BrowserContext> browser_context_; |
| |
| // BrowserContextKeyedAPI implementation. |
| static const char* service_name() { |
| return "WebNavigationAPI"; |
| } |
| static const bool kServiceRedirectedInIncognito = true; |
| static const bool kServiceIsNULLWhileTesting = true; |
| |
| // Created lazily upon OnListenerAdded. |
| std::unique_ptr<WebNavigationEventRouter> web_navigation_event_router_; |
| }; |
| |
| } // namespace extensions |
| |
| #endif // CHROME_BROWSER_EXTENSIONS_API_WEB_NAVIGATION_WEB_NAVIGATION_API_H_ |