OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/common/extensions/url_pattern.h" | 5 #include "chrome/common/extensions/url_pattern.h" |
6 | 6 |
7 #include "base/string_number_conversions.h" | 7 #include "base/string_number_conversions.h" |
8 #include "base/string_piece.h" | 8 #include "base/string_piece.h" |
9 #include "base/string_split.h" | 9 #include "base/string_split.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 int parsed_port = url_parse::PORT_UNSPECIFIED; | 89 int parsed_port = url_parse::PORT_UNSPECIFIED; |
90 if (!base::StringToInt(port, &parsed_port)) | 90 if (!base::StringToInt(port, &parsed_port)) |
91 return false; | 91 return false; |
92 return (parsed_port >= 0) && (parsed_port < 65536); | 92 return (parsed_port >= 0) && (parsed_port < 65536); |
93 } | 93 } |
94 | 94 |
95 } // namespace | 95 } // namespace |
96 | 96 |
97 URLPattern::URLPattern() | 97 URLPattern::URLPattern() |
98 : valid_schemes_(SCHEME_NONE), | 98 : valid_schemes_(SCHEME_NONE), |
| 99 valid_inner_schemes_(SCHEME_NONE), |
99 match_all_urls_(false), | 100 match_all_urls_(false), |
100 match_subdomains_(false), | 101 match_subdomains_(false), |
101 port_("*") {} | 102 port_("*") {} |
102 | 103 |
103 URLPattern::URLPattern(int valid_schemes) | 104 URLPattern::URLPattern(int valid_schemes) |
104 : valid_schemes_(valid_schemes), | 105 : valid_schemes_(valid_schemes), |
| 106 valid_inner_schemes_(valid_schemes), |
105 match_all_urls_(false), | 107 match_all_urls_(false), |
106 match_subdomains_(false), | 108 match_subdomains_(false), |
107 port_("*") {} | 109 port_("*") {} |
108 | 110 |
109 URLPattern::URLPattern(int valid_schemes, const std::string& pattern) | 111 URLPattern::URLPattern(int valid_schemes, const std::string& pattern) |
110 // Strict error checking is used, because this constructor is only | 112 // Strict error checking is used, because this constructor is only |
111 // appropriate when we know |pattern| is valid. | 113 // appropriate when we know |pattern| is valid. |
112 : valid_schemes_(valid_schemes), | 114 : valid_schemes_(valid_schemes), |
| 115 valid_inner_schemes_(valid_schemes), |
113 match_all_urls_(false), | 116 match_all_urls_(false), |
114 match_subdomains_(false), | 117 match_subdomains_(false), |
115 port_("*") { | 118 port_("*") { |
116 if (PARSE_SUCCESS != Parse(pattern)) | 119 if (PARSE_SUCCESS != Parse(pattern)) |
117 NOTREACHED() << "URLPattern is invalid: " << pattern; | 120 NOTREACHED() << "URLPattern is invalid: " << pattern; |
118 } | 121 } |
119 | 122 |
120 URLPattern::~URLPattern() { | 123 URLPattern::~URLPattern() { |
121 } | 124 } |
122 | 125 |
(...skipping 11 matching lines...) Expand all Loading... |
134 SetMatchSubdomains(false); | 137 SetMatchSubdomains(false); |
135 SetPort("*"); | 138 SetPort("*"); |
136 | 139 |
137 // Special case pattern to match every valid URL. | 140 // Special case pattern to match every valid URL. |
138 if (pattern == kAllUrlsPattern) { | 141 if (pattern == kAllUrlsPattern) { |
139 SetMatchAllURLs(true); | 142 SetMatchAllURLs(true); |
140 return PARSE_SUCCESS; | 143 return PARSE_SUCCESS; |
141 } | 144 } |
142 | 145 |
143 // Parse out the scheme. | 146 // Parse out the scheme. |
144 size_t scheme_end_pos = pattern.find(chrome::kStandardSchemeSeparator); | 147 size_t scheme_end_pos = pattern.find(':'); |
145 bool has_standard_scheme_separator = true; | |
146 | |
147 // Some urls also use ':' alone as the scheme separator. | |
148 if (scheme_end_pos == std::string::npos) { | |
149 scheme_end_pos = pattern.find(':'); | |
150 has_standard_scheme_separator = false; | |
151 } | |
152 | |
153 if (scheme_end_pos == std::string::npos) | 148 if (scheme_end_pos == std::string::npos) |
154 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR; | 149 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR; |
155 | 150 |
| 151 bool has_standard_scheme_separator = false; |
| 152 if (scheme_end_pos + 2 < pattern.length() && |
| 153 pattern[scheme_end_pos + 1] == '/' && |
| 154 pattern[scheme_end_pos + 2] == '/') { |
| 155 has_standard_scheme_separator = true; |
| 156 } |
| 157 |
156 if (!SetScheme(pattern.substr(0, scheme_end_pos))) | 158 if (!SetScheme(pattern.substr(0, scheme_end_pos))) |
157 return PARSE_ERROR_INVALID_SCHEME; | 159 return PARSE_ERROR_INVALID_SCHEME; |
158 | 160 |
159 bool standard_scheme = IsStandardScheme(scheme_); | 161 bool standard_scheme = IsStandardScheme(scheme_); |
| 162 |
| 163 if (scheme_ == chrome::kFileSystemScheme) { |
| 164 size_t inner_scheme_start_pos = scheme_end_pos + 1; |
| 165 scheme_end_pos = pattern.find(chrome::kStandardSchemeSeparator, |
| 166 inner_scheme_start_pos); |
| 167 if (scheme_end_pos == std::string::npos) |
| 168 return PARSE_ERROR_MISSING_SCHEME_SEPARATOR; |
| 169 has_standard_scheme_separator = true; |
| 170 if (!SetInnerScheme( |
| 171 pattern.substr(inner_scheme_start_pos, |
| 172 scheme_end_pos - inner_scheme_start_pos))) |
| 173 return PARSE_ERROR_INVALID_SCHEME; |
| 174 standard_scheme = IsStandardScheme(inner_scheme_); |
| 175 } |
| 176 |
160 if (standard_scheme != has_standard_scheme_separator) | 177 if (standard_scheme != has_standard_scheme_separator) |
161 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR; | 178 return PARSE_ERROR_WRONG_SCHEME_SEPARATOR; |
162 | 179 |
163 // Advance past the scheme separator. | 180 // Advance past the scheme separator. |
164 scheme_end_pos += | 181 scheme_end_pos += |
165 (standard_scheme ? strlen(chrome::kStandardSchemeSeparator) : 1); | 182 (has_standard_scheme_separator ? |
| 183 strlen(chrome::kStandardSchemeSeparator) : 1); |
166 if (scheme_end_pos >= pattern.size()) | 184 if (scheme_end_pos >= pattern.size()) |
167 return PARSE_ERROR_EMPTY_HOST; | 185 return PARSE_ERROR_EMPTY_HOST; |
168 | 186 |
169 // Parse out the host and path. | 187 // Parse out the host and path. |
170 size_t host_start_pos = scheme_end_pos; | 188 size_t host_start_pos = scheme_end_pos; |
171 size_t path_start_pos = 0; | 189 size_t path_start_pos = 0; |
172 | 190 |
173 if (!standard_scheme) { | 191 if (!standard_scheme) { |
174 path_start_pos = host_start_pos; | 192 path_start_pos = host_start_pos; |
175 } else if (scheme_ == chrome::kFileScheme) { | 193 } else if (scheme_ == chrome::kFileScheme) { |
176 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); | 194 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); |
177 if (host_end_pos == std::string::npos) { | 195 if (host_end_pos == std::string::npos) { |
178 // Allow hostname omission. | 196 // Allow hostname omission. |
179 // e.g. file://* is interpreted as file:///*, | 197 // e.g. file://* is interpreted as file:///*, |
180 // file://foo* is interpreted as file:///foo*. | 198 // file://foo* is interpreted as file:///foo*. |
181 path_start_pos = host_start_pos - 1; | 199 path_start_pos = host_start_pos - 1; |
182 } else { | 200 } else { |
183 // Ignore hostname if scheme is file://. | 201 // Ignore hostname if scheme is file://. |
184 // e.g. file://localhost/foo is equal to file:///foo. | 202 // e.g. file://localhost/foo is equal to file:///foo. |
185 path_start_pos = host_end_pos; | 203 path_start_pos = host_end_pos; |
186 } | 204 } |
| 205 } else if (scheme_ == chrome::kFileSystemScheme && |
| 206 inner_scheme_ == chrome::kFileScheme) { |
| 207 // We can't distinguish between a host and a storage type in a |
| 208 // filesystem:file URL, so just let it be part of the path. |
| 209 path_start_pos = host_start_pos; |
187 } else { | 210 } else { |
188 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); | 211 size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); |
189 | 212 |
190 // Host is required. | 213 // Host is required. |
191 if (host_start_pos == host_end_pos) | 214 if (host_start_pos == host_end_pos) |
192 return PARSE_ERROR_EMPTY_HOST; | 215 return PARSE_ERROR_EMPTY_HOST; |
193 | 216 |
194 if (host_end_pos == std::string::npos) | 217 if (host_end_pos == std::string::npos) |
195 return PARSE_ERROR_EMPTY_PATH; | 218 return PARSE_ERROR_EMPTY_PATH; |
196 | 219 |
(...skipping 26 matching lines...) Expand all Loading... |
223 // think '*' works as a glob in the host. | 246 // think '*' works as a glob in the host. |
224 if (host_.find('*') != std::string::npos) | 247 if (host_.find('*') != std::string::npos) |
225 return PARSE_ERROR_INVALID_HOST_WILDCARD; | 248 return PARSE_ERROR_INVALID_HOST_WILDCARD; |
226 | 249 |
227 return PARSE_SUCCESS; | 250 return PARSE_SUCCESS; |
228 } | 251 } |
229 | 252 |
230 void URLPattern::SetValidSchemes(int valid_schemes) { | 253 void URLPattern::SetValidSchemes(int valid_schemes) { |
231 spec_.clear(); | 254 spec_.clear(); |
232 valid_schemes_ = valid_schemes; | 255 valid_schemes_ = valid_schemes; |
| 256 valid_inner_schemes_ = valid_schemes; |
| 257 } |
| 258 |
| 259 void URLPattern::SetValidInnerSchemes(int valid_schemes) { |
| 260 spec_.clear(); |
| 261 valid_inner_schemes_ = valid_schemes; |
233 } | 262 } |
234 | 263 |
235 void URLPattern::SetHost(const std::string& host) { | 264 void URLPattern::SetHost(const std::string& host) { |
236 spec_.clear(); | 265 spec_.clear(); |
237 host_ = host; | 266 host_ = host; |
238 } | 267 } |
239 | 268 |
240 void URLPattern::SetMatchAllURLs(bool val) { | 269 void URLPattern::SetMatchAllURLs(bool val) { |
241 spec_.clear(); | 270 spec_.clear(); |
242 match_all_urls_ = val; | 271 match_all_urls_ = val; |
243 | 272 |
244 if (val) { | 273 if (val) { |
245 match_subdomains_ = true; | 274 match_subdomains_ = true; |
246 scheme_ = "*"; | 275 scheme_ = "*"; |
247 host_.clear(); | 276 host_.clear(); |
248 SetPath("/*"); | 277 SetPath("/*"); |
249 } | 278 } |
250 } | 279 } |
251 | 280 |
252 void URLPattern::SetMatchSubdomains(bool val) { | 281 void URLPattern::SetMatchSubdomains(bool val) { |
253 spec_.clear(); | 282 spec_.clear(); |
254 match_subdomains_ = val; | 283 match_subdomains_ = val; |
255 } | 284 } |
256 | 285 |
257 bool URLPattern::SetScheme(const std::string& scheme) { | 286 bool URLPattern::SetScheme(const std::string& scheme) { |
258 spec_.clear(); | 287 spec_.clear(); |
259 scheme_ = scheme; | 288 inner_scheme_.clear(); |
260 if (scheme_ == "*") { | 289 if (scheme == "*") { |
261 valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS); | 290 valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS); |
262 } else if (!IsValidScheme(scheme_)) { | 291 } else if (!IsValidScheme(scheme)) { |
263 return false; | 292 return false; |
264 } | 293 } |
| 294 scheme_ = scheme; |
265 return true; | 295 return true; |
266 } | 296 } |
267 | 297 |
| 298 bool URLPattern::SetInnerScheme(const std::string& inner_scheme) { |
| 299 spec_.clear(); |
| 300 DCHECK(scheme_ == chrome::kFileSystemScheme); |
| 301 if (inner_scheme == "*") { |
| 302 valid_inner_schemes_ = SCHEME_HTTP | SCHEME_HTTPS | SCHEME_FTP | |
| 303 SCHEME_EXTENSION; // Exclude file: and chrome:. |
| 304 } else if (!IsValidInnerScheme(inner_scheme)) { |
| 305 return false; |
| 306 } |
| 307 inner_scheme_ = inner_scheme; |
| 308 return true; |
| 309 } |
| 310 |
268 bool URLPattern::IsValidScheme(const std::string& scheme) const { | 311 bool URLPattern::IsValidScheme(const std::string& scheme) const { |
269 if (valid_schemes_ == SCHEME_ALL) | 312 if (valid_schemes_ == SCHEME_ALL) |
270 return true; | 313 return true; |
271 | 314 |
272 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { | 315 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { |
273 if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i])) | 316 if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i])) |
274 return true; | 317 return true; |
275 } | 318 } |
276 | 319 |
277 return false; | 320 return false; |
278 } | 321 } |
279 | 322 |
| 323 bool URLPattern::IsValidInnerScheme(const std::string& scheme) const { |
| 324 // kFileSystemScheme is never a valid inner scheme, even if using SCHEME_ALL. |
| 325 if (scheme == chrome::kFileSystemScheme) |
| 326 return false; |
| 327 |
| 328 if (valid_inner_schemes_ == SCHEME_ALL) |
| 329 return true; |
| 330 |
| 331 for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { |
| 332 if (scheme == kValidSchemes[i] && |
| 333 (valid_inner_schemes_ & kValidSchemeMasks[i])) |
| 334 return true; |
| 335 } |
| 336 |
| 337 return false; |
| 338 } |
| 339 |
280 void URLPattern::SetPath(const std::string& path) { | 340 void URLPattern::SetPath(const std::string& path) { |
281 spec_.clear(); | 341 spec_.clear(); |
282 path_ = path; | 342 path_ = path; |
283 path_escaped_ = path_; | 343 path_escaped_ = path_; |
284 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); | 344 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); |
285 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); | 345 ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); |
286 } | 346 } |
287 | 347 |
288 bool URLPattern::SetPort(const std::string& port) { | 348 bool URLPattern::SetPort(const std::string& port) { |
289 spec_.clear(); | 349 spec_.clear(); |
290 if (IsValidPortForScheme(scheme_, port)) { | 350 std::string scheme = |
| 351 (scheme_ == chrome::kFileSystemScheme) ? inner_scheme_ : scheme_; |
| 352 if (IsValidPortForScheme(scheme, port)) { |
291 port_ = port; | 353 port_ = port; |
292 return true; | 354 return true; |
293 } | 355 } |
294 return false; | 356 return false; |
295 } | 357 } |
296 | 358 |
297 bool URLPattern::MatchesURL(const GURL& test) const { | 359 bool URLPattern::MatchesURL(const GURL& test) const { |
298 if (!MatchesScheme(test.scheme())) | 360 if (!MatchesScheme(test.scheme())) |
299 return false; | 361 return false; |
300 | 362 |
301 if (match_all_urls_) | 363 if (match_all_urls_) |
302 return true; | 364 return true; |
303 | 365 |
304 return MatchesSecurityOriginHelper(test) && | 366 DCHECK(!test.SchemeIsFileSystem() || test.inner_url()); |
305 MatchesPath(test.PathForRequest()); | 367 if (scheme_ == chrome::kFileSystemScheme && |
| 368 (!test.SchemeIsFileSystem() || |
| 369 !MatchesInnerScheme(test.inner_url()->scheme()))) |
| 370 return false; |
| 371 |
| 372 std::string path = test.PathForRequest(); |
| 373 |
| 374 // Filesystem URLs have the first path segment on the inner_url. |
| 375 if (test.SchemeIsFileSystem()) |
| 376 path = test.inner_url()->path() + path; |
| 377 |
| 378 return MatchesSecurityOriginHelper(test) && MatchesPath(path); |
306 } | 379 } |
307 | 380 |
308 bool URLPattern::MatchesSecurityOrigin(const GURL& test) const { | 381 bool URLPattern::MatchesSecurityOrigin(const GURL& test) const { |
309 if (!MatchesScheme(test.scheme())) | 382 if (!MatchesScheme(test.scheme())) |
310 return false; | 383 return false; |
311 | 384 |
312 if (match_all_urls_) | 385 if (match_all_urls_) |
313 return true; | 386 return true; |
314 | 387 |
315 return MatchesSecurityOriginHelper(test); | 388 return MatchesSecurityOriginHelper(test); |
316 } | 389 } |
317 | 390 |
318 bool URLPattern::MatchesScheme(const std::string& test) const { | 391 bool URLPattern::MatchesScheme(const std::string& test) const { |
319 if (!IsValidScheme(test)) | 392 if (!IsValidScheme(test)) |
320 return false; | 393 return false; |
321 | 394 |
322 return scheme_ == "*" || test == scheme_; | 395 return scheme_ == "*" || test == scheme_; |
323 } | 396 } |
324 | 397 |
| 398 bool URLPattern::MatchesInnerScheme(const std::string& test) const { |
| 399 DCHECK(scheme_ == chrome::kFileSystemScheme); |
| 400 if (!IsValidInnerScheme(test)) |
| 401 return false; |
| 402 |
| 403 return inner_scheme_ == "*" || test == inner_scheme_; |
| 404 } |
| 405 |
325 bool URLPattern::MatchesHost(const std::string& host) const { | 406 bool URLPattern::MatchesHost(const std::string& host) const { |
326 std::string test(chrome::kHttpScheme); | 407 std::string test(chrome::kHttpScheme); |
327 test += chrome::kStandardSchemeSeparator; | 408 test += chrome::kStandardSchemeSeparator; |
328 test += host; | 409 test += host; |
329 test += "/"; | 410 test += "/"; |
330 return MatchesHost(GURL(test)); | 411 return MatchesHost(GURL(test)); |
331 } | 412 } |
332 | 413 |
333 bool URLPattern::MatchesHost(const GURL& test) const { | 414 bool URLPattern::MatchesHost(const GURL& test) const { |
334 // If the hosts are exactly equal, we have a match. | 415 // If the hosts are exactly equal, we have a match. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 if (!spec_.empty()) | 461 if (!spec_.empty()) |
381 return spec_; | 462 return spec_; |
382 | 463 |
383 if (match_all_urls_) { | 464 if (match_all_urls_) { |
384 spec_ = kAllUrlsPattern; | 465 spec_ = kAllUrlsPattern; |
385 return spec_; | 466 return spec_; |
386 } | 467 } |
387 | 468 |
388 bool standard_scheme = IsStandardScheme(scheme_); | 469 bool standard_scheme = IsStandardScheme(scheme_); |
389 | 470 |
390 std::string spec = scheme_ + | 471 std::string spec = scheme_; |
391 (standard_scheme ? chrome::kStandardSchemeSeparator : ":"); | 472 std::string scheme = scheme_; |
| 473 bool add_standard_separator = standard_scheme; |
| 474 if (scheme_ == chrome::kFileSystemScheme) { |
| 475 spec += ":" + inner_scheme_; |
| 476 add_standard_separator = true; |
| 477 standard_scheme = IsStandardScheme(inner_scheme_); |
| 478 scheme = inner_scheme_; |
| 479 } |
| 480 spec += (add_standard_separator ? chrome::kStandardSchemeSeparator : ":"); |
392 | 481 |
393 if (scheme_ != chrome::kFileScheme && standard_scheme) { | 482 if (scheme != chrome::kFileScheme && standard_scheme) { |
394 if (match_subdomains_) { | 483 if (match_subdomains_) { |
395 spec += "*"; | 484 spec += "*"; |
396 if (!host_.empty()) | 485 if (!host_.empty()) |
397 spec += "."; | 486 spec += "."; |
398 } | 487 } |
399 | 488 |
400 if (!host_.empty()) | 489 if (!host_.empty()) |
401 spec += host_; | 490 spec += host_; |
402 | 491 |
403 if (port_ != "*") { | 492 if (port_ != "*") { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
445 for (std::vector<std::string>::const_iterator i = schemes.begin(); | 534 for (std::vector<std::string>::const_iterator i = schemes.begin(); |
446 i != schemes.end(); ++i) { | 535 i != schemes.end(); ++i) { |
447 if (MatchesScheme(*i)) | 536 if (MatchesScheme(*i)) |
448 return true; | 537 return true; |
449 } | 538 } |
450 | 539 |
451 return false; | 540 return false; |
452 } | 541 } |
453 | 542 |
454 bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const { | 543 bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const { |
455 // Ignore hostname if scheme is file://. | 544 // Ignore hostname if scheme is file:// or filesystem:file://. |
456 if (scheme_ != chrome::kFileScheme && !MatchesHost(test)) | 545 std::string scheme = scheme_; |
| 546 const GURL* test_url = &test; |
| 547 if (scheme == chrome::kFileSystemScheme) { |
| 548 scheme = inner_scheme_; |
| 549 test_url = test.inner_url(); |
| 550 DCHECK(test_url); |
| 551 } |
| 552 if (scheme != chrome::kFileScheme && !MatchesHost(*test_url)) |
457 return false; | 553 return false; |
458 | 554 |
459 if (!MatchesPort(test.EffectiveIntPort())) | 555 if (!MatchesPort(test_url->EffectiveIntPort())) |
460 return false; | 556 return false; |
461 | 557 |
462 return true; | 558 return true; |
463 } | 559 } |
464 | 560 |
465 std::vector<std::string> URLPattern::GetExplicitSchemes() const { | 561 std::vector<std::string> URLPattern::GetExplicitSchemes() const { |
466 std::vector<std::string> result; | 562 std::vector<std::string> result; |
467 | 563 |
468 if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) { | 564 if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) { |
469 result.push_back(scheme_); | 565 result.push_back(scheme_); |
(...skipping 22 matching lines...) Expand all Loading... |
492 } | 588 } |
493 | 589 |
494 return result; | 590 return result; |
495 } | 591 } |
496 | 592 |
497 // static | 593 // static |
498 const char* URLPattern::GetParseResultString( | 594 const char* URLPattern::GetParseResultString( |
499 URLPattern::ParseResult parse_result) { | 595 URLPattern::ParseResult parse_result) { |
500 return kParseResultMessages[parse_result]; | 596 return kParseResultMessages[parse_result]; |
501 } | 597 } |
OLD | NEW |