File: navigation_web_message_sender.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (157 lines) | stat: -rw-r--r-- 6,814 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_JS_INJECTION_BROWSER_NAVIGATION_WEB_MESSAGE_SENDER_H_
#define COMPONENTS_JS_INJECTION_BROWSER_NAVIGATION_WEB_MESSAGE_SENDER_H_

#include <string>

#include "base/values.h"
#include "content/public/browser/page_user_data.h"
#include "content/public/browser/web_contents_observer.h"

namespace content {
class NavigationHandle;
class Page;
}  // namespace content

namespace features {

// Enable creation of this class for special navigation listeners.
BASE_DECLARE_FEATURE(kEnableNavigationListener);

}  // namespace features

namespace js_injection {

class EmptyReplyProxy;
class WebMessageHost;
class WebMessageHostFactory;
struct WebMessage;

// A special interceptor for "navigation listener" WebMessageListeners where
// instead of establishing a connection with the renderer, a navigation observer
// is created on the browser, to inject navigation-related notification
// messages to the embedder.
//
// The NavigationWebMessageSender is 1:1 with Page, and navigation messages
// related to a certain Page will be sent by the NavigationWebMessageSender
// associated with that Page.
// See https://crbug.com/332809183 on why this is needed.
class NavigationWebMessageSender
    : public content::PageUserData<NavigationWebMessageSender>,
      public content::WebContentsObserver {
 public:
  // Depending on which object name is used, BFCache might be disallowed. If
  // `kNavigationListenerDisableBFCacheObjectName` is used, the client requests
  // to disable BFCache, so it will ensure all pages can't be BFCached. We
  // provide this functionality so that if the client can't handle BFCache yet
  // (due to needing to update client-side code to handle reusing pages, etc)
  // while the BFCache flag is already enabled on the WebView side (e.g. during
  // random experimentation), it won't get confused  with the ordering of events
  // (e.g. PAGE_DELETED not getting called for a long time). If the client uses
  // `kNavigationListenerAllowBFCacheObjectName` instead, it signals that it can
  // handle BFCache cases correctly, so pages are allowed to enter BFCache (if
  // the BFCache feature is turned on).
  static const char16_t kNavigationListenerAllowBFCacheObjectName[];
  static const char16_t kNavigationListenerDisableBFCacheObjectName[];

  // === Various messages that can be dispatched to the client ===

  // Only dispatched once globally, when the first NavigationWebMessageSender is
  // created. This indicates to the client that the special navigation listeners
  // are implemented (it might not be available in older versions).
  static const char kOptedInMessage[];

  // The navigation messages will contain details of the navigation like the
  // URL, whether the navigation is same-document or not, etc.
  //
  // Indicates that a navigation has started. This is dispatched on
  // `DidStartNavigation()`.
  static const char kNavigationStartedMessage[];
  // Indicates that a navigation has been redirected. This is dispatched on
  // `DidStartNavigation()`.
  static const char kNavigationRedirectedMessage[];
  // Indicates that a navigation has completed. This is dispatched on
  // `DidFinishNavigation()`.
  static const char kNavigationCompletedMessage[];

  // Indicates that the page has finished loading (i.e. the "load" event fired
  // on the primary main frame). This is dispatched on `DidFinishLoad()`.
  static const char kPageLoadEndMessage[];

  // Indicates that the page's initial DOM Content has finished loading (i.e.
  // the "domcontentloaded" event fired on the primary main frame). This is
  // dispatched on `DOMContentLoaded()`.
  static const char kDOMContentLoadedMessage[];

  // Indicates that the primary main frame just did a first contentful paint.
  // This is dispatched on `OnFirstContentfulPaintInPrimaryMainFrame()`.
  static const char kFirstContentfulPaintMessage[];

  // Indicates that the page has been deleted. This is dispatched from the class
  // destructor, since this is a PageUserData. If the page is BFCached, this
  // will be when the page is evicted. Otherwise, it will be when the primary
  // Page changed after a cross-document navigation away from this apge.
  static const char kPageDeletedMessage[];

  static bool IsNavigationListener(const std::u16string& js_object_name);
  static void CreateForPageIfNeeded(content::Page& page,
                                    const std::u16string& js_object_name,
                                    WebMessageHostFactory* factory);

  ~NavigationWebMessageSender() override;

  void DispatchOptInMessage();

 private:
  friend class PageUserData<NavigationWebMessageSender>;
  friend class NavigationListenerBrowserTest;
  FRIEND_TEST_ALL_PREFIXES(NavigationListenerBrowserTest, Basic);
  FRIEND_TEST_ALL_PREFIXES(NavigationListenerBrowserTest, NoLoadEnd);
  FRIEND_TEST_ALL_PREFIXES(NavigationListenerBrowserTest,
                           NewRendererInitiatedSameDocNavDuringCrossDocNav);
  FRIEND_TEST_ALL_PREFIXES(NavigationListenerBrowserTest,
                           NewBrowserInitiatedSameDocNavDuringCrossDocNav);
  FRIEND_TEST_ALL_PREFIXES(NavigationListenerBrowserTest,
                           NewCrossDocNavDuringCrossDocNav);

  static std::unique_ptr<WebMessage> CreateWebMessage(
      base::Value::Dict message_dict);

  NavigationWebMessageSender(content::Page& page,
                             const std::u16string& js_object_name,
                             WebMessageHostFactory* factory);

  // content::WebContentsObserver implementations
  void DOMContentLoaded(content::RenderFrameHost* render_frame_host) override;
  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
                     const GURL& validated_url) override;
  void DidStartNavigation(
      content::NavigationHandle* navigation_handle) override;
  void DidRedirectNavigation(
      content::NavigationHandle* navigation_handle) override;
  void DidFinishNavigation(
      content::NavigationHandle* navigation_handle) override;
  void OnFirstContentfulPaintInPrimaryMainFrame() override;

  void PostMessageWithType(std::string_view type);
  void PostMessage(base::Value::Dict message_dict);

  bool ShouldSendMessageForNavigation(
      content::NavigationHandle* navigation_handle);

  bool ShouldSendMessageForRenderFrameHost(
      content::RenderFrameHost* render_frame_host);

  WebMessageHost* GetWebMessageHostForTesting() { return host_.get(); }

  std::unique_ptr<EmptyReplyProxy> reply_proxy_;
  std::unique_ptr<WebMessageHost> host_;
  PAGE_USER_DATA_KEY_DECL();
};

}  // namespace js_injection

#endif  // COMPONENTS_JS_INJECTION_BROWSER_NAVIGATION_WEB_MESSAGE_SENDER_H_