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 #ifdef WIN32 | 5 #ifdef WIN32 |
6 #include <windows.h> | 6 #include <windows.h> |
7 #else | 7 #else |
8 #include <pthread.h> | 8 #include <pthread.h> |
9 #endif | 9 #endif |
10 | 10 |
11 #include <algorithm> | 11 #include <algorithm> |
12 #include <ostream> | 12 #include <ostream> |
13 | 13 |
14 #include "url/gurl.h" | 14 #include "url/gurl.h" |
15 | 15 |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "url/url_canon_stdstring.h" | 17 #include "url/url_canon_stdstring.h" |
18 #include "url/url_util.h" | 18 #include "url/url_util.h" |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 // External template that can handle initialization of either character type. | |
23 // The input spec is given, and the canonical version will be placed in | |
24 // |*canonical|, along with the parsing of the canonical spec in |*parsed|. | |
25 template<typename STR> | |
26 bool InitCanonical(const STR& input_spec, | |
27 std::string* canonical, | |
28 url_parse::Parsed* parsed) { | |
29 // Reserve enough room in the output for the input, plus some extra so that | |
30 // we have room if we have to escape a few things without reallocating. | |
31 canonical->reserve(input_spec.size() + 32); | |
32 url_canon::StdStringCanonOutput output(canonical); | |
33 bool success = url_util::Canonicalize( | |
34 input_spec.data(), static_cast<int>(input_spec.length()), | |
35 NULL, &output, parsed); | |
36 | |
37 output.Complete(); // Must be done before using string. | |
38 return success; | |
39 } | |
40 | |
41 static std::string* empty_string = NULL; | 22 static std::string* empty_string = NULL; |
42 static GURL* empty_gurl = NULL; | 23 static GURL* empty_gurl = NULL; |
43 | 24 |
44 #ifdef WIN32 | 25 #ifdef WIN32 |
45 | 26 |
46 // Returns a static reference to an empty string for returning a reference | 27 // Returns a static reference to an empty string for returning a reference |
47 // when there is no underlying string. | 28 // when there is no underlying string. |
48 const std::string& EmptyStringForGURL() { | 29 const std::string& EmptyStringForGURL() { |
49 // Avoid static object construction/destruction on startup/shutdown. | 30 // Avoid static object construction/destruction on startup/shutdown. |
50 if (!empty_string) { | 31 if (!empty_string) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 : spec_(other.spec_), | 68 : spec_(other.spec_), |
88 is_valid_(other.is_valid_), | 69 is_valid_(other.is_valid_), |
89 parsed_(other.parsed_) { | 70 parsed_(other.parsed_) { |
90 if (other.inner_url_) | 71 if (other.inner_url_) |
91 inner_url_.reset(new GURL(*other.inner_url_)); | 72 inner_url_.reset(new GURL(*other.inner_url_)); |
92 // Valid filesystem urls should always have an inner_url_. | 73 // Valid filesystem urls should always have an inner_url_. |
93 DCHECK(!is_valid_ || !SchemeIsFileSystem() || inner_url_); | 74 DCHECK(!is_valid_ || !SchemeIsFileSystem() || inner_url_); |
94 } | 75 } |
95 | 76 |
96 GURL::GURL(const std::string& url_string) { | 77 GURL::GURL(const std::string& url_string) { |
97 is_valid_ = InitCanonical(url_string, &spec_, &parsed_); | 78 InitCanonical(url_string, true); |
98 if (is_valid_ && SchemeIsFileSystem()) { | |
99 inner_url_.reset( | |
100 new GURL(spec_.data(), parsed_.Length(), | |
101 *parsed_.inner_parsed(), true)); | |
102 } | |
103 } | 79 } |
104 | 80 |
105 GURL::GURL(const base::string16& url_string) { | 81 GURL::GURL(const base::string16& url_string) { |
106 is_valid_ = InitCanonical(url_string, &spec_, &parsed_); | 82 InitCanonical(url_string, true); |
107 if (is_valid_ && SchemeIsFileSystem()) { | 83 } |
108 inner_url_.reset( | 84 |
109 new GURL(spec_.data(), parsed_.Length(), | 85 GURL::GURL(const std::string& url_string, RetainWhiteSpaceSelector) { |
110 *parsed_.inner_parsed(), true)); | 86 InitCanonical(url_string, false); |
111 } | |
112 } | 87 } |
113 | 88 |
114 GURL::GURL(const char* canonical_spec, size_t canonical_spec_len, | 89 GURL::GURL(const char* canonical_spec, size_t canonical_spec_len, |
115 const url_parse::Parsed& parsed, bool is_valid) | 90 const url_parse::Parsed& parsed, bool is_valid) |
116 : spec_(canonical_spec, canonical_spec_len), | 91 : spec_(canonical_spec, canonical_spec_len), |
117 is_valid_(is_valid), | 92 is_valid_(is_valid), |
118 parsed_(parsed) { | 93 parsed_(parsed) { |
119 InitializeFromCanonicalSpec(); | 94 InitializeFromCanonicalSpec(); |
120 } | 95 } |
121 | 96 |
122 GURL::GURL(std::string canonical_spec, | 97 GURL::GURL(std::string canonical_spec, |
123 const url_parse::Parsed& parsed, bool is_valid) | 98 const url_parse::Parsed& parsed, bool is_valid) |
124 : is_valid_(is_valid), | 99 : is_valid_(is_valid), |
125 parsed_(parsed) { | 100 parsed_(parsed) { |
126 spec_.swap(canonical_spec); | 101 spec_.swap(canonical_spec); |
127 InitializeFromCanonicalSpec(); | 102 InitializeFromCanonicalSpec(); |
128 } | 103 } |
129 | 104 |
| 105 template<typename STR> |
| 106 void GURL::InitCanonical(const STR& input_spec, bool trim_path_end) { |
| 107 // Reserve enough room in the output for the input, plus some extra so that |
| 108 // we have room if we have to escape a few things without reallocating. |
| 109 spec_.reserve(input_spec.size() + 32); |
| 110 url_canon::StdStringCanonOutput output(&spec_); |
| 111 is_valid_ = url_util::Canonicalize( |
| 112 input_spec.data(), static_cast<int>(input_spec.length()), trim_path_end, |
| 113 NULL, &output, &parsed_); |
| 114 |
| 115 output.Complete(); // Must be done before using string. |
| 116 if (is_valid_ && SchemeIsFileSystem()) { |
| 117 inner_url_.reset(new GURL(spec_.data(), parsed_.Length(), |
| 118 *parsed_.inner_parsed(), true)); |
| 119 } |
| 120 } |
| 121 |
130 void GURL::InitializeFromCanonicalSpec() { | 122 void GURL::InitializeFromCanonicalSpec() { |
131 if (is_valid_ && SchemeIsFileSystem()) { | 123 if (is_valid_ && SchemeIsFileSystem()) { |
132 inner_url_.reset( | 124 inner_url_.reset( |
133 new GURL(spec_.data(), parsed_.Length(), | 125 new GURL(spec_.data(), parsed_.Length(), |
134 *parsed_.inner_parsed(), true)); | 126 *parsed_.inner_parsed(), true)); |
135 } | 127 } |
136 | 128 |
137 #ifndef NDEBUG | 129 #ifndef NDEBUG |
138 // For testing purposes, check that the parsed canonical URL is identical to | 130 // For testing purposes, check that the parsed canonical URL is identical to |
139 // what we would have produced. Skip checking for invalid URLs have no meaning | 131 // what we would have produced. Skip checking for invalid URLs have no meaning |
140 // and we can't always canonicalize then reproducabely. | 132 // and we can't always canonicalize then reproducabely. |
141 if (is_valid_) { | 133 if (is_valid_) { |
142 url_parse::Component scheme; | 134 url_parse::Component scheme; |
| 135 // We can't do this check on the inner_url of a filesystem URL, as |
| 136 // canonical_spec actually points to the start of the outer URL, so we'd |
| 137 // end up with infinite recursion in this constructor. |
143 if (!url_util::FindAndCompareScheme(spec_.data(), spec_.length(), | 138 if (!url_util::FindAndCompareScheme(spec_.data(), spec_.length(), |
144 "filesystem", &scheme) || | 139 "filesystem", &scheme) || |
145 scheme.begin == parsed_.scheme.begin) { | 140 scheme.begin == parsed_.scheme.begin) { |
146 // We can't do this check on the inner_url of a filesystem URL, as | 141 // We need to retain trailing whitespace on path URLs, as the |parsed_| |
147 // canonical_spec actually points to the start of the outer URL, so we'd | 142 // spec we originally received may legitimately contain trailing white- |
148 // end up with infinite recursion in this constructor. | 143 // space on the path or components e.g. if the #ref has been |
149 GURL test_url(spec_); | 144 // removed from a "foo:hello #ref" URL (see http://crbug.com/291747). |
| 145 GURL test_url(spec_, RETAIN_TRAILING_PATH_WHITEPACE); |
150 | 146 |
151 DCHECK(test_url.is_valid_ == is_valid_); | 147 DCHECK(test_url.is_valid_ == is_valid_); |
152 DCHECK(test_url.spec_ == spec_); | 148 DCHECK(test_url.spec_ == spec_); |
153 | 149 |
154 DCHECK(test_url.parsed_.scheme == parsed_.scheme); | 150 DCHECK(test_url.parsed_.scheme == parsed_.scheme); |
155 DCHECK(test_url.parsed_.username == parsed_.username); | 151 DCHECK(test_url.parsed_.username == parsed_.username); |
156 DCHECK(test_url.parsed_.password == parsed_.password); | 152 DCHECK(test_url.parsed_.password == parsed_.password); |
157 DCHECK(test_url.parsed_.host == parsed_.host); | 153 DCHECK(test_url.parsed_.host == parsed_.host); |
158 DCHECK(test_url.parsed_.port == parsed_.port); | 154 DCHECK(test_url.parsed_.port == parsed_.port); |
159 DCHECK(test_url.parsed_.path == parsed_.path); | 155 DCHECK(test_url.parsed_.path == parsed_.path); |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 void GURL::Swap(GURL* other) { | 505 void GURL::Swap(GURL* other) { |
510 spec_.swap(other->spec_); | 506 spec_.swap(other->spec_); |
511 std::swap(is_valid_, other->is_valid_); | 507 std::swap(is_valid_, other->is_valid_); |
512 std::swap(parsed_, other->parsed_); | 508 std::swap(parsed_, other->parsed_); |
513 inner_url_.swap(other->inner_url_); | 509 inner_url_.swap(other->inner_url_); |
514 } | 510 } |
515 | 511 |
516 std::ostream& operator<<(std::ostream& out, const GURL& url) { | 512 std::ostream& operator<<(std::ostream& out, const GURL& url) { |
517 return out << url.possibly_invalid_spec(); | 513 return out << url.possibly_invalid_spec(); |
518 } | 514 } |
OLD | NEW |