File: external_protocol_handler.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 (212 lines) | stat: -rw-r--r-- 8,584 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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_EXTERNAL_PROTOCOL_EXTERNAL_PROTOCOL_HANDLER_H_
#define CHROME_BROWSER_EXTERNAL_PROTOCOL_EXTERNAL_PROTOCOL_HANDLER_H_

#include <optional>
#include <string>

#include "build/build_config.h"
#include "chrome/browser/shell_integration.h"
#include "content/public/browser/web_contents.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
#include "ui/base/page_transition_types.h"

namespace content {
class WeakDocumentPtr;
}

namespace url {
class Origin;
}

class GURL;
class PrefRegistrySimple;
class Profile;

class ExternalProtocolHandler {
 public:
  enum BlockState {
    DONT_BLOCK,
    BLOCK,
    UNKNOWN,
  };

  // This is used to back a UMA histogram, so it should be treated as
  // append-only.
  // This metric is related to BlockState but is only used for metrics
  // reporting, and it differentiates multiple possible states that map to
  // BlockState.
  enum class BlockStateMetric {
    kDeniedDefault,
    kAllowedDefaultMail,
    kAllowedDefaultNews_Deprecated,  // No longer emitted.
    kNewsNotDefault_Deprecated,      // No longer emitted.
    kAllowedByEnterprisePolicy,
    kAllowedByPreference,
    kPrompt,
    // Insert new metric values above this line and update kMaxValue.
    kMaxValue = kPrompt,
  };

  // This is used to back a UMA histogram, so it should be treated as
  // append-only. Any new values should be inserted immediately prior to
  // HANDLE_STATE_LAST.
  enum HandleState {
    LAUNCH,
    CHECKED_LAUNCH,
    DONT_LAUNCH,
    CHECKED_DONT_LAUNCH_DEPRECATED,
    HANDLE_STATE_LAST
  };

  // Delegate to allow unit testing to provide different behavior.
  class Delegate {
   public:
    virtual scoped_refptr<shell_integration::DefaultSchemeClientWorker>
    CreateShellWorker(const GURL& url) = 0;
    virtual BlockState GetBlockState(const std::string& scheme,
                                     Profile* profile) = 0;
    virtual void BlockRequest() = 0;
    virtual void RunExternalProtocolDialog(
        const GURL& url,
        content::WebContents* web_contents,
        ui::PageTransition page_transition,
        bool has_user_gesture,
        const std::optional<url::Origin>& initiating_origin,
        const std::u16string& program_name) = 0;
    virtual void LaunchUrlWithoutSecurityCheck(
        const GURL& url,
        content::WebContents* web_contents) = 0;
    virtual void FinishedProcessingCheck() = 0;

    virtual void OnSetBlockState(const std::string& scheme,
                                 const url::Origin& initiating_origin,
                                 ExternalProtocolHandler::BlockState state) {}
    virtual void ReportExternalAppRedirectToSafeBrowsing(
        const GURL& url,
        content::WebContents* web_contents) {}
    virtual ~Delegate() = default;
  };

  // UMA histogram metric names.
  static const char kBlockStateMetric[];
  static const char kHandleStateMetric[];

  ExternalProtocolHandler(const ExternalProtocolHandler&) = delete;
  ExternalProtocolHandler& operator=(const ExternalProtocolHandler&) = delete;

  // Called on the UI thread. Allows switching out the
  // ExternalProtocolHandler::Delegate for testing code.
  static void SetDelegateForTesting(Delegate* delegate);

  // True if |initiating_origin| is not nullptr and is considered
  // potentially trustworthy.
  static bool MayRememberAllowDecisionsForThisOrigin(
      const url::Origin* initiating_origin);

  // Returns whether we should block a given scheme.
  // |initiating_origin| can be nullptr if the user is performing a
  // browser initiated top frame navigation, for example by typing in the
  // address bar or right-clicking a link and selecting 'Open In New Tab'.
  // Renderer-initiated navigations will set |initiating_origin| to the origin
  // of the content requesting the navigation.
  static BlockState GetBlockState(const std::string& scheme,
                                  const url::Origin* initiating_origin,
                                  Profile* profile);

