Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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 "extensions/common/manifest_handlers/options_page_info.h" | |
| 6 | |
| 7 #include "base/file_util.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "extensions/common/api/extensions_manifest_types.h" | |
| 12 #include "extensions/common/file_util.h" | |
| 13 #include "extensions/common/manifest_constants.h" | |
| 14 #include "extensions/strings/grit/extensions_strings.h" | |
| 15 #include "ui/base/l10n/l10n_util.h" | |
| 16 | |
| 17 using base::ASCIIToUTF16; | |
| 18 using base::DictionaryValue; | |
| 19 | |
| 20 namespace extensions { | |
| 21 | |
| 22 namespace keys = manifest_keys; | |
| 23 namespace values = manifest_values; | |
| 24 namespace errors = manifest_errors; | |
| 25 | |
| 26 using core_api::extensions_manifest_types::OptionsUI; | |
| 27 | |
| 28 namespace { | |
| 29 // Parses |url_string| into a GURL |result| if it is a valid options page for | |
| 30 // this app/extension. If not, it returns the reason in |error|. Because this | |
| 31 // handles URLs for both "options_page" and "options_ui.page", the | |
| 32 // OptionsUrlType must be passed to this function to send the correct error | |
| 33 // message. Returns true on success, false otherwise. | |
| 34 bool ParseOptionsUrl(Extension* extension, | |
| 35 std::string url_string, | |
|
not at google - send to devlin
2014/08/29 05:39:24
const std::string&
ericzeng
2014/08/29 22:08:51
Done.
| |
| 36 OptionsPageInfo::OptionsUrlType url_type, | |
|
not at google - send to devlin
2014/08/29 05:39:24
Rather than having this enum type, you could param
ericzeng
2014/08/29 16:52:22
Doesn't that mean moving the errors out of manifes
ericzeng
2014/08/29 22:08:51
Changed from enum to parameterized string
| |
| 37 base::string16* error, | |
| 38 GURL* result) { | |
| 39 if (extension->is_hosted_app()) { | |
| 40 // hosted apps require an absolute URL. | |
| 41 GURL options_url(url_string); | |
| 42 if (!options_url.is_valid() || !options_url.SchemeIsHTTPOrHTTPS()) { | |
| 43 if (url_type == OptionsPageInfo::OPTIONS_PAGE) | |
| 44 *error = base::ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp); | |
| 45 else if (url_type == OptionsPageInfo::OPTIONS_UI_PAGE) | |
| 46 *error = base::ASCIIToUTF16(errors::kInvalidOptionsUIPageInHostedApp); | |
|
not at google - send to devlin
2014/08/29 05:39:24
This shouldn't even be possible, hosted apps can't
ericzeng
2014/08/29 22:08:51
Removed OptionsUI errors
| |
| 47 return false; | |
| 48 } | |
| 49 *result = options_url; | |
|
not at google - send to devlin
2014/08/29 05:39:25
You should probably early-return in the hosted app
ericzeng
2014/08/29 22:08:51
Done.
| |
| 50 | |
| 51 } else { | |
| 52 GURL absolute(url_string); | |
| 53 if (absolute.is_valid()) { | |
| 54 if (url_type == OptionsPageInfo::OPTIONS_PAGE) { | |
| 55 *error = | |
| 56 base::ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage); | |
| 57 } else if (url_type == OptionsPageInfo::OPTIONS_UI_PAGE) { | |
| 58 *error = | |
| 59 base::ASCIIToUTF16(errors::kInvalidOptionsUIPageExpectUrlInPackage); | |
| 60 } | |
| 61 return false; | |
| 62 } | |
| 63 | |
| 64 GURL resource_url = extension->GetResourceURL(url_string); | |
| 65 if (!resource_url.is_valid()) { | |
| 66 if (url_type == OptionsPageInfo::OPTIONS_PAGE) | |
| 67 *error = base::ASCIIToUTF16(errors::kInvalidOptionsUIPage); | |
| 68 else if (url_type == OptionsPageInfo::OPTIONS_UI_PAGE) | |
| 69 *error = base::ASCIIToUTF16(errors::kInvalidOptionsUIPage); | |
|
not at google - send to devlin
2014/08/29 05:39:25
These are the same?
ericzeng
2014/08/29 22:08:50
Replaced with parameterized error
| |
| 70 return false; | |
| 71 } | |
| 72 *result = resource_url; | |
| 73 } | |
| 74 return true; | |
| 75 } | |
| 76 | |
| 77 OptionsPageInfo* GetOptionsPageInfo(const Extension* extension) { | |
| 78 return static_cast<OptionsPageInfo*>( | |
| 79 extension->GetManifestData(keys::kOptionsUI)); | |
| 80 } | |
| 81 | |
| 82 } // namespace | |
| 83 | |
| 84 OptionsPageInfo::OptionsPageInfo(GURL options_page, | |
| 85 GURL options_ui_page, | |
| 86 bool chrome_styles, | |
| 87 bool open_in_tab) | |
| 88 : options_page_(options_page), | |
| 89 options_ui_page_(options_ui_page), | |
| 90 chrome_styles_(chrome_styles), | |
| 91 open_in_tab_(open_in_tab) { | |
| 92 } | |
| 93 | |
| 94 OptionsPageInfo::~OptionsPageInfo() { | |
| 95 } | |
| 96 | |
| 97 // static | |
| 98 GURL OptionsPageInfo::GetOptionsPage(const Extension* extension) { | |
| 99 OptionsPageInfo* info = GetOptionsPageInfo(extension); | |
| 100 if (!info) { | |
| 101 return GURL::EmptyGURL(); | |
| 102 } | |
| 103 | |
| 104 if (info->options_ui_page_.is_valid()) { | |
| 105 return info->options_ui_page_; | |
| 106 } | |
| 107 return info->options_page_; | |
| 108 } | |
| 109 | |
| 110 // static | |
| 111 bool OptionsPageInfo::ChromeStyle(const Extension* extension) { | |
| 112 return GetOptionsPageInfo(extension)->chrome_styles_; | |
|
not at google - send to devlin
2014/08/29 05:39:24
Shouldn't you be checking for an empty info here?
ericzeng
2014/08/29 22:08:51
Done.
| |
| 113 } | |
| 114 | |
| 115 // static | |
| 116 bool OptionsPageInfo::OpenInTab(const Extension* extension) { | |
| 117 return GetOptionsPageInfo(extension)->open_in_tab_; | |
|
not at google - send to devlin
2014/08/29 05:39:24
And here?
And for both of the above: we should ma
ericzeng
2014/08/29 22:08:51
Done.
| |
| 118 } | |
| 119 | |
| 120 scoped_ptr<OptionsPageInfo> OptionsPageInfo::FromValues( | |
|
not at google - send to devlin
2014/08/29 05:39:24
FromValues looks kinda odd, and besides this is a
ericzeng
2014/08/29 22:08:50
Done.
| |
| 121 Extension* extension, | |
| 122 const base::Value* options_ui_value, | |
| 123 const base::Value* options_page_value, | |
| 124 std::vector<InstallWarning>* install_warnings, | |
| 125 base::string16* error) { | |
| 126 GURL options_page; | |
| 127 GURL options_ui_page; | |
| 128 bool chrome_style = false; | |
| 129 bool open_in_tab = false; | |
| 130 | |
| 131 // Parse the options_ui object | |
| 132 if (options_ui_value) { | |
| 133 scoped_ptr<OptionsUI> options_ui = | |
| 134 OptionsUI::FromValue(*options_ui_value, error); | |
| 135 if (options_ui) { | |
| 136 if (!ParseOptionsUrl(extension, | |
| 137 options_ui->page, | |
| 138 OptionsUrlType::OPTIONS_UI_PAGE, | |
| 139 error, | |
| 140 &options_ui_page)) { | |
| 141 return scoped_ptr<OptionsPageInfo>(); | |
| 142 } | |
| 143 chrome_style = | |
| 144 options_ui->chrome_style.get() && *options_ui->chrome_style; | |
| 145 open_in_tab = options_ui->open_in_tab.get() && *options_ui->open_in_tab; | |
| 146 } else { | |
| 147 *error = base::ASCIIToUTF16(errors::kInvalidOptionsUIPage); | |
| 148 return scoped_ptr<OptionsPageInfo>(); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 // Parse the options_page entry | |
| 153 if (options_page_value) { | |
| 154 std::string options_page_string; | |
| 155 if (!options_page_value->GetAsString(&options_page_string)) { | |
| 156 *error = ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 157 return scoped_ptr<OptionsPageInfo>(); | |
| 158 } | |
| 159 if (!ParseOptionsUrl(extension, | |
| 160 options_page_string, | |
| 161 OptionsUrlType::OPTIONS_PAGE, | |
| 162 error, | |
| 163 &options_page)) { | |
| 164 return scoped_ptr<OptionsPageInfo>(); | |
| 165 } | |
| 166 } | |
| 167 return make_scoped_ptr(new OptionsPageInfo( | |
| 168 options_page, options_ui_page, chrome_style, open_in_tab)); | |
| 169 } | |
| 170 | |
| 171 OptionsPageManifestHandler::OptionsPageManifestHandler() { | |
| 172 } | |
| 173 | |
| 174 OptionsPageManifestHandler::~OptionsPageManifestHandler() { | |
| 175 } | |
| 176 | |
| 177 bool OptionsPageManifestHandler::Parse(Extension* extension, | |
|
not at google - send to devlin
2014/08/29 05:39:24
Generally speaking: everywhere, try to show instal
ericzeng
2014/08/29 16:52:22
Does you mean that in places where I set *error =
| |
| 178 base::string16* error) { | |
| 179 const base::Value* options_ui_value = NULL; | |
| 180 const base::Value* options_page_value = NULL; | |
| 181 if (!extension->manifest()->Get(keys::kOptionsUI, &options_ui_value) && | |
| 182 !extension->manifest()->Get(keys::kOptionsPage, &options_page_value)) { | |
| 183 // Note: extension->manifest()->Get returns false both when the value is | |
| 184 // malformed or missing. Therefore we can't determine which one is at fault, | |
| 185 // so for now return the error message for just options_page. | |
| 186 *error = base::ASCIIToUTF16(errors::kInvalidOptionsPage); | |
| 187 return false; | |
| 188 } | |
|
not at google - send to devlin
2014/08/29 05:39:24
Keeping the parse logic in OptionsPageInfo is good
ericzeng
2014/08/29 22:08:51
Done.
| |
| 189 | |
| 190 std::vector<InstallWarning> install_warnings; | |
| 191 | |
| 192 scoped_ptr<OptionsPageInfo> info = | |
| 193 OptionsPageInfo::FromValues(extension, | |
| 194 options_ui_value, | |
| 195 options_page_value, | |
| 196 &install_warnings, | |
| 197 error); | |
| 198 | |
| 199 if (!info) | |
| 200 return false; | |
| 201 | |
| 202 extension->AddInstallWarnings(install_warnings); | |
| 203 extension->SetManifestData(keys::kOptionsUI, info.release()); | |
| 204 return true; | |
| 205 } | |
| 206 | |
| 207 bool OptionsPageManifestHandler::Validate( | |
| 208 const Extension* extension, | |
| 209 std::string* error, | |
| 210 std::vector<InstallWarning>* warnings) const { | |
| 211 // Validate path to the options page. Don't check the URL for hosted apps, | |
| 212 // because they are expected to refer to an external URL. | |
| 213 if (!OptionsPageInfo::GetOptionsPage(extension).is_empty() && | |
|
not at google - send to devlin
2014/08/29 05:39:24
HasOptionsPage would look so much nicer in places
ericzeng
2014/08/29 22:08:51
Done.
| |
| 214 !extension->is_hosted_app()) { | |
| 215 const base::FilePath options_path = | |
| 216 extensions::file_util::ExtensionURLToRelativeFilePath( | |
| 217 OptionsPageInfo::GetOptionsPage(extension)); | |
| 218 const base::FilePath path = | |
|
not at google - send to devlin
2014/08/29 05:39:24
const base::FilePath&
ericzeng
2014/08/29 22:08:51
Done.
| |
| 219 extension->GetResource(options_path).GetFilePath(); | |
| 220 if (path.empty() || !base::PathExists(path)) { | |
| 221 *error = l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED, | |
| 222 options_path.LossyDisplayName()); | |
| 223 return false; | |
| 224 } | |
| 225 } | |
| 226 return true; | |
| 227 } | |
| 228 | |
| 229 const std::vector<std::string> OptionsPageManifestHandler::Keys() const { | |
| 230 static const char* keys[] = {keys::kOptionsPage, keys::kOptionsUI}; | |
| 231 return std::vector<std::string>(keys, keys + arraysize(keys)); | |
| 232 } | |
| 233 | |
| 234 } // namespace extensions | |
| OLD | NEW |