blob: 6bb275eaafc828bb9b92f937979313c04a42c89b [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2012 The Chromium Authors
[email protected]a6d36cc2011-02-23 00:39:482// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:385#include "components/custom_handlers/protocol_handler.h"
[email protected]a6d36cc2011-02-23 00:39:486
Albert J. Wongf60c8d22021-07-27 07:25:267#include "base/json/values_util.h"
Ryan Hamilton7f3bd3d2022-04-23 00:07:398#include "base/strings/escape.h"
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:389#include "base/strings/utf_string_conversions.h"
10#include "components/strings/grit/components_strings.h"
11#include "content/public/browser/browser_thread.h"
Javier Fernández García-Boented6ea1f32021-09-06 11:22:1912#include "content/public/common/content_client.h"
Raymes Khoury58373df2019-08-06 06:29:2013#include "content/public/common/origin_util.h"
Frédéric Wang41052242021-04-19 07:28:4714#include "services/network/public/cpp/is_potentially_trustworthy.h"
Frédéric Wangdde6d042020-08-24 10:27:0315#include "third_party/blink/public/common/custom_handlers/protocol_handler_utils.h"
Javier Fernández García-Boente03816ca32021-08-06 15:41:3716#include "third_party/blink/public/common/scheme_registry.h"
Fabio Rocha1c346192021-02-12 05:07:1617#include "third_party/blink/public/common/security/protocol_handler_security_level.h"
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:3818#include "ui/base/l10n/l10n_util.h"
Javier Fernández García-Boented6ea1f32021-09-06 11:22:1919
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:3820using content::BrowserThread;
21
22namespace custom_handlers {
[email protected]4f49ce72012-06-28 01:03:5423
Frédéric Wangdb6af9ef2020-12-14 09:18:1624ProtocolHandler::ProtocolHandler(
25 const std::string& protocol,
26 const GURL& url,
27 base::Time last_modified,
28 blink::ProtocolHandlerSecurityLevel security_level)
Christian Dullweber5decc532018-05-03 14:53:1329 : protocol_(base::ToLowerASCII(protocol)),
30 url_(url),
Frédéric Wangdb6af9ef2020-12-14 09:18:1631 last_modified_(last_modified),
32 security_level_(security_level) {}
[email protected]a6d36cc2011-02-23 00:39:4833
Fabio Rocha1c346192021-02-12 05:07:1634ProtocolHandler::ProtocolHandler(const ProtocolHandler&) = default;
35ProtocolHandler::~ProtocolHandler() = default;
36
[email protected]1b60cec2011-05-04 01:29:5737ProtocolHandler ProtocolHandler::CreateProtocolHandler(
[email protected]a6d36cc2011-02-23 00:39:4838 const std::string& protocol,
Frédéric Wangdb6af9ef2020-12-14 09:18:1639 const GURL& url,
40 blink::ProtocolHandlerSecurityLevel security_level) {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:3841 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Frédéric Wangdb6af9ef2020-12-14 09:18:1642 return ProtocolHandler(protocol, url, base::Time::Now(), security_level);
[email protected]a6d36cc2011-02-23 00:39:4843}
44
Fabio Rocha1c346192021-02-12 05:07:1645ProtocolHandler::ProtocolHandler(
46 const std::string& protocol,
47 const GURL& url,
48 const std::string& app_id,
49 base::Time last_modified,
50 blink::ProtocolHandlerSecurityLevel security_level)
51 : protocol_(base::ToLowerASCII(protocol)),
52 url_(url),
53 web_app_id_(app_id),
54 last_modified_(last_modified),
55 security_level_(security_level) {}
56
57// static
58ProtocolHandler ProtocolHandler::CreateWebAppProtocolHandler(
59 const std::string& protocol,
60 const GURL& url,
61 const std::string& app_id) {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:3862 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Fabio Rocha1c346192021-02-12 05:07:1663 return ProtocolHandler(protocol, url, app_id, base::Time::Now(),
64 blink::ProtocolHandlerSecurityLevel::kStrict);
[email protected]1b60cec2011-05-04 01:29:5765}
66
Fabio Rocha1c346192021-02-12 05:07:1667ProtocolHandler::ProtocolHandler() = default;
68
Javier Fernández García-Boente7d55e362022-03-03 23:53:4969bool ProtocolHandler::IsValidDict(const base::Value::Dict& value) {
[email protected]c125e532014-05-10 20:39:0670 // Note that "title" parameter is ignored.
Christian Dullweber5decc532018-05-03 14:53:1371 // The |last_modified| field is optional as it was introduced in M68.
Javier Fernández García-Boente7d55e362022-03-03 23:53:4972 return value.FindString("protocol") && value.FindString("url");
[email protected]1b60cec2011-05-04 01:29:5773}
74
Raymes Khoury58373df2019-08-06 06:29:2075bool ProtocolHandler::IsValid() const {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:3876 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Javier Fernández García-Boentef8a578f2022-06-29 23:36:2377 // We don't want to include URL's syntax checks because there are use cases of
78 // the protocol handlers logic that require more flexibility than the one
79 // specified for the registerProtocolHandler API (eg, Predefined Handlers).
Javier Fernández García-Boente0bda5d22022-03-17 23:25:2780 if (!blink::IsAllowedCustomHandlerURL(url_, security_level_))
Raymes Khoury58373df2019-08-06 06:29:2081 return false;
Raymes Khoury58373df2019-08-06 06:29:2082
Javier Fernández García-Boente0bda5d22022-03-17 23:25:2783 return blink::IsValidCustomHandlerScheme(protocol_, security_level_);
Raymes Khoury58373df2019-08-06 06:29:2084}
85
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:3886bool ProtocolHandler::IsSameOrigin(const ProtocolHandler& handler) const {
87 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Mike West800532c2021-10-14 09:26:5288 return handler.url().DeprecatedGetOriginAsURL() ==
89 url_.DeprecatedGetOriginAsURL();
[email protected]d1dd80772011-09-28 03:53:5590}
91
[email protected]a8c1e7452011-05-14 06:17:0792const ProtocolHandler& ProtocolHandler::EmptyProtocolHandler() {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:3893 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]a8c1e7452011-05-14 06:17:0794 static const ProtocolHandler* const kEmpty = new ProtocolHandler();
95 return *kEmpty;
96}
97
[email protected]1b60cec2011-05-04 01:29:5798ProtocolHandler ProtocolHandler::CreateProtocolHandler(
Javier Fernández García-Boente7d55e362022-03-03 23:53:4999 const base::Value::Dict& value) {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:38100 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]1b60cec2011-05-04 01:29:57101 if (!IsValidDict(value)) {
[email protected]a8c1e7452011-05-14 06:17:07102 return EmptyProtocolHandler();
[email protected]1b60cec2011-05-04 01:29:57103 }
[email protected]a6d36cc2011-02-23 00:39:48104 std::string protocol, url;
Christian Dullweber5decc532018-05-03 14:53:13105 // |time| defaults to the beginning of time if it is not specified.
106 base::Time time;
Frédéric Wangdb6af9ef2020-12-14 09:18:16107 blink::ProtocolHandlerSecurityLevel security_level =
108 blink::ProtocolHandlerSecurityLevel::kStrict;
Javier Fernández García-Boente7d55e362022-03-03 23:53:49109 if (const std::string* protocol_in = value.FindString("protocol"))
Maks Orlovichc73c1eb2a2022-01-07 17:57:22110 protocol = *protocol_in;
Javier Fernández García-Boente7d55e362022-03-03 23:53:49111 if (const std::string* url_in = value.FindString("url"))
Maks Orlovichc73c1eb2a2022-01-07 17:57:22112 url = *url_in;
Anton Bikineev46bbb972021-05-15 17:53:53113 absl::optional<base::Time> time_value =
Javier Fernández García-Boente7d55e362022-03-03 23:53:49114 base::ValueToTime(value.Find("last_modified"));
Xiaohan Wangec1c552a2019-02-07 18:29:08115 // Treat invalid times as the default value.
116 if (time_value)
Nigel Taoe8e7b4662020-06-09 02:40:29117 time = *time_value;
Javier Fernández García-Boente7d55e362022-03-03 23:53:49118 absl::optional<int> security_level_value = value.FindInt("security_level");
Frédéric Wangdb6af9ef2020-12-14 09:18:16119 if (security_level_value) {
120 security_level =
121 blink::ProtocolHandlerSecurityLevelFrom(*security_level_value);
122 }
Fabio Rocha1c346192021-02-12 05:07:16123
Javier Fernández García-Boente7d55e362022-03-03 23:53:49124 if (const base::Value* app_id_val = value.Find("app_id")) {
Fabio Rocha1c346192021-02-12 05:07:16125 std::string app_id;
Maks Orlovichc73c1eb2a2022-01-07 17:57:22126 if (app_id_val->is_string())
127 app_id = app_id_val->GetString();
Fabio Rocha1c346192021-02-12 05:07:16128 return ProtocolHandler(protocol, GURL(url), app_id, time, security_level);
129 }
130
Frédéric Wangdb6af9ef2020-12-14 09:18:16131 return ProtocolHandler(protocol, GURL(url), time, security_level);
[email protected]a6d36cc2011-02-23 00:39:48132}
133
[email protected]a8c1e7452011-05-14 06:17:07134GURL ProtocolHandler::TranslateUrl(const GURL& url) const {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:38135 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]a6d36cc2011-02-23 00:39:48136 std::string translatedUrlSpec(url_.spec());
Gyuyoung Kim0fdf6a72017-12-07 06:20:47137 base::ReplaceFirstSubstringAfterOffset(
138 &translatedUrlSpec, 0, "%s",
Ryan Hamilton7f3bd3d2022-04-23 00:07:39139 base::EscapeQueryParamValue(url.spec(), false));
[email protected]a6d36cc2011-02-23 00:39:48140 return GURL(translatedUrlSpec);
141}
142
Javier Fernández García-Boente7d55e362022-03-03 23:53:49143base::Value::Dict ProtocolHandler::Encode() const {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:38144 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Javier Fernández García-Boente7d55e362022-03-03 23:53:49145 base::Value::Dict d;
146 d.Set("protocol", protocol_);
147 d.Set("url", url_.spec());
148 d.Set("last_modified", base::TimeToValue(last_modified_));
149 d.Set("security_level", static_cast<int>(security_level_));
Fabio Rocha1c346192021-02-12 05:07:16150
151 if (web_app_id_.has_value())
Javier Fernández García-Boente7d55e362022-03-03 23:53:49152 d.Set("app_id", web_app_id_.value());
Fabio Rocha1c346192021-02-12 05:07:16153
[email protected]a6d36cc2011-02-23 00:39:48154 return d;
155}
156
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58157std::u16string ProtocolHandler::GetProtocolDisplayName(
Esmael El-Moslimanyed90af42018-04-04 00:17:21158 const std::string& protocol) {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:38159 DCHECK_CURRENTLY_ON(BrowserThread::UI);
160 if (protocol == "mailto")
161 return l10n_util::GetStringUTF16(IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME);
162 if (protocol == "webcal")
163 return l10n_util::GetStringUTF16(IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME);
164 return base::UTF8ToUTF16(protocol);
Esmael El-Moslimanyed90af42018-04-04 00:17:21165}
166
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58167std::u16string ProtocolHandler::GetProtocolDisplayName() const {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:38168 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Esmael El-Moslimanyed90af42018-04-04 00:17:21169 return GetProtocolDisplayName(protocol_);
170}
171
[email protected]4f49ce72012-06-28 01:03:54172#if !defined(NDEBUG)
173std::string ProtocolHandler::ToString() const {
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:38174 return "{ protocol=" + protocol_ + ", url=" + url_.spec() + " }";
[email protected]4f49ce72012-06-28 01:03:54175}
176#endif
177
[email protected]a8c1e7452011-05-14 06:17:07178bool ProtocolHandler::operator==(const ProtocolHandler& other) const {
[email protected]c125e532014-05-10 20:39:06179 return protocol_ == other.protocol_ && url_ == other.url_;
[email protected]a6d36cc2011-02-23 00:39:48180}
[email protected]88fb6a62011-06-27 04:07:57181
[email protected]2532ff92011-10-06 03:22:48182bool ProtocolHandler::IsEquivalent(const ProtocolHandler& other) const {
183 return protocol_ == other.protocol_ && url_ == other.url_;
184}
185
[email protected]88fb6a62011-06-27 04:07:57186bool ProtocolHandler::operator<(const ProtocolHandler& other) const {
[email protected]c125e532014-05-10 20:39:06187 return url_ < other.url_;
[email protected]88fb6a62011-06-27 04:07:57188}
Javier Fernández García-Boented6ea1f32021-09-06 11:22:19189
Javier Fernández García-Boenteaa6aa0882022-03-02 20:48:38190} // namespace custom_handlers