1 // Copyright 2013 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/extensions/api/url_handlers/url_handlers_parser.h" 6 7 #include "base/command_line.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "base/values.h" 12 #include "extensions/common/error_utils.h" 13 #include "extensions/common/manifest_constants.h" 14 #include "extensions/common/manifest_handlers/offline_enabled_info.h" 15 #include "extensions/common/switches.h" 16 #include "net/base/network_change_notifier.h" 17 #include "url/gurl.h" 18 19 using base::ASCIIToUTF16; 20 using net::NetworkChangeNotifier; 21 22 // TODO(sergeygs): Use the same strategy that externally_connectable does for 23 // parsing the manifest: declare a schema for the manifest entry in 24 // manifest_types.json, then use it here. 25 // 26 // See: 27 // chrome/common/extensions/api/manifest_types.json 28 // chrome/common/extensions/manifest_handlers/externally_connectable.* 29 // 30 // Do the same in (at least) file_handlers_parser.cc as well. 31 32 namespace extensions { 33 34 namespace mkeys = manifest_keys; 35 namespace merrors = manifest_errors; 36 37 UrlHandlerInfo::UrlHandlerInfo() { 38 } 39 40 UrlHandlerInfo::~UrlHandlerInfo() { 41 } 42 43 UrlHandlers::UrlHandlers() { 44 } 45 46 UrlHandlers::~UrlHandlers() { 47 } 48 49 // static 50 const std::vector<UrlHandlerInfo>* UrlHandlers::GetUrlHandlers( 51 const Extension* extension) { 52 UrlHandlers* info = static_cast<UrlHandlers*>( 53 extension->GetManifestData(mkeys::kUrlHandlers)); 54 return info ? &info->handlers : NULL; 55 } 56 57 // static 58 bool UrlHandlers::CanExtensionHandleUrl( 59 const Extension* extension, 60 const GURL& url) { 61 return FindMatchingUrlHandler(extension, url) != NULL; 62 } 63 64 // static 65 const UrlHandlerInfo* UrlHandlers::FindMatchingUrlHandler( 66 const Extension* extension, 67 const GURL& url) { 68 const std::vector<UrlHandlerInfo>* handlers = GetUrlHandlers(extension); 69 if (!handlers) 70 return NULL; 71 72 if (NetworkChangeNotifier::IsOffline() && 73 !OfflineEnabledInfo::IsOfflineEnabled(extension)) 74 return NULL; 75 76 for (std::vector<extensions::UrlHandlerInfo>::const_iterator it = 77 handlers->begin(); it != handlers->end(); it++) { 78 if (it->patterns.MatchesURL(url)) 79 return &(*it); 80 } 81 82 return NULL; 83 } 84 85 UrlHandlersParser::UrlHandlersParser() { 86 } 87 88 UrlHandlersParser::~UrlHandlersParser() { 89 } 90 91 bool ParseUrlHandler(const std::string& handler_id, 92 const base::DictionaryValue& handler_info, 93 std::vector<UrlHandlerInfo>* url_handlers, 94 base::string16* error) { 95 DCHECK(error); 96 97 UrlHandlerInfo handler; 98 handler.id = handler_id; 99 100 if (!handler_info.GetString(mkeys::kUrlHandlerTitle, &handler.title)) { 101 *error = base::ASCIIToUTF16(merrors::kInvalidURLHandlerTitle); 102 return false; 103 } 104 105 const base::ListValue* manif_patterns = NULL; 106 if (!handler_info.GetList(mkeys::kMatches, &manif_patterns) || 107 manif_patterns->GetSize() == 0) { 108 *error = ErrorUtils::FormatErrorMessageUTF16( 109 merrors::kInvalidURLHandlerPattern, handler_id); 110 return false; 111 } 112 113 for (base::ListValue::const_iterator it = manif_patterns->begin(); 114 it != manif_patterns->end(); ++it) { 115 std::string str_pattern; 116 (*it)->GetAsString(&str_pattern); 117 // TODO(sergeygs): Limit this to non-top-level domains. 118 // TODO(sergeygs): Also add a verification to the CWS installer that the 119 // URL patterns claimed here belong to the app's author verified sites. 120 URLPattern pattern(URLPattern::SCHEME_HTTP | 121 URLPattern::SCHEME_HTTPS); 122 if (pattern.Parse(str_pattern) != URLPattern::PARSE_SUCCESS) { 123 *error = ErrorUtils::FormatErrorMessageUTF16( 124 merrors::kInvalidURLHandlerPatternElement, handler_id); 125 return false; 126 } 127 handler.patterns.AddPattern(pattern); 128 } 129 130 url_handlers->push_back(handler); 131 132 return true; 133 } 134 135 bool UrlHandlersParser::Parse(Extension* extension, base::string16* error) { 136 scoped_ptr<UrlHandlers> info(new UrlHandlers); 137 const base::DictionaryValue* all_handlers = NULL; 138 if (!extension->manifest()->GetDictionary( 139 mkeys::kUrlHandlers, &all_handlers)) { 140 *error = base::ASCIIToUTF16(merrors::kInvalidURLHandlers); 141 return false; 142 } 143 144 DCHECK(extension->is_platform_app()); 145 146 for (base::DictionaryValue::Iterator iter(*all_handlers); !iter.IsAtEnd(); 147 iter.Advance()) { 148 // A URL handler entry is a title and a list of URL patterns to handle. 149 const base::DictionaryValue* handler = NULL; 150 if (!iter.value().GetAsDictionary(&handler)) { 151 *error = base::ASCIIToUTF16(merrors::kInvalidURLHandlerPatternElement); 152 return false; 153 } 154 155 if (!ParseUrlHandler(iter.key(), *handler, &info->handlers, error)) { 156 // Text in |error| is set by ParseUrlHandler. 157 return false; 158 } 159 } 160 161 extension->SetManifestData(mkeys::kUrlHandlers, info.release()); 162 163 return true; 164 } 165 166 const std::vector<std::string> UrlHandlersParser::Keys() const { 167 return SingleKey(mkeys::kUrlHandlers); 168 } 169 170 } // namespace extensions 171