Index: content/renderer/manifest/manifest_parser.cc |
diff --git a/content/renderer/manifest/manifest_parser.cc b/content/renderer/manifest/manifest_parser.cc |
index bab85cd75f1b1acc9aad4161f213dfe65b155f6e..11c4f33908dad3e7cae118744c1e8d5518b4bfed 100644 |
--- a/content/renderer/manifest/manifest_parser.cc |
+++ b/content/renderer/manifest/manifest_parser.cc |
@@ -19,21 +19,142 @@ namespace content { |
namespace { |
-enum TrimType { |
- Trim, |
- NoTrim |
-}; |
- |
-base::NullableString16 ParseString(const base::DictionaryValue& dictionary, |
- const std::string& key, |
- TrimType trim) { |
+// Helper function that returns whether the given |str| is a valid width or |
+// height value for an icon sizes per: |
+// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes |
+bool IsValidIconWidthOrHeight(const std::string& str) { |
+ if (str.empty() || str[0] == '0') |
+ return false; |
+ for (size_t i = 0; i < str.size(); ++i) |
+ if (!IsAsciiDigit(str[i])) |
+ return false; |
+ return true; |
+} |
+ |
+// Parses the 'sizes' attribute of an icon as described in the HTML spec: |
+// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes |
+// Return a vector of gfx::Size that contains the valid sizes found. "Any" is |
+// represented by gfx::Size(0, 0). |
+// TODO(mlamouri): this is implemented as a separate function because it should |
+// be refactored with the other icon sizes parsing implementations, see |
+// http://crbug.com/416477 |
+std::vector<gfx::Size> ParseIconSizesHTML(const base::string16& sizes_str16) { |
+ if (!base::IsStringASCII(sizes_str16)) |
+ return std::vector<gfx::Size>(); |
+ |
+ std::vector<gfx::Size> sizes; |
+ std::string sizes_str = |
+ base::StringToLowerASCII(base::UTF16ToUTF8(sizes_str16)); |
+ std::vector<std::string> sizes_str_list; |
+ base::SplitStringAlongWhitespace(sizes_str, &sizes_str_list); |
+ |
+ for (size_t i = 0; i < sizes_str_list.size(); ++i) { |
+ std::string& size_str = sizes_str_list[i]; |
+ if (size_str == "any") { |
+ sizes.push_back(gfx::Size(0, 0)); |
+ continue; |
+ } |
+ |
+ // It is expected that [0] => width and [1] => height after the split. |
+ std::vector<std::string> size_list; |
+ base::SplitStringDontTrim(size_str, L'x', &size_list); |
+ if (size_list.size() != 2) |
+ continue; |
+ if (!IsValidIconWidthOrHeight(size_list[0]) || |
+ !IsValidIconWidthOrHeight(size_list[1])) { |
+ continue; |
+ } |
+ |
+ int width, height; |
+ if (!base::StringToInt(size_list[0], &width) || |
+ !base::StringToInt(size_list[1], &height)) { |
+ continue; |
+ } |
+ |
+ sizes.push_back(gfx::Size(width, height)); |
+ } |
+ |
+ return sizes; |
+} |
+ |
+const std::string& GetErrorPrefix() { |
+ CR_DEFINE_STATIC_LOCAL(std::string, error_prefix, |
+ ("Manifest parsing error: ")); |
+ return error_prefix; |
+} |
+ |
+} // anonymous namespace |
+ |
+ |
+ManifestParser::ManifestParser(const base::StringPiece& data, |
+ const GURL& manifest_url, |
+ const GURL& document_url) |
+ : data_(data), |
+ manifest_url_(manifest_url), |
+ document_url_(document_url), |
+ failed_(false) { |
+} |
+ |
+ManifestParser::~ManifestParser() { |
+} |
+ |
+void ManifestParser::Parse() { |
+ std::string parse_error; |
+ scoped_ptr<base::Value> value( |
+ base::JSONReader::ReadAndReturnError(data_, base::JSON_PARSE_RFC, |
+ nullptr, &parse_error)); |
+ |
+ if (!value) { |
+ errors_.push_back(GetErrorPrefix() + parse_error); |
+ ManifestUmaUtil::ParseFailed(); |
+ failed_ = true; |
+ return; |
+ } |
+ |
+ base::DictionaryValue* dictionary = nullptr; |
+ if (!value->GetAsDictionary(&dictionary)) { |
+ errors_.push_back(GetErrorPrefix() + |
+ "root element must be a valid JSON object."); |
+ ManifestUmaUtil::ParseFailed(); |
+ failed_ = true; |
+ return; |
+ } |
+ CHECK(dictionary); |
Peter Beverloo
2014/11/27 14:37:37
*D*CHECK :-)
mlamouri (slow - plz ping)
2014/11/27 14:44:10
Done.
|
+ |
+ manifest_.name = ParseName(*dictionary); |
+ manifest_.short_name = ParseShortName(*dictionary); |
+ manifest_.start_url = ParseStartURL(*dictionary); |
+ manifest_.display = ParseDisplay(*dictionary); |
+ manifest_.orientation = ParseOrientation(*dictionary); |
+ manifest_.icons = ParseIcons(*dictionary); |
+ manifest_.gcm_sender_id = ParseGCMSenderID(*dictionary); |
+ |
+ ManifestUmaUtil::ParseSucceeded(manifest_); |
+} |
+ |
+const Manifest& ManifestParser::manifest() const { |
+ return manifest_; |
+} |
+ |
+const std::vector<std::string>& ManifestParser::errors() const { |
+ return errors_; |
+} |
+ |
+bool ManifestParser::failed() const { |
+ return failed_; |
+} |
+ |
+base::NullableString16 ManifestParser::ParseString( |
+ const base::DictionaryValue& dictionary, |
+ const std::string& key, |
+ TrimType trim) { |
if (!dictionary.HasKey(key)) |
return base::NullableString16(); |
base::string16 value; |
if (!dictionary.GetString(key, &value)) { |
- // TODO(mlamouri): provide a custom message to the developer console about |
- // the property being incorrectly set. |
+ errors_.push_back(GetErrorPrefix() + |
+ "property '" + key + "' ignored, type string expected."); |
return base::NullableString16(); |
} |
@@ -42,13 +163,9 @@ base::NullableString16 ParseString(const base::DictionaryValue& dictionary, |
return base::NullableString16(value, false); |
} |
-// Helper function to parse URLs present on a given |dictionary| in a given |
-// field identified by its |key|. The URL is first parsed as a string then |
-// resolved using |base_url|. |
-// Returns a GURL. If the parsing failed, the GURL will not be valid. |
-GURL ParseURL(const base::DictionaryValue& dictionary, |
- const std::string& key, |
- const GURL& base_url) { |
+GURL ManifestParser::ParseURL(const base::DictionaryValue& dictionary, |
+ const std::string& key, |
+ const GURL& base_url) { |
base::NullableString16 url_str = ParseString(dictionary, key, NoTrim); |
if (url_str.is_null()) |
return GURL(); |
@@ -56,44 +173,32 @@ GURL ParseURL(const base::DictionaryValue& dictionary, |
return base_url.Resolve(url_str.string()); |
} |
-// Parses the 'name' field of the manifest, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-name-member |
-// Returns the parsed string if any, a null string if the parsing failed. |
-base::NullableString16 ParseName(const base::DictionaryValue& dictionary) { |
+base::NullableString16 ManifestParser::ParseName( |
+ const base::DictionaryValue& dictionary) { |
return ParseString(dictionary, "name", Trim); |
} |
-// Parses the 'short_name' field of the manifest, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-short-name-member |
-// Returns the parsed string if any, a null string if the parsing failed. |
-base::NullableString16 ParseShortName( |
+base::NullableString16 ManifestParser::ParseShortName( |
const base::DictionaryValue& dictionary) { |
return ParseString(dictionary, "short_name", Trim); |
} |
-// Parses the 'start_url' field of the manifest, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-start_url-member |
-// Returns the parsed GURL if any, an empty GURL if the parsing failed. |
-GURL ParseStartURL(const base::DictionaryValue& dictionary, |
- const GURL& manifest_url, |
- const GURL& document_url) { |
- GURL start_url = ParseURL(dictionary, "start_url", manifest_url); |
+GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) { |
+ GURL start_url = ParseURL(dictionary, "start_url", manifest_url_); |
if (!start_url.is_valid()) |
return GURL(); |
- if (start_url.GetOrigin() != document_url.GetOrigin()) { |
- // TODO(mlamouri): provide a custom message to the developer console. |
+ if (start_url.GetOrigin() != document_url_.GetOrigin()) { |
+ errors_.push_back(GetErrorPrefix() + "property 'start_url' ignored, should " |
+ "be same origin as document."); |
return GURL(); |
} |
return start_url; |
} |
-// Parses the 'display' field of the manifest, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-display-member |
-// Returns the parsed DisplayMode if any, DISPLAY_MODE_UNSPECIFIED if the |
-// parsing failed. |
-Manifest::DisplayMode ParseDisplay(const base::DictionaryValue& dictionary) { |
+Manifest::DisplayMode ManifestParser::ParseDisplay( |
+ const base::DictionaryValue& dictionary) { |
base::NullableString16 display = ParseString(dictionary, "display", Trim); |
if (display.is_null()) |
return Manifest::DISPLAY_MODE_UNSPECIFIED; |
@@ -106,15 +211,13 @@ Manifest::DisplayMode ParseDisplay(const base::DictionaryValue& dictionary) { |
return Manifest::DISPLAY_MODE_MINIMAL_UI; |
else if (LowerCaseEqualsASCII(display.string(), "browser")) |
return Manifest::DISPLAY_MODE_BROWSER; |
- else |
+ else { |
+ errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored."); |
return Manifest::DISPLAY_MODE_UNSPECIFIED; |
+ } |
} |
-// Parses the 'orientation' field of the manifest, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-orientation-member |
-// Returns the parsed WebScreenOrientationLockType if any, |
-// WebScreenOrientationLockDefault if the parsing failed. |
-blink::WebScreenOrientationLockType ParseOrientation( |
+blink::WebScreenOrientationLockType ManifestParser::ParseOrientation( |
const base::DictionaryValue& dictionary) { |
base::NullableString16 orientation = |
ParseString(dictionary, "orientation", Trim); |
@@ -138,130 +241,69 @@ blink::WebScreenOrientationLockType ParseOrientation( |
return blink::WebScreenOrientationLockPortraitPrimary; |
else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary")) |
return blink::WebScreenOrientationLockPortraitSecondary; |
- else |
+ else { |
+ errors_.push_back(GetErrorPrefix() + |
+ "unknown 'orientation' value ignored."); |
return blink::WebScreenOrientationLockDefault; |
+ } |
} |
-// Parses the 'src' field of an icon, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-src-member-of-an-icon |
-// Returns the parsed GURL if any, an empty GURL if the parsing failed. |
-GURL ParseIconSrc(const base::DictionaryValue& icon, |
- const GURL& manifest_url) { |
- return ParseURL(icon, "src", manifest_url); |
+GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) { |
+ return ParseURL(icon, "src", manifest_url_); |
} |
-// Parses the 'type' field of an icon, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-type-member-of-an-icon |
-// Returns the parsed string if any, a null string if the parsing failed. |
-base::NullableString16 ParseIconType(const base::DictionaryValue& icon) { |
- return ParseString(icon, "type", Trim); |
+base::NullableString16 ManifestParser::ParseIconType( |
+ const base::DictionaryValue& icon) { |
+ return ParseString(icon, "type", Trim); |
} |
-// Parses the 'density' field of an icon, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-a-density-member-of-an-icon |
-// Returns the parsed double if any, Manifest::Icon::kDefaultDensity if the |
-// parsing failed. |
-double ParseIconDensity(const base::DictionaryValue& icon) { |
+double ManifestParser::ParseIconDensity(const base::DictionaryValue& icon) { |
double density; |
- if (!icon.GetDouble("density", &density) || density <= 0) |
+ if (!icon.HasKey("density")) |
return Manifest::Icon::kDefaultDensity; |
+ |
+ if (!icon.GetDouble("density", &density) || density <= 0) { |
+ errors_.push_back(GetErrorPrefix() + |
+ "icon 'density' ignored, must be float greater than 0."); |
+ return Manifest::Icon::kDefaultDensity; |
+ } |
return density; |
} |
-// Helper function that returns whether the given |str| is a valid width or |
-// height value for an icon sizes per: |
-// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes |
-bool IsValidIconWidthOrHeight(const std::string& str) { |
- if (str.empty() || str[0] == '0') |
- return false; |
- for (size_t i = 0; i < str.size(); ++i) |
- if (!IsAsciiDigit(str[i])) |
- return false; |
- return true; |
-} |
+std::vector<gfx::Size> ManifestParser::ParseIconSizes( |
+ const base::DictionaryValue& icon) { |
+ base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim); |
-// Parses the 'sizes' attribute of an icon as described in the HTML spec: |
-// https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes |
-// Return a vector of gfx::Size that contains the valid sizes found. "Any" is |
-// represented by gfx::Size(0, 0). |
-// TODO(mlamouri): this is implemented as a separate function because it should |
-// be refactored with the other icon sizes parsing implementations, see |
-// http://crbug.com/416477 |
-std::vector<gfx::Size> ParseIconSizesHTML(const base::string16& sizes_str16) { |
- if (!base::IsStringASCII(sizes_str16)) |
+ if (sizes_str.is_null()) |
return std::vector<gfx::Size>(); |
- std::vector<gfx::Size> sizes; |
- std::string sizes_str = |
- base::StringToLowerASCII(base::UTF16ToUTF8(sizes_str16)); |
- std::vector<std::string> sizes_str_list; |
- base::SplitStringAlongWhitespace(sizes_str, &sizes_str_list); |
- |
- for (size_t i = 0; i < sizes_str_list.size(); ++i) { |
- std::string& size_str = sizes_str_list[i]; |
- if (size_str == "any") { |
- sizes.push_back(gfx::Size(0, 0)); |
- continue; |
- } |
- |
- // It is expected that [0] => width and [1] => height after the split. |
- std::vector<std::string> size_list; |
- base::SplitStringDontTrim(size_str, L'x', &size_list); |
- if (size_list.size() != 2) |
- continue; |
- if (!IsValidIconWidthOrHeight(size_list[0]) || |
- !IsValidIconWidthOrHeight(size_list[1])) { |
- continue; |
- } |
- |
- int width, height; |
- if (!base::StringToInt(size_list[0], &width) || |
- !base::StringToInt(size_list[1], &height)) { |
- continue; |
- } |
- |
- sizes.push_back(gfx::Size(width, height)); |
+ std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string()); |
+ if (sizes.empty()) { |
+ errors_.push_back(GetErrorPrefix() + "found icon with no valid size."); |
} |
- |
return sizes; |
} |
-// Parses the 'sizes' field of an icon, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-a-sizes-member-of-an-icon |
-// Returns a vector of gfx::Size with the successfully parsed sizes, if any. An |
-// empty vector if the field was not present or empty. "Any" is represented by |
-// gfx::Size(0, 0). |
-std::vector<gfx::Size> ParseIconSizes(const base::DictionaryValue& icon) { |
- base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim); |
- |
- return sizes_str.is_null() ? std::vector<gfx::Size>() |
- : ParseIconSizesHTML(sizes_str.string()); |
-} |
- |
-// Parses the 'icons' field of a Manifest, as defined in: |
-// http://w3c.github.io/manifest/#dfn-steps-for-processing-the-icons-member |
-// Returns a vector of Manifest::Icon with the successfully parsed icons, if |
-// any. An empty vector if the field was not present or empty. |
-std::vector<Manifest::Icon> ParseIcons(const base::DictionaryValue& dictionary, |
- const GURL& manifest_url) { |
+std::vector<Manifest::Icon> ManifestParser::ParseIcons( |
+ const base::DictionaryValue& dictionary) { |
std::vector<Manifest::Icon> icons; |
if (!dictionary.HasKey("icons")) |
return icons; |
- const base::ListValue* icons_list = 0; |
+ const base::ListValue* icons_list = nullptr; |
if (!dictionary.GetList("icons", &icons_list)) { |
- // TODO(mlamouri): provide a custom message to the developer console about |
- // the property being incorrectly set. |
+ errors_.push_back(GetErrorPrefix() + |
+ "property 'icons' ignored, type array expected."); |
return icons; |
} |
for (size_t i = 0; i < icons_list->GetSize(); ++i) { |
- const base::DictionaryValue* icon_dictionary = 0; |
+ const base::DictionaryValue* icon_dictionary = nullptr; |
if (!icons_list->GetDictionary(i, &icon_dictionary)) |
continue; |
Manifest::Icon icon; |
- icon.src = ParseIconSrc(*icon_dictionary, manifest_url); |
+ icon.src = ParseIconSrc(*icon_dictionary); |
// An icon MUST have a valid src. If it does not, it MUST be ignored. |
if (!icon.src.is_valid()) |
continue; |
@@ -275,54 +317,9 @@ std::vector<Manifest::Icon> ParseIcons(const base::DictionaryValue& dictionary, |
return icons; |
} |
-// Parses the 'gcm_sender_id' field of the manifest. |
-// This is a proprietary extension of the Web Manifest specification. |
-// Returns the parsed string if any, a null string if the parsing failed. |
-base::NullableString16 ParseGCMSenderID( |
+base::NullableString16 ManifestParser::ParseGCMSenderID( |
const base::DictionaryValue& dictionary) { |
return ParseString(dictionary, "gcm_sender_id", Trim); |
} |
-} // anonymous namespace |
- |
-Manifest ManifestParser::Parse(const base::StringPiece& json, |
- const GURL& manifest_url, |
- const GURL& document_url) { |
- scoped_ptr<base::Value> value(base::JSONReader::Read(json)); |
- if (!value) { |
- // TODO(mlamouri): get the JSON parsing error and report it to the developer |
- // console. |
- ManifestUmaUtil::ParseFailed(); |
- return Manifest(); |
- } |
- |
- if (value->GetType() != base::Value::TYPE_DICTIONARY) { |
- // TODO(mlamouri): provide a custom message to the developer console. |
- ManifestUmaUtil::ParseFailed(); |
- return Manifest(); |
- } |
- |
- base::DictionaryValue* dictionary = 0; |
- value->GetAsDictionary(&dictionary); |
- if (!dictionary) { |
- // TODO(mlamouri): provide a custom message to the developer console. |
- ManifestUmaUtil::ParseFailed(); |
- return Manifest(); |
- } |
- |
- Manifest manifest; |
- |
- manifest.name = ParseName(*dictionary); |
- manifest.short_name = ParseShortName(*dictionary); |
- manifest.start_url = ParseStartURL(*dictionary, manifest_url, document_url); |
- manifest.display = ParseDisplay(*dictionary); |
- manifest.orientation = ParseOrientation(*dictionary); |
- manifest.icons = ParseIcons(*dictionary, manifest_url); |
- manifest.gcm_sender_id = ParseGCMSenderID(*dictionary); |
- |
- ManifestUmaUtil::ParseSucceeded(manifest); |
- |
- return manifest; |
-} |
- |
} // namespace content |