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

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 DCHECK(dictionary);
123
124 manifest_.name = ParseName(*dictionary);
125 manifest_.short_name = ParseShortName(*dictionary);
126 manifest_.start_url = ParseStartURL(*dictionary);
127 manifest_.display = ParseDisplay(*dictionary);
128 manifest_.orientation = ParseOrientation(*dictionary);
129 manifest_.icons = ParseIcons(*dictionary);
130 manifest_.gcm_sender_id = ParseGCMSenderID(*dictionary);
131
132 ManifestUmaUtil::ParseSucceeded(manifest_);
133 }
134
135 const Manifest& ManifestParser::manifest() const {
136 return manifest_;
137 }
138
139 const std::vector<std::string>& ManifestParser::errors() const {
140 return errors_;
141 }
142
143 bool ManifestParser::failed() const {
144 return failed_;
145 }
146
147 base::NullableString16 ManifestParser::ParseString(
148 const base::DictionaryValue& dictionary,
149 const std::string& key,
150 TrimType trim) {
30 if (!dictionary.HasKey(key)) 151 if (!dictionary.HasKey(key))
31 return base::NullableString16(); 152 return base::NullableString16();
32 153
33 base::string16 value; 154 base::string16 value;
34 if (!dictionary.GetString(key, &value)) { 155 if (!dictionary.GetString(key, &value)) {
35 // TODO(mlamouri): provide a custom message to the developer console about 156 errors_.push_back(GetErrorPrefix() +
36 // the property being incorrectly set. 157 "property '" + key + "' ignored, type string expected.");
37 return base::NullableString16(); 158 return base::NullableString16();
38 } 159 }
39 160
40 if (trim == Trim) 161 if (trim == Trim)
41 base::TrimWhitespace(value, base::TRIM_ALL, &value); 162 base::TrimWhitespace(value, base::TRIM_ALL, &value);
42 return base::NullableString16(value, false); 163 return base::NullableString16(value, false);
43 } 164 }
44 165
45 // Helper function to parse URLs present on a given |dictionary| in a given 166 GURL ManifestParser::ParseURL(const base::DictionaryValue& dictionary,
46 // field identified by its |key|. The URL is first parsed as a string then 167 const std::string& key,
47 // resolved using |base_url|. 168 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); 169 base::NullableString16 url_str = ParseString(dictionary, key, NoTrim);
53 if (url_str.is_null()) 170 if (url_str.is_null())
54 return GURL(); 171 return GURL();
55 172
56 return base_url.Resolve(url_str.string()); 173 return base_url.Resolve(url_str.string());
57 } 174 }
58 175
59 // Parses the 'name' field of the manifest, as defined in: 176 base::NullableString16 ManifestParser::ParseName(
60 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-name-member 177 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); 178 return ParseString(dictionary, "name", Trim);
64 } 179 }
65 180
66 // Parses the 'short_name' field of the manifest, as defined in: 181 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) { 182 const base::DictionaryValue& dictionary) {
71 return ParseString(dictionary, "short_name", Trim); 183 return ParseString(dictionary, "short_name", Trim);
72 } 184 }
73 185
74 // Parses the 'start_url' field of the manifest, as defined in: 186 GURL ManifestParser::ParseStartURL(const base::DictionaryValue& dictionary) {
75 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-start_url-member 187 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()) 188 if (!start_url.is_valid())
82 return GURL(); 189 return GURL();
83 190
84 if (start_url.GetOrigin() != document_url.GetOrigin()) { 191 if (start_url.GetOrigin() != document_url_.GetOrigin()) {
85 // TODO(mlamouri): provide a custom message to the developer console. 192 errors_.push_back(GetErrorPrefix() + "property 'start_url' ignored, should "
193 "be same origin as document.");
86 return GURL(); 194 return GURL();
87 } 195 }
88 196
89 return start_url; 197 return start_url;
90 } 198 }
91 199
92 // Parses the 'display' field of the manifest, as defined in: 200 Manifest::DisplayMode ManifestParser::ParseDisplay(
93 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-display-member 201 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); 202 base::NullableString16 display = ParseString(dictionary, "display", Trim);
98 if (display.is_null()) 203 if (display.is_null())
99 return Manifest::DISPLAY_MODE_UNSPECIFIED; 204 return Manifest::DISPLAY_MODE_UNSPECIFIED;
100 205
101 if (LowerCaseEqualsASCII(display.string(), "fullscreen")) 206 if (LowerCaseEqualsASCII(display.string(), "fullscreen"))
102 return Manifest::DISPLAY_MODE_FULLSCREEN; 207 return Manifest::DISPLAY_MODE_FULLSCREEN;
103 else if (LowerCaseEqualsASCII(display.string(), "standalone")) 208 else if (LowerCaseEqualsASCII(display.string(), "standalone"))
104 return Manifest::DISPLAY_MODE_STANDALONE; 209 return Manifest::DISPLAY_MODE_STANDALONE;
105 else if (LowerCaseEqualsASCII(display.string(), "minimal-ui")) 210 else if (LowerCaseEqualsASCII(display.string(), "minimal-ui"))
106 return Manifest::DISPLAY_MODE_MINIMAL_UI; 211 return Manifest::DISPLAY_MODE_MINIMAL_UI;
107 else if (LowerCaseEqualsASCII(display.string(), "browser")) 212 else if (LowerCaseEqualsASCII(display.string(), "browser"))
108 return Manifest::DISPLAY_MODE_BROWSER; 213 return Manifest::DISPLAY_MODE_BROWSER;
109 else 214 else {
215 errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored.");
110 return Manifest::DISPLAY_MODE_UNSPECIFIED; 216 return Manifest::DISPLAY_MODE_UNSPECIFIED;
217 }
111 } 218 }
112 219
113 // Parses the 'orientation' field of the manifest, as defined in: 220 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) { 221 const base::DictionaryValue& dictionary) {
119 base::NullableString16 orientation = 222 base::NullableString16 orientation =
120 ParseString(dictionary, "orientation", Trim); 223 ParseString(dictionary, "orientation", Trim);
121 224
122 if (orientation.is_null()) 225 if (orientation.is_null())
123 return blink::WebScreenOrientationLockDefault; 226 return blink::WebScreenOrientationLockDefault;
124 227
125 if (LowerCaseEqualsASCII(orientation.string(), "any")) 228 if (LowerCaseEqualsASCII(orientation.string(), "any"))
126 return blink::WebScreenOrientationLockAny; 229 return blink::WebScreenOrientationLockAny;
127 else if (LowerCaseEqualsASCII(orientation.string(), "natural")) 230 else if (LowerCaseEqualsASCII(orientation.string(), "natural"))
128 return blink::WebScreenOrientationLockNatural; 231 return blink::WebScreenOrientationLockNatural;
129 else if (LowerCaseEqualsASCII(orientation.string(), "landscape")) 232 else if (LowerCaseEqualsASCII(orientation.string(), "landscape"))
130 return blink::WebScreenOrientationLockLandscape; 233 return blink::WebScreenOrientationLockLandscape;
131 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-primary")) 234 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-primary"))
132 return blink::WebScreenOrientationLockLandscapePrimary; 235 return blink::WebScreenOrientationLockLandscapePrimary;
133 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-secondary")) 236 else if (LowerCaseEqualsASCII(orientation.string(), "landscape-secondary"))
134 return blink::WebScreenOrientationLockLandscapeSecondary; 237 return blink::WebScreenOrientationLockLandscapeSecondary;
135 else if (LowerCaseEqualsASCII(orientation.string(), "portrait")) 238 else if (LowerCaseEqualsASCII(orientation.string(), "portrait"))
136 return blink::WebScreenOrientationLockPortrait; 239 return blink::WebScreenOrientationLockPortrait;
137 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-primary")) 240 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-primary"))
138 return blink::WebScreenOrientationLockPortraitPrimary; 241 return blink::WebScreenOrientationLockPortraitPrimary;
139 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary")) 242 else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary"))
140 return blink::WebScreenOrientationLockPortraitSecondary; 243 return blink::WebScreenOrientationLockPortraitSecondary;
141 else 244 else {
245 errors_.push_back(GetErrorPrefix() +
246 "unknown 'orientation' value ignored.");
142 return blink::WebScreenOrientationLockDefault; 247 return blink::WebScreenOrientationLockDefault;
248 }
143 } 249 }
144 250
145 // Parses the 'src' field of an icon, as defined in: 251 GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) {
146 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-src-member-of-an- icon 252 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 } 253 }
152 254
153 // Parses the 'type' field of an icon, as defined in: 255 base::NullableString16 ManifestParser::ParseIconType(
154 // http://w3c.github.io/manifest/#dfn-steps-for-processing-the-type-member-of-an -icon 256 const base::DictionaryValue& icon) {
155 // Returns the parsed string if any, a null string if the parsing failed. 257 return ParseString(icon, "type", Trim);
156 base::NullableString16 ParseIconType(const base::DictionaryValue& icon) {
157 return ParseString(icon, "type", Trim);
158 } 258 }
159 259
160 // Parses the 'density' field of an icon, as defined in: 260 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; 261 double density;
166 if (!icon.GetDouble("density", &density) || density <= 0) 262 if (!icon.HasKey("density"))
167 return Manifest::Icon::kDefaultDensity; 263 return Manifest::Icon::kDefaultDensity;
264
265 if (!icon.GetDouble("density", &density) || density <= 0) {
266 errors_.push_back(GetErrorPrefix() +
267 "icon 'density' ignored, must be float greater than 0.");
268 return Manifest::Icon::kDefaultDensity;
269 }
168 return density; 270 return density;
169 } 271 }
170 272
171 // Helper function that returns whether the given |str| is a valid width or 273 std::vector<gfx::Size> ManifestParser::ParseIconSizes(
172 // height value for an icon sizes per: 274 const base::DictionaryValue& icon) {
173 // https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes 275 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 276
183 // Parses the 'sizes' attribute of an icon as described in the HTML spec: 277 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>(); 278 return std::vector<gfx::Size>();
193 279
194 std::vector<gfx::Size> sizes; 280 std::vector<gfx::Size> sizes = ParseIconSizesHTML(sizes_str.string());
195 std::string sizes_str = 281 if (sizes.empty()) {
196 base::StringToLowerASCII(base::UTF16ToUTF8(sizes_str16)); 282 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 } 283 }
225
226 return sizes; 284 return sizes;
227 } 285 }
228 286
229 // Parses the 'sizes' field of an icon, as defined in: 287 std::vector<Manifest::Icon> ManifestParser::ParseIcons(
230 // http://w3c.github.io/manifest/#dfn-steps-for-processing-a-sizes-member-of-an- icon 288 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; 289 std::vector<Manifest::Icon> icons;
248 if (!dictionary.HasKey("icons")) 290 if (!dictionary.HasKey("icons"))
249 return icons; 291 return icons;
250 292
251 const base::ListValue* icons_list = 0; 293 const base::ListValue* icons_list = nullptr;
252 if (!dictionary.GetList("icons", &icons_list)) { 294 if (!dictionary.GetList("icons", &icons_list)) {
253 // TODO(mlamouri): provide a custom message to the developer console about 295 errors_.push_back(GetErrorPrefix() +
254 // the property being incorrectly set. 296 "property 'icons' ignored, type array expected.");
255 return icons; 297 return icons;
256 } 298 }
257 299
258 for (size_t i = 0; i < icons_list->GetSize(); ++i) { 300 for (size_t i = 0; i < icons_list->GetSize(); ++i) {
259 const base::DictionaryValue* icon_dictionary = 0; 301 const base::DictionaryValue* icon_dictionary = nullptr;
260 if (!icons_list->GetDictionary(i, &icon_dictionary)) 302 if (!icons_list->GetDictionary(i, &icon_dictionary))
261 continue; 303 continue;
262 304
263 Manifest::Icon icon; 305 Manifest::Icon icon;
264 icon.src = ParseIconSrc(*icon_dictionary, manifest_url); 306 icon.src = ParseIconSrc(*icon_dictionary);
265 // An icon MUST have a valid src. If it does not, it MUST be ignored. 307 // An icon MUST have a valid src. If it does not, it MUST be ignored.
266 if (!icon.src.is_valid()) 308 if (!icon.src.is_valid())
267 continue; 309 continue;
268 icon.type = ParseIconType(*icon_dictionary); 310 icon.type = ParseIconType(*icon_dictionary);
269 icon.density = ParseIconDensity(*icon_dictionary); 311 icon.density = ParseIconDensity(*icon_dictionary);
270 icon.sizes = ParseIconSizes(*icon_dictionary); 312 icon.sizes = ParseIconSizes(*icon_dictionary);
271 313
272 icons.push_back(icon); 314 icons.push_back(icon);
273 } 315 }
274 316
275 return icons; 317 return icons;
276 } 318 }
277 319
278 // Parses the 'gcm_sender_id' field of the manifest. 320 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) { 321 const base::DictionaryValue& dictionary) {
283 return ParseString(dictionary, "gcm_sender_id", Trim); 322 return ParseString(dictionary, "gcm_sender_id", Trim);
284 } 323 }
285 324
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 325 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/manifest/manifest_parser.h ('k') | content/renderer/manifest/manifest_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698