Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: content/renderer/manifest/manifest_parser.cc

Issue 748373003: Report errors when parsing Manifest and expose them in developer console. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: review comments Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/manifest/manifest_parser.h" 5 #include "content/renderer/manifest/manifest_parser.h"
6 6
7 #include "base/json/json_reader.h" 7 #include "base/json/json_reader.h"
8 #include "base/strings/nullable_string16.h" 8 #include "base/strings/nullable_string16.h"
9 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_split.h" 10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h" 13 #include "base/values.h"
14 #include "content/public/common/manifest.h" 14 #include "content/public/common/manifest.h"
15 #include "content/renderer/manifest/manifest_uma_util.h" 15 #include "content/renderer/manifest/manifest_uma_util.h"
16 #include "ui/gfx/geometry/size.h" 16 #include "ui/gfx/geometry/size.h"
17 17
18 namespace content { 18 namespace content {
19 19
20 namespace { 20 namespace {
21 21
22 enum TrimType { 22 // Helper function that returns whether the given |str| is a valid width or
23 Trim, 23 // height value for an icon sizes per:
24 NoTrim 24 // https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
25 }; 25 bool IsValidIconWidthOrHeight(const std::string& str) {
26 if (str.empty() || str[0] == '0')
27 return false;
28 for (size_t i = 0; i < str.size(); ++i)
29 if (!IsAsciiDigit(str[i]))
30 return false;
31 return true;
32 }
26 33
27 base::NullableString16 ParseString(const base::DictionaryValue& dictionary, 34 // Parses the 'sizes' attribute of an icon as described in the HTML spec:
28 const std::string& key, 35 // https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
29 TrimType trim) { 36 // Return a vector of gfx::Size that contains the valid sizes found. "Any" is
37 // represented by gfx::Size(0, 0).
38 // TODO(mlamouri): this is implemented as a separate function because it should
39 // be refactored with the other icon sizes parsing implementations, see
40 // http://crbug.com/416477
41 std::vector<gfx::Size> ParseIconSizesHTML(const base::string16& sizes_str16) {
42 if (!base::IsStringASCII(sizes_str16))
43 return std::vector<gfx::Size>();
44
45 std::vector<gfx::Size> sizes;
46 std::string sizes_str =
47 base::StringToLowerASCII(base::UTF16ToUTF8(sizes_str16));
48 std::vector<std::string> sizes_str_list;
49 base::SplitStringAlongWhitespace(sizes_str, &sizes_str_list);
50
51 for (size_t i = 0; i < sizes_str_list.size(); ++i) {
52 std::string& size_str = sizes_str_list[i];
53 if (size_str == "any") {
54 sizes.push_back(gfx::Size(0, 0));
55 continue;
56 }
57
58 // It is expected that [0] => width and [1] => height after the split.
59 std::vector<std::string> size_list;
60 base::SplitStringDontTrim(size_str, L'x', &size_list);
61 if (size_list.size() != 2)
62 continue;
63 if (!IsValidIconWidthOrHeight(size_list[0]) ||
64 !IsValidIconWidthOrHeight(size_list[1])) {
65 continue;
66 }
67
68 int width, height;
69 if (!base::StringToInt(size_list[0], &width) ||
70 !base::StringToInt(size_list[1], &height)) {
71 continue;
72 }
73
74 sizes.push_back(gfx::Size(width, height));
75 }
76
77 return sizes;
78 }
79
80 const std::string& GetErrorPrefix() {
81 CR_DEFINE_STATIC_LOCAL(std::string, error_prefix,
82 ("Manifest parsing error: "));
83 return error_prefix;
84 }
85
86 } // anonymous namespace
87
88
89 ManifestParser::ManifestParser(const base::StringPiece& data,
90 const GURL& manifest_url,
91 const GURL& document_url)
92 : data_(data),
93 manifest_url_(manifest_url),
94 document_url_(document_url),
95 failed_(false) {
96 }
97
98 ManifestParser::~ManifestParser() {
99 }
100
101 void ManifestParser::Parse() {
102 std::string parse_error;
103 scoped_ptr<base::Value> value(
104 base::JSONReader::ReadAndReturnError(data_, base::JSON_PARSE_RFC,
105 nullptr, &parse_error));
106
107 if (!value) {
108 errors_.push_back(GetErrorPrefix() + parse_error);
109 ManifestUmaUtil::ParseFailed();
110 failed_ = true;
111 return;
112 }
113
114 base::DictionaryValue* dictionary = nullptr;
115 if (!value->GetAsDictionary(&dictionary)) {
116 errors_.push_back(GetErrorPrefix() +
117 "root element must be a valid JSON object.");
118 ManifestUmaUtil::ParseFailed();
119 failed_ = true;
120 return;
121 }
122
123 manifest_.name = ParseName(*dictionary);
124 manifest_.short_name = ParseShortName(*dictionary);
125 manifest_.start_url = ParseStartURL(*dictionary);
126 manifest_.display = ParseDisplay(*dictionary);
127 manifest_.orientation = ParseOrientation(*dictionary);
128 manifest_.icons = ParseIcons(*dictionary);
129 manifest_.gcm_sender_id = ParseGCMSenderID(*dictionary);
130
131 ManifestUmaUtil::ParseSucceeded(manifest_);
132 }
133
134 const Manifest& ManifestParser::manifest() const {
135 return manifest_;
136 }
137
138 const std::vector<std::string>& ManifestParser::errors() const {
139 return errors_;
140 }
141
142 bool ManifestParser::failed() const {
143 return failed_;
144 }
145
146 base::NullableString16 ManifestParser::ParseString(
147 const base::DictionaryValue& dictionary,
148 const std::string& key,
149 TrimType trim) {
30 if (!dictionary.HasKey(key)) 150 if (!dictionary.HasKey(key))
31 return base::NullableString16(); 151 return base::NullableString16();
32 152
33 base::string16 value; 153 base::string16 value;
34 if (!dictionary.GetString(key, &value)) { 154 if (!dictionary.GetString(key, &value)) {
35 // TODO(mlamouri): provide a custom message to the developer console about 155 errors_.push_back(GetErrorPrefix() +
36 // the property being incorrectly set. 156 "property '" + key + "' ignored, type string expected.");
37 return base::NullableString16(); 157 return base::NullableString16();
38 } 158 }
39 159
40 if (trim == Trim) 160 if (trim == Trim)
41 base::TrimWhitespace(value, base::TRIM_ALL, &value); 161 base::TrimWhitespace(value, base::TRIM_ALL, &value);
42 return base::NullableString16(value, false); 162 return base::NullableString16(value, false);
43 } 163 }
44 164
45 // Helper function to parse URLs present on a given |dictionary| in a given 165 GURL ManifestParser::ParseURL(const base::DictionaryValue& dictionary,
46 // field identified by its |key|. The URL is first parsed as a string then 166 const std::string& key,
47 // resolved using |base_url|. 167 const GURL& base_url) {
48 // Returns a GURL. If the parsing failed, the GURL will not be valid.
49 GURL ParseURL(const base::DictionaryValue& dictionary,
50 const std::string& key,
51 const GURL& base_url) {
52 base::NullableString16 url_str = ParseString(dictionary, key, NoTrim); 168 base::NullableString16 url_str = ParseString(dictionary, key, NoTrim);
53 if (url_str.is_null()) 169 if (url_str.is_null())
54 return GURL(); 170 return GURL();
55 171
56 return base_url.Resolve(url_str.string()); 172 return base_url.Resolve(url_str.string());
57 } 173 }
58 174
59 // Parses the 'name' field of the manifest, as defined in: 175 base::NullableString16 ManifestParser::ParseName(
60 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-name-member 176 const base::DictionaryValue& dictionary) {
61 // Returns the parsed string if any, a null string if the parsing failed.
62 base::NullableString16 ParseName(const base::DictionaryValue& dictionary) {
63 return ParseString(dictionary, "name", Trim); 177 return ParseString(dictionary, "name", Trim);
64 } 178 }
65 179
66 // Parses the 'short_name' field of the manifest, as defined in: 180 base::NullableString16 ManifestParser::ParseShortName(
67 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-short-name-member
68 // Returns the parsed string if any, a null string if the parsing failed.
69 base::NullableString16 ParseShortName(
70 const base::DictionaryValue& dictionary) { 181 const base::DictionaryValue& dictionary) {
71 return ParseString(dictionary, "short_name", Trim); 182 return ParseString(dictionary, "short_name", Trim);
72 } 183 }
73 184
74 // Parses the 'start_url' field of the manifest, as defined in: 185 GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) {
75 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-start_url-member 186 GURL start_url = ParseURL(dictionary, "start_url", manifest_url_);
76 // Returns the parsed GURL if any, an empty GURL if the parsing failed.
77 GURL ParseStartURL(const base::DictionaryValue& dictionary,
78 const GURL& manifest_url,
79 const GURL& document_url) {
80 GURL start_url = ParseURL(dictionary, "start_url", manifest_url);
81 if (!start_url.is_valid()) 187 if (!start_url.is_valid())
82 return GURL(); 188 return GURL();
83 189
84 if (start_url.GetOrigin() != document_url.GetOrigin()) { 190 if (start_url.GetOrigin() != document_url_.GetOrigin()) {
85 // TODO(mlamouri): provide a custom message to the developer console. 191 errors_.push_back(GetErrorPrefix() + "property 'start_url' ignored, should "
192 "be same origin as document.");
86 return GURL(); 193 return GURL();
87 } 194 }
88 195
89 return start_url; 196 return start_url;
90 } 197 }
91 198
92 // Parses the 'display' field of the manifest, as defined in: 199 Manifest::DisplayMode ManifestParser::ParseDisplay(
93 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-display-member 200 const base::DictionaryValue& dictionary) {
94 // Returns the parsed DisplayMode if any, DISPLAY_MODE_UNSPECIFIED if the
95 // parsing failed.
96 Manifest::DisplayMode ParseDisplay(const base::DictionaryValue& dictionary) {
97 base::NullableString16 display = ParseString(dictionary, "display", Trim); 201 base::NullableString16 display = ParseString(dictionary, "display", Trim);
98 if (display.is_null()) 202 if (display.is_null())
99 return Manifest::DISPLAY_MODE_UNSPECIFIED; 203 return Manifest::DISPLAY_MODE_UNSPECIFIED;
100 204
101 if (LowerCaseEqualsASCII(display.string(), "fullscreen")) 205 if (LowerCaseEqualsASCII(display.string(), "fullscreen"))
102 return Manifest::DISPLAY_MODE_FULLSCREEN; 206 return Manifest::DISPLAY_MODE_FULLSCREEN;
103 else if (LowerCaseEqualsASCII(display.string(), "standalone")) 207 else if (LowerCaseEqualsASCII(display.string(), "standalone"))
104 return Manifest::DISPLAY_MODE_STANDALONE; 208 return Manifest::DISPLAY_MODE_STANDALONE;
105 else if (LowerCaseEqualsASCII(display.string(), "minimal-ui")) 209 else if (LowerCaseEqualsASCII(display.string(), "minimal-ui"))
106 return Manifest::DISPLAY_MODE_MINIMAL_UI; 210 return Manifest::DISPLAY_MODE_MINIMAL_UI;
107 else if (LowerCaseEqualsASCII(display.string(), "browser")) 211 else if (LowerCaseEqualsASCII(display.string(), "browser"))
108 return Manifest::DISPLAY_MODE_BROWSER; 212 return Manifest::DISPLAY_MODE_BROWSER;
109 else 213 else {
214 errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored.");
110 return Manifest::DISPLAY_MODE_UNSPECIFIED; 215 return Manifest::DISPLAY_MODE_UNSPECIFIED;
216 }
111 } 217 }
112 218
113 // Parses the 'orientation' field of the manifest, as defined in: 219 blink::WebScreenOrientationLockType ManifestParser::ParseOrientation(
114 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-orientation-membe r
115 // Returns the parsed WebScreenOrientationLockType if any,
116 // WebScreenOrientationLockDefault if the parsing failed.
117 blink::WebScreenOrientationLockType ParseOrientation(
118 const base::DictionaryValue& dictionary) { 220 const base::DictionaryValue& dictionary) {
119 base::NullableString16 orientation = 221 base::NullableString16 orientation =
120 ParseString(dictionary, "orientation", Trim); 222 ParseString(dictionary, "orientation", Trim);
121 223
122 if (orientation.is_null()) 224 if (orientation.is_null())
123 return blink::WebScreenOrientationLockDefault; 225 return blink::WebScreenOrientationLockDefault;
124 226
125 if (LowerCaseEqualsASCII(orientation.string(), "any")) 227 if (LowerCaseEqualsASCII(orientation.string(), "any"))
126 return blink::WebScreenOrientationLockAny; 228 return blink::WebScreenOrientationLockAny;
127 else if (LowerCaseEqualsASCII(orientation.string(), "natural")) 229 else if (LowerCaseEqualsASCII(orientation.string(), "natural"))
128 return blink::WebScreenOrientationLockNatural; 230 return blink::WebScreenOrientationLockNatural;
129 else if (LowerCaseEqualsASCII(orientation.string(), "landscape")) 231 else if (LowerCaseEqualsASCII(orientation.string(), "landscape"))
130 return blink::WebScreenOrientationLockLandscape; 232 return blink::WebScreenOrientationLockLandscape;
131 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-primary")) 233 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-primary"))
132 return blink::WebScreenOrientationLockLandscapePrimary; 234 return blink::WebScreenOrientationLockLandscapePrimary;
133 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-secondary")) 235 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-secondary"))
134 return blink::WebScreenOrientationLockLandscapeSecondary; 236 return blink::WebScreenOrientationLockLandscapeSecondary;
135 else if (LowerCaseEqualsASCII(orientation.string(), "portrait")) 237 else if (LowerCaseEqualsASCII(orientation.string(), "portrait"))
136 return blink::WebScreenOrientationLockPortrait; 238 return blink::WebScreenOrientationLockPortrait;
137 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-primary")) 239 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-primary"))
138 return blink::WebScreenOrientationLockPortraitPrimary; 240 return blink::WebScreenOrientationLockPortraitPrimary;
139 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary")) 241 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary"))
140 return blink::WebScreenOrientationLockPortraitSecondary; 242 return blink::WebScreenOrientationLockPortraitSecondary;
141 else 243 else {
244 errors_.push_back(GetErrorPrefix() +
245 "unknown 'orientation' value ignored.");
142 return blink::WebScreenOrientationLockDefault; 246 return blink::WebScreenOrientationLockDefault;
247 }
143 } 248 }
144 249
145 // Parses the 'src' field of an icon, as defined in: 250 GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) {
146 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-src-member-of-an- icon 251 return ParseURL(icon, "src", manifest_url_);
147 // Returns the parsed GURL if any, an empty GURL if the parsing failed.
148 GURL ParseIconSrc(const base::DictionaryValue& icon,
149 const GURL& manifest_url) {
150 return ParseURL(icon, "src", manifest_url);
151 } 252 }
152 253
153 // Parses the 'type' field of an icon, as defined in: 254 base::NullableString16 ManifestParser::ParseIconType(
154 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-type-member-of-an -icon 255 const base::DictionaryValue& icon) {
155 // Returns the parsed string if any, a null string if the parsing failed. 256 return ParseString(icon, "type", Trim);
156 base::NullableString16 ParseIconType(const base::DictionaryValue& icon) {
157 return ParseString(icon, "type", Trim);
158 } 257 }
159 258
160 // Parses the 'density' field of an icon, as defined in: 259 double ManifestParser::ParseIconDensity(const base::DictionaryValue& icon) {
161 // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-density-member-of-a n-icon
162 // Returns the parsed double if any, Manifest::Icon::kDefaultDensity if the
163 // parsing failed.
164 double ParseIconDensity(const base::DictionaryValue& icon) {
165 double density; 260 double density;
166 if (!icon.GetDouble("density", &density) || density <= 0) 261 if (!icon.HasKey("density"))
167 return Manifest::Icon::kDefaultDensity; 262 return Manifest::Icon::kDefaultDensity;
263
264 if (!icon.GetDouble("density", &density) || density <= 0) {
265 errors_.push_back(GetErrorPrefix() +
266 "icon 'density' ignored, must be float greater than 0.");
267 return Manifest::Icon::kDefaultDensity;
268 }
168 return density; 269 return density;
169 } 270 }
170 271
171 // Helper function that returns whether the given |str| is a valid width or 272 std::vector<gfx::Size> ManifestParser::ParseIconSizes(
172 // height value for an icon sizes per: 273 const base::DictionaryValue& icon) {
173 // https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes 274 base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim);
174 bool IsValidIconWidthOrHeight(const std::string& str) {
175 if (str.empty() || str[0] == '0')
176 return false;
177 for (size_t i = 0; i < str.size(); ++i)
178 if (!IsAsciiDigit(str[i]))
179 return false;
180 return true;
181 }
182 275
183 // Parses the 'sizes' attribute of an icon as described in the HTML spec: 276 if (sizes_str.is_null())
184 // https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes
185 // Return a vector of gfx::Size that contains the valid sizes found. "Any" is
186 // represented by gfx::Size(0, 0).
187 // TODO(mlamouri): this is implemented as a separate function because it should
188 // be refactored with the other icon sizes parsing implementations, see
189 // http://crbug.com/416477
190 std::vector<gfx::Size> ParseIconSizesHTML(const base::string16& sizes_str16) {
191 if (!base::IsStringASCII(sizes_str16))
192 return std::vector<gfx::Size>(); 277 return std::vector<gfx::Size>();
193 278
194 std::vector<gfx::Size> sizes; 279 std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string());
195 std::string sizes_str = 280 if (sizes.empty()) {
196 base::StringToLowerASCII(base::UTF16ToUTF8(sizes_str16)); 281 errors_.push_back(GetErrorPrefix() + "found icon with no valid size.");
197 std::vector<std::string> sizes_str_list;
198 base::SplitStringAlongWhitespace(sizes_str, &sizes_str_list);
199
200 for (size_t i = 0; i < sizes_str_list.size(); ++i) {
201 std::string& size_str = sizes_str_list[i];
202 if (size_str == "any") {
203 sizes.push_back(gfx::Size(0, 0));
204 continue;
205 }
206
207 // It is expected that [0] => width and [1] => height after the split.
208 std::vector<std::string> size_list;
209 base::SplitStringDontTrim(size_str, L'x', &size_list);
210 if (size_list.size() != 2)
211 continue;
212 if (!IsValidIconWidthOrHeight(size_list[0]) ||
213 !IsValidIconWidthOrHeight(size_list[1])) {
214 continue;
215 }
216
217 int width, height;
218 if (!base::StringToInt(size_list[0], &width) ||
219 !base::StringToInt(size_list[1], &height)) {
220 continue;
221 }
222
223 sizes.push_back(gfx::Size(width, height));
224 } 282 }
225
226 return sizes; 283 return sizes;
227 } 284 }
228 285
229 // Parses the 'sizes' field of an icon, as defined in: 286 std::vector<Manifest::Icon> ManifestParser::ParseIcons(
230 // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-sizes-member-of-an- icon 287 const base::DictionaryValue& dictionary) {
231 // Returns a vector of gfx::Size with the successfully parsed sizes, if any. An
232 // empty vector if the field was not present or empty. "Any" is represented by
233 // gfx::Size(0, 0).
234 std::vector<gfx::Size> ParseIconSizes(const base::DictionaryValue& icon) {
235 base::NullableString16 sizes_str = ParseString(icon, "sizes", NoTrim);
236
237 return sizes_str.is_null() ? std::vector<gfx::Size>()
238 : ParseIconSizesHTML(sizes_str.string());
239 }
240
241 // Parses the 'icons' field of a Manifest, as defined in:
242 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-icons-member
243 // Returns a vector of Manifest::Icon with the successfully parsed icons, if
244 // any. An empty vector if the field was not present or empty.
245 std::vector<Manifest::Icon> ParseIcons(const base::DictionaryValue& dictionary,
246 const GURL& manifest_url) {
247 std::vector<Manifest::Icon> icons; 288 std::vector<Manifest::Icon> icons;
248 if (!dictionary.HasKey("icons")) 289 if (!dictionary.HasKey("icons"))
249 return icons; 290 return icons;
250 291
251 const base::ListValue* icons_list = 0; 292 const base::ListValue* icons_list = nullptr;
252 if (!dictionary.GetList("icons", &icons_list)) { 293 if (!dictionary.GetList("icons", &icons_list)) {
253 // TODO(mlamouri): provide a custom message to the developer console about 294 errors_.push_back(GetErrorPrefix() +
254 // the property being incorrectly set. 295 "property 'icons' ignored, type array expected.");
255 return icons; 296 return icons;
256 } 297 }
257 298
258 for (size_t i = 0; i < icons_list->GetSize(); ++i) { 299 for (size_t i = 0; i < icons_list->GetSize(); ++i) {
259 const base::DictionaryValue* icon_dictionary = 0; 300 const base::DictionaryValue* icon_dictionary = nullptr;
260 if (!icons_list->GetDictionary(i, &icon_dictionary)) 301 if (!icons_list->GetDictionary(i, &icon_dictionary))
261 continue; 302 continue;
262 303
263 Manifest::Icon icon; 304 Manifest::Icon icon;
264 icon.src = ParseIconSrc(*icon_dictionary, manifest_url); 305 icon.src = ParseIconSrc(*icon_dictionary);
265 // An icon MUST have a valid src. If it does not, it MUST be ignored. 306 // An icon MUST have a valid src. If it does not, it MUST be ignored.
266 if (!icon.src.is_valid()) 307 if (!icon.src.is_valid())
267 continue; 308 continue;
268 icon.type = ParseIconType(*icon_dictionary); 309 icon.type = ParseIconType(*icon_dictionary);
269 icon.density = ParseIconDensity(*icon_dictionary); 310 icon.density = ParseIconDensity(*icon_dictionary);
270 icon.sizes = ParseIconSizes(*icon_dictionary); 311 icon.sizes = ParseIconSizes(*icon_dictionary);
271 312
272 icons.push_back(icon); 313 icons.push_back(icon);
273 } 314 }
274 315
275 return icons; 316 return icons;
276 } 317 }
277 318
278 // Parses the 'gcm_sender_id' field of the manifest. 319 base::NullableString16 ManifestParser::ParseGCMSenderID(
279 // This is a proprietary extension of the Web Manifest specification.
280 // Returns the parsed string if any, a null string if the parsing failed.
281 base::NullableString16 ParseGCMSenderID(
282 const base::DictionaryValue& dictionary) { 320 const base::DictionaryValue& dictionary) {
283 return ParseString(dictionary, "gcm_sender_id", Trim); 321 return ParseString(dictionary, "gcm_sender_id", Trim);
284 } 322 }
285 323
286 } // anonymous namespace
287
288 Manifest ManifestParser::Parse(const base::StringPiece& json,
289 const GURL& manifest_url,
290 const GURL& document_url) {
291 scoped_ptr<base::Value> value(base::JSONReader::Read(json));
292 if (!value) {
293 // TODO(mlamouri): get the JSON parsing error and report it to the developer
294 // console.
295 ManifestUmaUtil::ParseFailed();
296 return Manifest();
297 }
298
299 if (value->GetType() != base::Value::TYPE_DICTIONARY) {
300 // TODO(mlamouri): provide a custom message to the developer console.
301 ManifestUmaUtil::ParseFailed();
302 return Manifest();
303 }
304
305 base::DictionaryValue* dictionary = 0;
306 value->GetAsDictionary(&dictionary);
307 if (!dictionary) {
308 // TODO(mlamouri): provide a custom message to the developer console.
309 ManifestUmaUtil::ParseFailed();
310 return Manifest();
311 }
312
313 Manifest manifest;
314
315 manifest.name = ParseName(*dictionary);
316 manifest.short_name = ParseShortName(*dictionary);
317 manifest.start_url = ParseStartURL(*dictionary, manifest_url, document_url);
318 manifest.display = ParseDisplay(*dictionary);
319 manifest.orientation = ParseOrientation(*dictionary);
320 manifest.icons = ParseIcons(*dictionary, manifest_url);
321 manifest.gcm_sender_id = ParseGCMSenderID(*dictionary);
322
323 ManifestUmaUtil::ParseSucceeded(manifest);
324
325 return manifest;
326 }
327
328 } // namespace content 324 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698