  // Sets whether we should block a given scheme + origin.
  static void SetBlockState(const std::string& scheme,
                            const url::Origin& initiating_origin,
                            BlockState state,
                            Profile* profile);

  // Checks to see if the protocol is allowed, if it is allowlisted,
  // the application associated with the protocol is launched on the io thread,
  // if it is denylisted, returns silently. Otherwise, an
  // ExternalProtocolDialog is created asking the user. If the user accepts,
  // LaunchUrlWithoutSecurityCheck is called on the io thread and the
  // application is launched.
  // If possible, |initiator_document| identifies the document that requested
  // the external protocol launch.
  // Must run on the UI thread.
  static void LaunchUrl(
      const GURL& url,
      content::WebContents::Getter web_contents_getter,
      ui::PageTransition page_transition,
      bool has_user_gesture,
      bool is_in_fenced_frame_tree,
      const std::optional<url::Origin>& initiating_origin,
      content::WeakDocumentPtr initiator_document
#if BUILDFLAG(IS_ANDROID)
      ,
      mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory
#endif
  );

  // Starts a url using the external protocol handler with the help
  // of shellexecute. Should only be called if the protocol is allowlisted
  // (checked in LaunchUrl) or if the user explicitly allows it. (By selecting
  // "Open Application" in an ExternalProtocolDialog.) |url| might be escaped
  // already when calling into this function but e.g. from LaunchUrl but it
  // doesn't have to be because is also escaped in it.
  // NOTE: You should NOT call this function directly unless you are sure the
  // url you have has been checked against the denylist.
  // All calls to this function should originate in some way from LaunchUrl.
  static void LaunchUrlWithoutSecurityCheck(
      const GURL& url,
      content::WebContents* web_contents,
      content::WeakDocumentPtr initiator_document);

  // Allows LaunchUrl to proceed with launching an external protocol handler.
  // This is typically triggered by a user gesture, but is also called for
  // each extension API function. Note that each call to LaunchUrl resets
  // the state to false (not allowed).
  static void PermitLaunchUrl();

  // Records an UMA metric for the external protocol HandleState selected, based
  // on if the check box is selected / not and block / Dont block is picked.
  static void RecordHandleStateMetrics(bool checkbox_selected,
                                       BlockState state);

  // Register the ExcludedSchemes preference.
  static void RegisterPrefs(PrefRegistrySimple* registry);

#if !BUILDFLAG(IS_ANDROID)
  // Creates and runs a External Protocol dialog box.
  // |url| - The url of the request.
  // |render_process_host_id| and |routing_id| are used by
  // tab_util::GetWebContentsByID to aquire the tab contents associated with
  // this dialog.
  // NOTE: There is a race between the Time of Check and the Time Of Use for
  //       the command line. Since the caller (web page) does not have access
  //       to change the command line by itself, we do not do anything special
  //       to protect against this scenario.
  // This is implemented separately on each platform.
  // TODO(davidsac): Consider refactoring this to take a WebContents directly.
  // crbug.com/668289
  //
  // The dialog displays |initiating_origin| to the user so that they can
  // attribute the external protocol request to a site that initiated it. If an
  // opaque origin (for example, an origin inside a sandboxed iframe) initiated
  // the request, then |initiating_origin| should be set to the precursor origin
  // (that is, the origin that created the opaque origin).
  static void RunExternalProtocolDialog(
      const GURL& url,
      content::WebContents* web_contents,
      ui::PageTransition page_transition,
      bool has_user_gesture,
      bool is_in_fenced_frame_tree,
      const std::optional<url::Origin>& initiating_origin,
      content::WeakDocumentPtr initiator_document,
      const std::u16string& program_name);
#endif

  // Clears the external protocol handling data.
  static void ClearData(Profile* profile);
};

#endif  // CHROME_BROWSER_EXTERNAL_PROTOCOL_EXTERNAL_PROTOCOL_HANDLER_H_