OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "url/url_util.h" | 5 #include "url/url_util.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/debug/leak_annotations.h" | 10 #include "base/debug/leak_annotations.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "url/url_canon_internal.h" | 13 #include "url/url_canon_internal.h" |
14 #include "url/url_file.h" | 14 #include "url/url_file.h" |
15 #include "url/url_util_internal.h" | 15 #include "url/url_util_internal.h" |
16 | 16 |
17 namespace url { | 17 namespace url { |
18 | 18 |
19 namespace { | 19 namespace { |
20 | 20 |
21 const int kNumStandardURLSchemes = 8; | 21 const int kNumStandardURLSchemes = 8; |
22 const char* kStandardURLSchemes[kNumStandardURLSchemes] = { | 22 const SchemeWithType kStandardURLSchemes[kNumStandardURLSchemes] = { |
23 kHttpScheme, | 23 {kHttpScheme, SCHEME_WITH_PORT}, |
24 kHttpsScheme, | 24 {kHttpsScheme, SCHEME_WITH_PORT}, |
25 kFileScheme, // Yes, file urls can have a hostname! | 25 {kFileScheme, SCHEME_WITHOUT_PORT}, // Yes, file urls can have a hostname! |
Ryan Sleevi
2015/08/13 22:32:12
nit: It took me a while to find out why this is 't
tyoshino (SeeGerritForStatus)
2015/08/14 06:29:01
Ya. At least we won't break anything new, I think.
| |
26 kFtpScheme, | 26 {kFtpScheme, SCHEME_WITH_PORT}, |
27 kGopherScheme, | 27 {kGopherScheme, SCHEME_WITH_PORT}, |
28 kWsScheme, // WebSocket. | 28 {kWsScheme, SCHEME_WITH_PORT}, // WebSocket. |
29 kWssScheme, // WebSocket secure. | 29 {kWssScheme, SCHEME_WITH_PORT}, // WebSocket secure. |
30 kFileSystemScheme, | 30 {kFileSystemScheme, SCHEME_WITHOUT_AUTHORITY}, |
31 }; | 31 }; |
32 | 32 |
33 // List of the currently installed standard schemes. This list is lazily | 33 // List of the currently installed standard schemes. This list is lazily |
34 // initialized by InitStandardSchemes and is leaked on shutdown to prevent | 34 // initialized by InitStandardSchemes and is leaked on shutdown to prevent |
35 // any destructors from being called that will slow us down or cause problems. | 35 // any destructors from being called that will slow us down or cause problems. |
36 std::vector<const char*>* standard_schemes = NULL; | 36 std::vector<SchemeWithType>* standard_schemes = NULL; |
37 | 37 |
38 // See the LockStandardSchemes declaration in the header. | 38 // See the LockStandardSchemes declaration in the header. |
39 bool standard_schemes_locked = false; | 39 bool standard_schemes_locked = false; |
40 | 40 |
41 // This template converts a given character type to the corresponding | 41 // This template converts a given character type to the corresponding |
42 // StringPiece type. | 42 // StringPiece type. |
43 template<typename CHAR> struct CharToStringPiece { | 43 template<typename CHAR> struct CharToStringPiece { |
44 }; | 44 }; |
45 template<> struct CharToStringPiece<char> { | 45 template<> struct CharToStringPiece<char> { |
46 typedef base::StringPiece Piece; | 46 typedef base::StringPiece Piece; |
47 }; | 47 }; |
48 template<> struct CharToStringPiece<base::char16> { | 48 template<> struct CharToStringPiece<base::char16> { |
49 typedef base::StringPiece16 Piece; | 49 typedef base::StringPiece16 Piece; |
50 }; | 50 }; |
51 | 51 |
52 // Ensures that the standard_schemes list is initialized, does nothing if it | 52 // Ensures that the standard_schemes list is initialized, does nothing if it |
53 // already has values. | 53 // already has values. |
54 void InitStandardSchemes() { | 54 void InitStandardSchemes() { |
55 if (standard_schemes) | 55 if (standard_schemes) |
56 return; | 56 return; |
57 standard_schemes = new std::vector<const char*>; | 57 standard_schemes = new std::vector<SchemeWithType>; |
58 for (int i = 0; i < kNumStandardURLSchemes; i++) | 58 for (int i = 0; i < kNumStandardURLSchemes; i++) |
59 standard_schemes->push_back(kStandardURLSchemes[i]); | 59 standard_schemes->push_back(kStandardURLSchemes[i]); |
60 } | 60 } |
61 | 61 |
62 // Given a string and a range inside the string, compares it to the given | 62 // Given a string and a range inside the string, compares it to the given |
63 // lower-case |compare_to| buffer. | 63 // lower-case |compare_to| buffer. |
64 template<typename CHAR> | 64 template<typename CHAR> |
65 inline bool DoCompareSchemeComponent(const CHAR* spec, | 65 inline bool DoCompareSchemeComponent(const CHAR* spec, |
66 const Component& component, | 66 const Component& component, |
67 const char* compare_to) { | 67 const char* compare_to) { |
68 if (!component.is_nonempty()) | 68 if (!component.is_nonempty()) |
69 return compare_to[0] == 0; // When component is empty, match empty scheme. | 69 return compare_to[0] == 0; // When component is empty, match empty scheme. |
70 return base::LowerCaseEqualsASCII( | 70 return base::LowerCaseEqualsASCII( |
71 typename CharToStringPiece<CHAR>::Piece( | 71 typename CharToStringPiece<CHAR>::Piece( |
72 &spec[component.begin], component.len), | 72 &spec[component.begin], component.len), |
73 compare_to); | 73 compare_to); |
74 } | 74 } |
75 | 75 |
76 // Returns true if the given scheme identified by |scheme| within |spec| is one | 76 // Returns true and sets |type| to the SchemeType of the given scheme |
77 // of the registered "standard" schemes. | 77 // identified by |scheme| within |spec| if the scheme is one of the registered |
78 // "standard" schemes. | |
78 template<typename CHAR> | 79 template<typename CHAR> |
79 bool DoIsStandard(const CHAR* spec, const Component& scheme) { | 80 bool DoIsStandard(const CHAR* spec, |
81 const Component& scheme, | |
82 SchemeType* type) { | |
80 if (!scheme.is_nonempty()) | 83 if (!scheme.is_nonempty()) |
81 return false; // Empty or invalid schemes are non-standard. | 84 return false; // Empty or invalid schemes are non-standard. |
82 | 85 |
83 InitStandardSchemes(); | 86 InitStandardSchemes(); |
84 for (size_t i = 0; i < standard_schemes->size(); i++) { | 87 for (size_t i = 0; i < standard_schemes->size(); i++) { |
85 if (base::LowerCaseEqualsASCII( | 88 if (base::LowerCaseEqualsASCII( |
86 typename CharToStringPiece<CHAR>::Piece( | 89 typename CharToStringPiece<CHAR>::Piece( |
87 &spec[scheme.begin], scheme.len), | 90 &spec[scheme.begin], scheme.len), |
88 standard_schemes->at(i))) | 91 standard_schemes->at(i).scheme)) { |
92 *type = standard_schemes->at(i).type; | |
89 return true; | 93 return true; |
94 } | |
90 } | 95 } |
91 return false; | 96 return false; |
92 } | 97 } |
93 | 98 |
94 template<typename CHAR> | 99 template<typename CHAR> |
95 bool DoFindAndCompareScheme(const CHAR* str, | 100 bool DoFindAndCompareScheme(const CHAR* str, |
96 int str_len, | 101 int str_len, |
97 const char* compare, | 102 const char* compare, |
98 Component* found_scheme) { | 103 Component* found_scheme) { |
99 // Before extracting scheme, canonicalize the URL to remove any whitespace. | 104 // Before extracting scheme, canonicalize the URL to remove any whitespace. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 } | 154 } |
150 #endif | 155 #endif |
151 | 156 |
152 Component scheme; | 157 Component scheme; |
153 if (!ExtractScheme(spec, spec_len, &scheme)) | 158 if (!ExtractScheme(spec, spec_len, &scheme)) |
154 return false; | 159 return false; |
155 | 160 |
156 // This is the parsed version of the input URL, we have to canonicalize it | 161 // This is the parsed version of the input URL, we have to canonicalize it |
157 // before storing it in our object. | 162 // before storing it in our object. |
158 bool success; | 163 bool success; |
164 SchemeType unused_scheme_type = SCHEME_WITH_PORT; | |
159 if (DoCompareSchemeComponent(spec, scheme, url::kFileScheme)) { | 165 if (DoCompareSchemeComponent(spec, scheme, url::kFileScheme)) { |
160 // File URLs are special. | 166 // File URLs are special. |
161 ParseFileURL(spec, spec_len, &parsed_input); | 167 ParseFileURL(spec, spec_len, &parsed_input); |
162 success = CanonicalizeFileURL(spec, spec_len, parsed_input, | 168 success = CanonicalizeFileURL(spec, spec_len, parsed_input, |
163 charset_converter, output, output_parsed); | 169 charset_converter, output, output_parsed); |
164 } else if (DoCompareSchemeComponent(spec, scheme, url::kFileSystemScheme)) { | 170 } else if (DoCompareSchemeComponent(spec, scheme, url::kFileSystemScheme)) { |
165 // Filesystem URLs are special. | 171 // Filesystem URLs are special. |
166 ParseFileSystemURL(spec, spec_len, &parsed_input); | 172 ParseFileSystemURL(spec, spec_len, &parsed_input); |
167 success = CanonicalizeFileSystemURL(spec, spec_len, parsed_input, | 173 success = CanonicalizeFileSystemURL(spec, spec_len, parsed_input, |
168 charset_converter, output, | 174 charset_converter, output, |
169 output_parsed); | 175 output_parsed); |
170 | 176 |
171 } else if (DoIsStandard(spec, scheme)) { | 177 } else if (DoIsStandard(spec, scheme, &unused_scheme_type)) { |
172 // All "normal" URLs. | 178 // All "normal" URLs. |
173 ParseStandardURL(spec, spec_len, &parsed_input); | 179 ParseStandardURL(spec, spec_len, &parsed_input); |
174 success = CanonicalizeStandardURL(spec, spec_len, parsed_input, | 180 success = CanonicalizeStandardURL(spec, spec_len, parsed_input, |
175 charset_converter, output, output_parsed); | 181 charset_converter, output, output_parsed); |
176 | 182 |
177 } else if (DoCompareSchemeComponent(spec, scheme, url::kMailToScheme)) { | 183 } else if (DoCompareSchemeComponent(spec, scheme, url::kMailToScheme)) { |
178 // Mailto are treated like a standard url with only a scheme, path, query | 184 // Mailto are treated like a standard url with only a scheme, path, query |
179 ParseMailtoURL(spec, spec_len, &parsed_input); | 185 ParseMailtoURL(spec, spec_len, &parsed_input); |
180 success = CanonicalizeMailtoURL(spec, spec_len, parsed_input, output, | 186 success = CanonicalizeMailtoURL(spec, spec_len, parsed_input, output, |
181 output_parsed); | 187 output_parsed); |
(...skipping 27 matching lines...) Expand all Loading... | |
209 bool base_is_hierarchical = false; | 215 bool base_is_hierarchical = false; |
210 if (base_spec && | 216 if (base_spec && |
211 base_parsed.scheme.is_nonempty()) { | 217 base_parsed.scheme.is_nonempty()) { |
212 int after_scheme = base_parsed.scheme.end() + 1; // Skip past the colon. | 218 int after_scheme = base_parsed.scheme.end() + 1; // Skip past the colon. |
213 int num_slashes = CountConsecutiveSlashes(base_spec, after_scheme, | 219 int num_slashes = CountConsecutiveSlashes(base_spec, after_scheme, |
214 base_spec_len); | 220 base_spec_len); |
215 base_is_authority_based = num_slashes > 1; | 221 base_is_authority_based = num_slashes > 1; |
216 base_is_hierarchical = num_slashes > 0; | 222 base_is_hierarchical = num_slashes > 0; |
217 } | 223 } |
218 | 224 |
225 SchemeType unused_scheme_type = SCHEME_WITH_PORT; | |
219 bool standard_base_scheme = | 226 bool standard_base_scheme = |
220 base_parsed.scheme.is_nonempty() && | 227 base_parsed.scheme.is_nonempty() && |
221 DoIsStandard(base_spec, base_parsed.scheme); | 228 DoIsStandard(base_spec, base_parsed.scheme, &unused_scheme_type); |
222 | 229 |
223 bool is_relative; | 230 bool is_relative; |
224 Component relative_component; | 231 Component relative_component; |
225 if (!IsRelativeURL(base_spec, base_parsed, relative, relative_length, | 232 if (!IsRelativeURL(base_spec, base_parsed, relative, relative_length, |
226 (base_is_hierarchical || standard_base_scheme), | 233 (base_is_hierarchical || standard_base_scheme), |
227 &is_relative, &relative_component)) { | 234 &is_relative, &relative_component)) { |
228 // Error resolving. | 235 // Error resolving. |
229 return false; | 236 return false; |
230 } | 237 } |
231 | 238 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
332 // If we get here, then we know the scheme doesn't need to be replaced, so can | 339 // If we get here, then we know the scheme doesn't need to be replaced, so can |
333 // just key off the scheme in the spec to know how to do the replacements. | 340 // just key off the scheme in the spec to know how to do the replacements. |
334 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kFileScheme)) { | 341 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kFileScheme)) { |
335 return ReplaceFileURL(spec, parsed, replacements, charset_converter, output, | 342 return ReplaceFileURL(spec, parsed, replacements, charset_converter, output, |
336 out_parsed); | 343 out_parsed); |
337 } | 344 } |
338 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kFileSystemScheme)) { | 345 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kFileSystemScheme)) { |
339 return ReplaceFileSystemURL(spec, parsed, replacements, charset_converter, | 346 return ReplaceFileSystemURL(spec, parsed, replacements, charset_converter, |
340 output, out_parsed); | 347 output, out_parsed); |
341 } | 348 } |
342 if (DoIsStandard(spec, parsed.scheme)) { | 349 SchemeType unused_scheme_type = SCHEME_WITH_PORT; |
350 if (DoIsStandard(spec, parsed.scheme, &unused_scheme_type)) { | |
343 return ReplaceStandardURL(spec, parsed, replacements, charset_converter, | 351 return ReplaceStandardURL(spec, parsed, replacements, charset_converter, |
344 output, out_parsed); | 352 output, out_parsed); |
345 } | 353 } |
346 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kMailToScheme)) { | 354 if (DoCompareSchemeComponent(spec, parsed.scheme, url::kMailToScheme)) { |
347 return ReplaceMailtoURL(spec, parsed, replacements, output, out_parsed); | 355 return ReplaceMailtoURL(spec, parsed, replacements, output, out_parsed); |
348 } | 356 } |
349 | 357 |
350 // Default is a path URL. | 358 // Default is a path URL. |
351 return ReplacePathURL(spec, parsed, replacements, output, out_parsed); | 359 return ReplacePathURL(spec, parsed, replacements, output, out_parsed); |
352 } | 360 } |
353 | 361 |
354 } // namespace | 362 } // namespace |
355 | 363 |
356 void Initialize() { | 364 void Initialize() { |
357 InitStandardSchemes(); | 365 InitStandardSchemes(); |
358 } | 366 } |
359 | 367 |
360 void Shutdown() { | 368 void Shutdown() { |
361 if (standard_schemes) { | 369 if (standard_schemes) { |
362 delete standard_schemes; | 370 delete standard_schemes; |
363 standard_schemes = NULL; | 371 standard_schemes = NULL; |
364 } | 372 } |
365 } | 373 } |
366 | 374 |
367 void AddStandardScheme(const char* new_scheme) { | 375 void AddStandardScheme(const char* new_scheme, |
376 SchemeType type) { | |
368 // If this assert triggers, it means you've called AddStandardScheme after | 377 // If this assert triggers, it means you've called AddStandardScheme after |
369 // LockStandardSchemes have been called (see the header file for | 378 // LockStandardSchemes have been called (see the header file for |
370 // LockStandardSchemes for more). | 379 // LockStandardSchemes for more). |
371 // | 380 // |
372 // This normally means you're trying to set up a new standard scheme too late | 381 // This normally means you're trying to set up a new standard scheme too late |
373 // in your application's init process. Locate where your app does this | 382 // in your application's init process. Locate where your app does this |
374 // initialization and calls LockStandardScheme, and add your new standard | 383 // initialization and calls LockStandardScheme, and add your new standard |
375 // scheme there. | 384 // scheme there. |
376 DCHECK(!standard_schemes_locked) << | 385 DCHECK(!standard_schemes_locked) << |
377 "Trying to add a standard scheme after the list has been locked."; | 386 "Trying to add a standard scheme after the list has been locked."; |
378 | 387 |
379 size_t scheme_len = strlen(new_scheme); | 388 size_t scheme_len = strlen(new_scheme); |
380 if (scheme_len == 0) | 389 if (scheme_len == 0) |
381 return; | 390 return; |
382 | 391 |
383 // Dulicate the scheme into a new buffer and add it to the list of standard | 392 // Dulicate the scheme into a new buffer and add it to the list of standard |
384 // schemes. This pointer will be leaked on shutdown. | 393 // schemes. This pointer will be leaked on shutdown. |
385 char* dup_scheme = new char[scheme_len + 1]; | 394 char* dup_scheme = new char[scheme_len + 1]; |
386 ANNOTATE_LEAKING_OBJECT_PTR(dup_scheme); | 395 ANNOTATE_LEAKING_OBJECT_PTR(dup_scheme); |
387 memcpy(dup_scheme, new_scheme, scheme_len + 1); | 396 memcpy(dup_scheme, new_scheme, scheme_len + 1); |
388 | 397 |
389 InitStandardSchemes(); | 398 InitStandardSchemes(); |
390 standard_schemes->push_back(dup_scheme); | 399 standard_schemes->push_back(SchemeWithType(dup_scheme, type)); |
391 } | 400 } |
392 | 401 |
393 void LockStandardSchemes() { | 402 void LockStandardSchemes() { |
394 standard_schemes_locked = true; | 403 standard_schemes_locked = true; |
395 } | 404 } |
396 | 405 |
397 bool IsStandard(const char* spec, const Component& scheme) { | 406 bool IsStandard(const char* spec, const Component& scheme) { |
398 return DoIsStandard(spec, scheme); | 407 SchemeType unused_scheme_type; |
408 return DoIsStandard(spec, scheme, &unused_scheme_type); | |
409 } | |
410 | |
411 bool GetStandardSchemeType(const char* spec, | |
412 const Component& scheme, | |
413 SchemeType* type) { | |
414 return DoIsStandard(spec, scheme, type); | |
399 } | 415 } |
400 | 416 |
401 bool IsStandard(const base::char16* spec, const Component& scheme) { | 417 bool IsStandard(const base::char16* spec, const Component& scheme) { |
402 return DoIsStandard(spec, scheme); | 418 SchemeType unused_scheme_type; |
419 return DoIsStandard(spec, scheme, &unused_scheme_type); | |
403 } | 420 } |
404 | 421 |
405 bool FindAndCompareScheme(const char* str, | 422 bool FindAndCompareScheme(const char* str, |
406 int str_len, | 423 int str_len, |
407 const char* compare, | 424 const char* compare, |
408 Component* found_scheme) { | 425 Component* found_scheme) { |
409 return DoFindAndCompareScheme(str, str_len, compare, found_scheme); | 426 return DoFindAndCompareScheme(str, str_len, compare, found_scheme); |
410 } | 427 } |
411 | 428 |
412 bool FindAndCompareScheme(const base::char16* str, | 429 bool FindAndCompareScheme(const base::char16* str, |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
550 return DoCompareSchemeComponent(spec, component, compare_to); | 567 return DoCompareSchemeComponent(spec, component, compare_to); |
551 } | 568 } |
552 | 569 |
553 bool CompareSchemeComponent(const base::char16* spec, | 570 bool CompareSchemeComponent(const base::char16* spec, |
554 const Component& component, | 571 const Component& component, |
555 const char* compare_to) { | 572 const char* compare_to) { |
556 return DoCompareSchemeComponent(spec, component, compare_to); | 573 return DoCompareSchemeComponent(spec, component, compare_to); |
557 } | 574 } |
558 | 575 |
559 } // namespace url | 576 } // namespace url |
OLD | NEW |