text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // 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/compiler_specific.h"
  #include "base/macros.h"
  #include "chrome/browser/extensions/api/web_navigation/frame_navigation_state.h"
  #include "chrome/browser/extensions/chrome_extension_function.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/notification_observer.h"
  #include "content/public/browser/notification_registrar.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 "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() override;
  
    // Returns the object for the given |web_contents|.
    static WebNavigationTabObserver* Get(content::WebContents* web_contents);
  
    const FrameNavigationState& frame_navigation_state() const {
      return navigation_state_;
    }
  
    // content::WebContentsObserver implementation.
    void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
    void FrameDeleted(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 DocumentLoadedInFrame(
        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,
                     const base::string16& error_description,
                     bool was_ignored_by_handler) 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;
    void WebContentsDestroyed() 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);
  
    // Creates and sends onErrorOccurred events for all on-going navigations. If
    // |render_view_host| is non-NULL, only generates events for frames in this
    // render view host. If |frame_host_to_skip| is given, no events are sent for
    // that
    // frame.
    void SendErrorEvents(content::WebContents* web_contents,
                         content::RenderViewHost* render_view_host,
                         content::RenderFrameHost* frame_host_to_skip);
  
    // Tracks the state of the frames we are sending events for.
    FrameNavigationState navigation_state_;
  
    // 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_;
  
    // Used for tracking registrations to redirect notifications.
    content::NotificationRegistrar registrar_;
  
    DISALLOW_COPY_AND_ASSIGN(WebNavigationTabObserver);
  };
  
  // Observes navigation notifications and routes them as events to the extension
  // system.
  class WebNavigationEventRouter : public TabStripModelObserver,
                                   public BrowserTabStripTrackerDelegate,
                                   public content::NotificationObserver {
   public:
    explicit WebNavigationEventRouter(Profile* profile);
    ~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
    // TAB_ADDED notification.
    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.
    struct PendingWebContents{
      PendingWebContents();
      PendingWebContents(content::WebContents* source_web_contents,
                         content::RenderFrameHost* source_frame_host,
                         content::WebContents* target_web_contents,
                         const GURL& target_url);
      ~PendingWebContents();
  
      content::WebContents* source_web_contents;
      content::RenderFrameHost* source_frame_host;
      content::WebContents* target_web_contents;
      GURL target_url;
    };
  
    // BrowserTabStripTrackerDelegate implementation.
    bool ShouldTrackBrowser(Browser* browser) override;
  
    // TabStripModelObserver implementation.
    void TabReplacedAt(TabStripModel* tab_strip_model,
                       content::WebContents* old_contents,
                       content::WebContents* new_contents,
                       int index) override;
  
    // content::NotificationObserver implementation.
    void Observe(int type,
                 const content::NotificationSource& source,
                 const content::NotificationDetails& details) override;
  
    // Handler for the NOTIFICATION_TAB_ADDED event. The method takes the details
    // of such an event and creates a JSON formated extension event from it.
    void TabAdded(content::WebContents* tab);
  
    // Handler for NOTIFICATION_WEB_CONTENTS_DESTROYED. If |tab| is in
    // |pending_web_contents_|, it is removed.
    void TabDestroyed(content::WebContents* tab);
  
    // Mapping pointers to WebContents objects to information about how they got
    // created.
    std::map<content::WebContents*, PendingWebContents> pending_web_contents_;
  
    // Used for tracking registrations to navigation notifications.
    content::NotificationRegistrar registrar_;
  
    // The profile that owns us via ExtensionService.
    Profile* profile_;
  
    BrowserTabStripTracker browser_tab_strip_tracker_;
  
    DISALLOW_COPY_AND_ASSIGN(WebNavigationEventRouter);
  };
  
  // API function that returns the state of a given frame.
  class WebNavigationGetFrameFunction : public UIThreadExtensionFunction {
    ~WebNavigationGetFrameFunction() override {}
    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 UIThreadExtensionFunction {
    ~WebNavigationGetAllFramesFunction() override {}
    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() 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;
  
    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_;
  
    DISALLOW_COPY_AND_ASSIGN(WebNavigationAPI);
  };
  
  }  // namespace extensions
  
  #endif  // CHROME_BROWSER_EXTENSIONS_API_WEB_NAVIGATION_WEB_NAVIGATION_API_H_
  