Avi Drissman | 8ba1bad | 2022-09-13 19:22:36 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 2 | // 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-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 5 | #include "components/custom_handlers/protocol_handler.h" |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 6 | |
Albert J. Wong | f60c8d2 | 2021-07-27 07:25:26 | [diff] [blame] | 7 | #include "base/json/values_util.h" |
Ryan Hamilton | 7f3bd3d | 2022-04-23 00:07:39 | [diff] [blame] | 8 | #include "base/strings/escape.h" |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 9 | #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-Boente | d6ea1f3 | 2021-09-06 11:22:19 | [diff] [blame] | 12 | #include "content/public/common/content_client.h" |
Raymes Khoury | 58373df | 2019-08-06 06:29:20 | [diff] [blame] | 13 | #include "content/public/common/origin_util.h" |
Frédéric Wang | 4105224 | 2021-04-19 07:28:47 | [diff] [blame] | 14 | #include "services/network/public/cpp/is_potentially_trustworthy.h" |
Frédéric Wang | dde6d04 | 2020-08-24 10:27:03 | [diff] [blame] | 15 | #include "third_party/blink/public/common/custom_handlers/protocol_handler_utils.h" |
Javier Fernández García-Boente | 03816ca3 | 2021-08-06 15:41:37 | [diff] [blame] | 16 | #include "third_party/blink/public/common/scheme_registry.h" |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 17 | #include "third_party/blink/public/common/security/protocol_handler_security_level.h" |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 18 | #include "ui/base/l10n/l10n_util.h" |
Javier Fernández García-Boente | d6ea1f3 | 2021-09-06 11:22:19 | [diff] [blame] | 19 | |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 20 | using content::BrowserThread; |
| 21 | |
| 22 | namespace custom_handlers { |
[email protected] | 4f49ce7 | 2012-06-28 01:03:54 | [diff] [blame] | 23 | |
Frédéric Wang | db6af9ef | 2020-12-14 09:18:16 | [diff] [blame] | 24 | ProtocolHandler::ProtocolHandler( |
| 25 | const std::string& protocol, |
| 26 | const GURL& url, |
| 27 | base::Time last_modified, |
| 28 | blink::ProtocolHandlerSecurityLevel security_level) |
Christian Dullweber | 5decc53 | 2018-05-03 14:53:13 | [diff] [blame] | 29 | : protocol_(base::ToLowerASCII(protocol)), |
| 30 | url_(url), |
Frédéric Wang | db6af9ef | 2020-12-14 09:18:16 | [diff] [blame] | 31 | last_modified_(last_modified), |
| 32 | security_level_(security_level) {} |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 33 | |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 34 | ProtocolHandler::ProtocolHandler(const ProtocolHandler&) = default; |
| 35 | ProtocolHandler::~ProtocolHandler() = default; |
| 36 | |
[email protected] | 1b60cec | 2011-05-04 01:29:57 | [diff] [blame] | 37 | ProtocolHandler ProtocolHandler::CreateProtocolHandler( |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 38 | const std::string& protocol, |
Frédéric Wang | db6af9ef | 2020-12-14 09:18:16 | [diff] [blame] | 39 | const GURL& url, |
| 40 | blink::ProtocolHandlerSecurityLevel security_level) { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 41 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Frédéric Wang | db6af9ef | 2020-12-14 09:18:16 | [diff] [blame] | 42 | return ProtocolHandler(protocol, url, base::Time::Now(), security_level); |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 43 | } |
| 44 | |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 45 | ProtocolHandler::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 |
| 58 | ProtocolHandler ProtocolHandler::CreateWebAppProtocolHandler( |
| 59 | const std::string& protocol, |
| 60 | const GURL& url, |
| 61 | const std::string& app_id) { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 62 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 63 | return ProtocolHandler(protocol, url, app_id, base::Time::Now(), |
| 64 | blink::ProtocolHandlerSecurityLevel::kStrict); |
[email protected] | 1b60cec | 2011-05-04 01:29:57 | [diff] [blame] | 65 | } |
| 66 | |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 67 | ProtocolHandler::ProtocolHandler() = default; |
| 68 | |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 69 | bool ProtocolHandler::IsValidDict(const base::Value::Dict& value) { |
[email protected] | c125e53 | 2014-05-10 20:39:06 | [diff] [blame] | 70 | // Note that "title" parameter is ignored. |
Christian Dullweber | 5decc53 | 2018-05-03 14:53:13 | [diff] [blame] | 71 | // The |last_modified| field is optional as it was introduced in M68. |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 72 | return value.FindString("protocol") && value.FindString("url"); |
[email protected] | 1b60cec | 2011-05-04 01:29:57 | [diff] [blame] | 73 | } |
| 74 | |
Raymes Khoury | 58373df | 2019-08-06 06:29:20 | [diff] [blame] | 75 | bool ProtocolHandler::IsValid() const { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 76 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Javier Fernández García-Boente | f8a578f | 2022-06-29 23:36:23 | [diff] [blame] | 77 | // 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-Boente | 0bda5d2 | 2022-03-17 23:25:27 | [diff] [blame] | 80 | if (!blink::IsAllowedCustomHandlerURL(url_, security_level_)) |
Raymes Khoury | 58373df | 2019-08-06 06:29:20 | [diff] [blame] | 81 | return false; |
Raymes Khoury | 58373df | 2019-08-06 06:29:20 | [diff] [blame] | 82 | |
Javier Fernández García-Boente | 0bda5d2 | 2022-03-17 23:25:27 | [diff] [blame] | 83 | return blink::IsValidCustomHandlerScheme(protocol_, security_level_); |
Raymes Khoury | 58373df | 2019-08-06 06:29:20 | [diff] [blame] | 84 | } |
| 85 | |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 86 | bool ProtocolHandler::IsSameOrigin(const ProtocolHandler& handler) const { |
| 87 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Mike West | 800532c | 2021-10-14 09:26:52 | [diff] [blame] | 88 | return handler.url().DeprecatedGetOriginAsURL() == |
| 89 | url_.DeprecatedGetOriginAsURL(); |
[email protected] | d1dd8077 | 2011-09-28 03:53:55 | [diff] [blame] | 90 | } |
| 91 | |
[email protected] | a8c1e745 | 2011-05-14 06:17:07 | [diff] [blame] | 92 | const ProtocolHandler& ProtocolHandler::EmptyProtocolHandler() { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 93 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
[email protected] | a8c1e745 | 2011-05-14 06:17:07 | [diff] [blame] | 94 | static const ProtocolHandler* const kEmpty = new ProtocolHandler(); |
| 95 | return *kEmpty; |
| 96 | } |
| 97 | |
[email protected] | 1b60cec | 2011-05-04 01:29:57 | [diff] [blame] | 98 | ProtocolHandler ProtocolHandler::CreateProtocolHandler( |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 99 | const base::Value::Dict& value) { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 100 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
[email protected] | 1b60cec | 2011-05-04 01:29:57 | [diff] [blame] | 101 | if (!IsValidDict(value)) { |
[email protected] | a8c1e745 | 2011-05-14 06:17:07 | [diff] [blame] | 102 | return EmptyProtocolHandler(); |
[email protected] | 1b60cec | 2011-05-04 01:29:57 | [diff] [blame] | 103 | } |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 104 | std::string protocol, url; |
Christian Dullweber | 5decc53 | 2018-05-03 14:53:13 | [diff] [blame] | 105 | // |time| defaults to the beginning of time if it is not specified. |
| 106 | base::Time time; |
Frédéric Wang | db6af9ef | 2020-12-14 09:18:16 | [diff] [blame] | 107 | blink::ProtocolHandlerSecurityLevel security_level = |
| 108 | blink::ProtocolHandlerSecurityLevel::kStrict; |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 109 | if (const std::string* protocol_in = value.FindString("protocol")) |
Maks Orlovich | c73c1eb2a | 2022-01-07 17:57:22 | [diff] [blame] | 110 | protocol = *protocol_in; |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 111 | if (const std::string* url_in = value.FindString("url")) |
Maks Orlovich | c73c1eb2a | 2022-01-07 17:57:22 | [diff] [blame] | 112 | url = *url_in; |
Anton Bikineev | 46bbb97 | 2021-05-15 17:53:53 | [diff] [blame] | 113 | absl::optional<base::Time> time_value = |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 114 | base::ValueToTime(value.Find("last_modified")); |
Xiaohan Wang | ec1c552a | 2019-02-07 18:29:08 | [diff] [blame] | 115 | // Treat invalid times as the default value. |
| 116 | if (time_value) |
Nigel Tao | e8e7b466 | 2020-06-09 02:40:29 | [diff] [blame] | 117 | time = *time_value; |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 118 | absl::optional<int> security_level_value = value.FindInt("security_level"); |
Frédéric Wang | db6af9ef | 2020-12-14 09:18:16 | [diff] [blame] | 119 | if (security_level_value) { |
| 120 | security_level = |
| 121 | blink::ProtocolHandlerSecurityLevelFrom(*security_level_value); |
| 122 | } |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 123 | |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 124 | if (const base::Value* app_id_val = value.Find("app_id")) { |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 125 | std::string app_id; |
Maks Orlovich | c73c1eb2a | 2022-01-07 17:57:22 | [diff] [blame] | 126 | if (app_id_val->is_string()) |
| 127 | app_id = app_id_val->GetString(); |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 128 | return ProtocolHandler(protocol, GURL(url), app_id, time, security_level); |
| 129 | } |
| 130 | |
Frédéric Wang | db6af9ef | 2020-12-14 09:18:16 | [diff] [blame] | 131 | return ProtocolHandler(protocol, GURL(url), time, security_level); |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 132 | } |
| 133 | |
[email protected] | a8c1e745 | 2011-05-14 06:17:07 | [diff] [blame] | 134 | GURL ProtocolHandler::TranslateUrl(const GURL& url) const { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 135 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 136 | std::string translatedUrlSpec(url_.spec()); |
Gyuyoung Kim | 0fdf6a7 | 2017-12-07 06:20:47 | [diff] [blame] | 137 | base::ReplaceFirstSubstringAfterOffset( |
| 138 | &translatedUrlSpec, 0, "%s", |
Ryan Hamilton | 7f3bd3d | 2022-04-23 00:07:39 | [diff] [blame] | 139 | base::EscapeQueryParamValue(url.spec(), false)); |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 140 | return GURL(translatedUrlSpec); |
| 141 | } |
| 142 | |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 143 | base::Value::Dict ProtocolHandler::Encode() const { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 144 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 145 | 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 Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 150 | |
| 151 | if (web_app_id_.has_value()) |
Javier Fernández García-Boente | 7d55e36 | 2022-03-03 23:53:49 | [diff] [blame] | 152 | d.Set("app_id", web_app_id_.value()); |
Fabio Rocha | 1c34619 | 2021-02-12 05:07:16 | [diff] [blame] | 153 | |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 154 | return d; |
| 155 | } |
| 156 | |
Jan Wilken Dörrie | aace0cfef | 2021-03-11 22:01:58 | [diff] [blame] | 157 | std::u16string ProtocolHandler::GetProtocolDisplayName( |
Esmael El-Moslimany | ed90af4 | 2018-04-04 00:17:21 | [diff] [blame] | 158 | const std::string& protocol) { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 159 | 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-Moslimany | ed90af4 | 2018-04-04 00:17:21 | [diff] [blame] | 165 | } |
| 166 | |
Jan Wilken Dörrie | aace0cfef | 2021-03-11 22:01:58 | [diff] [blame] | 167 | std::u16string ProtocolHandler::GetProtocolDisplayName() const { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 168 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Esmael El-Moslimany | ed90af4 | 2018-04-04 00:17:21 | [diff] [blame] | 169 | return GetProtocolDisplayName(protocol_); |
| 170 | } |
| 171 | |
[email protected] | 4f49ce7 | 2012-06-28 01:03:54 | [diff] [blame] | 172 | #if !defined(NDEBUG) |
| 173 | std::string ProtocolHandler::ToString() const { |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 174 | return "{ protocol=" + protocol_ + ", url=" + url_.spec() + " }"; |
[email protected] | 4f49ce7 | 2012-06-28 01:03:54 | [diff] [blame] | 175 | } |
| 176 | #endif |
| 177 | |
[email protected] | a8c1e745 | 2011-05-14 06:17:07 | [diff] [blame] | 178 | bool ProtocolHandler::operator==(const ProtocolHandler& other) const { |
[email protected] | c125e53 | 2014-05-10 20:39:06 | [diff] [blame] | 179 | return protocol_ == other.protocol_ && url_ == other.url_; |
[email protected] | a6d36cc | 2011-02-23 00:39:48 | [diff] [blame] | 180 | } |
[email protected] | 88fb6a6 | 2011-06-27 04:07:57 | [diff] [blame] | 181 | |
[email protected] | 2532ff9 | 2011-10-06 03:22:48 | [diff] [blame] | 182 | bool ProtocolHandler::IsEquivalent(const ProtocolHandler& other) const { |
| 183 | return protocol_ == other.protocol_ && url_ == other.url_; |
| 184 | } |
| 185 | |
[email protected] | 88fb6a6 | 2011-06-27 04:07:57 | [diff] [blame] | 186 | bool ProtocolHandler::operator<(const ProtocolHandler& other) const { |
[email protected] | c125e53 | 2014-05-10 20:39:06 | [diff] [blame] | 187 | return url_ < other.url_; |
[email protected] | 88fb6a6 | 2011-06-27 04:07:57 | [diff] [blame] | 188 | } |
Javier Fernández García-Boente | d6ea1f3 | 2021-09-06 11:22:19 | [diff] [blame] | 189 | |
Javier Fernández García-Boente | aa6aa088 | 2022-03-02 20:48:38 | [diff] [blame] | 190 | } // namespace custom_handlers |