1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/common/custom_handlers/protocol_handler.h"
6 
7 #include "base/macros.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/util/values/values_util.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "content/public/common/origin_util.h"
13 #include "extensions/common/constants.h"
14 #include "net/base/escape.h"
15 #include "third_party/blink/public/common/custom_handlers/protocol_handler_utils.h"
16 #include "ui/base/l10n/l10n_util.h"
17 
ProtocolHandler(const std::string & protocol,const GURL & url,base::Time last_modified)18 ProtocolHandler::ProtocolHandler(const std::string& protocol,
19                                  const GURL& url,
20                                  base::Time last_modified)
21     : protocol_(base::ToLowerASCII(protocol)),
22       url_(url),
23       last_modified_(last_modified) {}
24 
CreateProtocolHandler(const std::string & protocol,const GURL & url)25 ProtocolHandler ProtocolHandler::CreateProtocolHandler(
26     const std::string& protocol,
27     const GURL& url) {
28   return ProtocolHandler(protocol, url, base::Time::Now());
29 }
30 
ProtocolHandler()31 ProtocolHandler::ProtocolHandler() {
32 }
33 
IsValidDict(const base::DictionaryValue * value)34 bool ProtocolHandler::IsValidDict(const base::DictionaryValue* value) {
35   // Note that "title" parameter is ignored.
36   // The |last_modified| field is optional as it was introduced in M68.
37   return value->HasKey("protocol") && value->HasKey("url");
38 }
39 
IsValid() const40 bool ProtocolHandler::IsValid() const {
41   // TODO(https://crbug.com/977083): Consider limiting to secure contexts.
42 
43   // This matches VerifyCustomHandlerURLSecurity() in blink's
44   // NavigatorContentUtils.
45   if (!url_.SchemeIsHTTPOrHTTPS() &&
46       !url_.SchemeIs(extensions::kExtensionScheme)) {
47     return false;
48   }
49 
50   bool has_custom_scheme_prefix;
51   return blink::IsValidCustomHandlerScheme(protocol_, has_custom_scheme_prefix);
52 }
53 
IsSameOrigin(const ProtocolHandler & handler) const54 bool ProtocolHandler::IsSameOrigin(
55     const ProtocolHandler& handler) const {
56   return handler.url().GetOrigin() == url_.GetOrigin();
57 }
58 
EmptyProtocolHandler()59 const ProtocolHandler& ProtocolHandler::EmptyProtocolHandler() {
60   static const ProtocolHandler* const kEmpty = new ProtocolHandler();
61   return *kEmpty;
62 }
63 
CreateProtocolHandler(const base::DictionaryValue * value)64 ProtocolHandler ProtocolHandler::CreateProtocolHandler(
65     const base::DictionaryValue* value) {
66   if (!IsValidDict(value)) {
67     return EmptyProtocolHandler();
68   }
69   std::string protocol, url;
70   // |time| defaults to the beginning of time if it is not specified.
71   base::Time time;
72   value->GetString("protocol", &protocol);
73   value->GetString("url", &url);
74   base::Optional<base::Time> time_value =
75       util::ValueToTime(value->FindKey("last_modified"));
76   // Treat invalid times as the default value.
77   if (time_value)
78     time = *time_value;
79   return ProtocolHandler(protocol, GURL(url), time);
80 }
81 
TranslateUrl(const GURL & url) const82 GURL ProtocolHandler::TranslateUrl(const GURL& url) const {
83   std::string translatedUrlSpec(url_.spec());
84   base::ReplaceFirstSubstringAfterOffset(
85       &translatedUrlSpec, 0, "%s",
86       net::EscapeQueryParamValue(url.spec(), false));
87   return GURL(translatedUrlSpec);
88 }
89 
Encode() const90 std::unique_ptr<base::DictionaryValue> ProtocolHandler::Encode() const {
91   auto d = std::make_unique<base::DictionaryValue>();
92   d->SetString("protocol", protocol_);
93   d->SetString("url", url_.spec());
94   d->SetKey("last_modified", util::TimeToValue(last_modified_));
95   return d;
96 }
97 
GetProtocolDisplayName(const std::string & protocol)98 base::string16 ProtocolHandler::GetProtocolDisplayName(
99     const std::string& protocol) {
100   if (protocol == "mailto")
101     return l10n_util::GetStringUTF16(IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME);
102   if (protocol == "webcal")
103     return l10n_util::GetStringUTF16(IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME);
104   return base::UTF8ToUTF16(protocol);
105 }
106 
GetProtocolDisplayName() const107 base::string16 ProtocolHandler::GetProtocolDisplayName() const {
108   return GetProtocolDisplayName(protocol_);
109 }
110 
111 #if !defined(NDEBUG)
ToString() const112 std::string ProtocolHandler::ToString() const {
113   return "{ protocol=" + protocol_ +
114          ", url=" + url_.spec() +
115          " }";
116 }
117 #endif
118 
operator ==(const ProtocolHandler & other) const119 bool ProtocolHandler::operator==(const ProtocolHandler& other) const {
120   return protocol_ == other.protocol_ && url_ == other.url_;
121 }
122 
IsEquivalent(const ProtocolHandler & other) const123 bool ProtocolHandler::IsEquivalent(const ProtocolHandler& other) const {
124   return protocol_ == other.protocol_ && url_ == other.url_;
125 }
126 
operator <(const ProtocolHandler & other) const127 bool ProtocolHandler::operator<(const ProtocolHandler& other) const {
128   return url_ < other.url_;
129 }
130