[email protected] | 51bcc5d | 2013-04-24 01:41:37 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 4 | |
avi | c0c6031 | 2015-12-21 21:03:50 | [diff] [blame] | 5 | #include "url/gurl.h" |
| 6 | |
| 7 | #include <stddef.h> |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 8 | |
| 9 | #include <algorithm> |
| 10 | #include <ostream> |
| 11 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 12 | #include "base/logging.h" |
qyearsley | 7ffaa68 | 2015-08-03 07:03:49 | [diff] [blame] | 13 | #include "base/strings/string_piece.h" |
brettw | bc17d2c8 | 2015-06-09 22:39:08 | [diff] [blame] | 14 | #include "base/strings/string_util.h" |
dskiba | 3bc10ee8 | 2017-02-01 01:22:19 | [diff] [blame] | 15 | #include "base/trace_event/memory_usage_estimator.h" |
[email protected] | 318076b | 2013-04-18 21:19:45 | [diff] [blame] | 16 | #include "url/url_canon_stdstring.h" |
| 17 | #include "url/url_util.h" |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 18 | |
avi | c0c6031 | 2015-12-21 21:03:50 | [diff] [blame] | 19 | #ifdef WIN32 |
| 20 | #include <windows.h> |
| 21 | #else |
| 22 | #include <pthread.h> |
| 23 | #endif |
| 24 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 25 | namespace { |
| 26 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 27 | static std::string* empty_string = NULL; |
| 28 | static GURL* empty_gurl = NULL; |
| 29 | |
| 30 | #ifdef WIN32 |
| 31 | |
| 32 | // Returns a static reference to an empty string for returning a reference |
| 33 | // when there is no underlying string. |
| 34 | const std::string& EmptyStringForGURL() { |
| 35 | // Avoid static object construction/destruction on startup/shutdown. |
| 36 | if (!empty_string) { |
| 37 | // Create the string. Be careful that we don't break in the case that this |
| 38 | // is being called from multiple threads. Statics are not threadsafe. |
| 39 | std::string* new_empty_string = new std::string; |
| 40 | if (InterlockedCompareExchangePointer( |
| 41 | reinterpret_cast<PVOID*>(&empty_string), new_empty_string, NULL)) { |
| 42 | // The old value was non-NULL, so no replacement was done. Another |
| 43 | // thread did the initialization out from under us. |
| 44 | delete new_empty_string; |
| 45 | } |
| 46 | } |
| 47 | return *empty_string; |
| 48 | } |
| 49 | |
| 50 | #else |
| 51 | |
| 52 | static pthread_once_t empty_string_once = PTHREAD_ONCE_INIT; |
| 53 | static pthread_once_t empty_gurl_once = PTHREAD_ONCE_INIT; |
| 54 | |
| 55 | void EmptyStringForGURLOnce(void) { |
| 56 | empty_string = new std::string; |
| 57 | } |
| 58 | |
| 59 | const std::string& EmptyStringForGURL() { |
| 60 | // Avoid static object construction/destruction on startup/shutdown. |
| 61 | pthread_once(&empty_string_once, EmptyStringForGURLOnce); |
| 62 | return *empty_string; |
| 63 | } |
| 64 | |
| 65 | #endif // WIN32 |
| 66 | |
qyearsley | 2bc727d | 2015-08-14 20:17:15 | [diff] [blame] | 67 | } // namespace |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 68 | |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 69 | GURL::GURL() : is_valid_(false) { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | GURL::GURL(const GURL& other) |
| 73 | : spec_(other.spec_), |
| 74 | is_valid_(other.is_valid_), |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 75 | parsed_(other.parsed_) { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 76 | if (other.inner_url_) |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 77 | inner_url_.reset(new GURL(*other.inner_url_)); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 78 | // Valid filesystem urls should always have an inner_url_. |
| 79 | DCHECK(!is_valid_ || !SchemeIsFileSystem() || inner_url_); |
| 80 | } |
| 81 | |
sclittle | 376085b3 | 2017-03-14 21:08:41 | [diff] [blame] | 82 | GURL::GURL(GURL&& other) |
| 83 | : spec_(std::move(other.spec_)), |
| 84 | is_valid_(other.is_valid_), |
| 85 | parsed_(other.parsed_), |
| 86 | inner_url_(std::move(other.inner_url_)) { |
| 87 | other.is_valid_ = false; |
| 88 | other.parsed_ = url::Parsed(); |
| 89 | } |
| 90 | |
brettw | dfbcc3b | 2016-01-20 01:49:17 | [diff] [blame] | 91 | GURL::GURL(base::StringPiece url_string) { |
[email protected] | 369e84f7 | 2013-11-23 01:53:52 | [diff] [blame] | 92 | InitCanonical(url_string, true); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 93 | } |
| 94 | |
brettw | dfbcc3b | 2016-01-20 01:49:17 | [diff] [blame] | 95 | GURL::GURL(base::StringPiece16 url_string) { |
[email protected] | 369e84f7 | 2013-11-23 01:53:52 | [diff] [blame] | 96 | InitCanonical(url_string, true); |
| 97 | } |
| 98 | |
| 99 | GURL::GURL(const std::string& url_string, RetainWhiteSpaceSelector) { |
brettw | dfbcc3b | 2016-01-20 01:49:17 | [diff] [blame] | 100 | InitCanonical(base::StringPiece(url_string), false); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 101 | } |
| 102 | |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 103 | GURL::GURL(const char* canonical_spec, |
| 104 | size_t canonical_spec_len, |
| 105 | const url::Parsed& parsed, |
| 106 | bool is_valid) |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 107 | : spec_(canonical_spec, canonical_spec_len), |
| 108 | is_valid_(is_valid), |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 109 | parsed_(parsed) { |
[email protected] | 19b61f97 | 2013-07-26 13:30:09 | [diff] [blame] | 110 | InitializeFromCanonicalSpec(); |
| 111 | } |
| 112 | |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 113 | GURL::GURL(std::string canonical_spec, const url::Parsed& parsed, bool is_valid) |
ki.stfu | cebea5e | 2016-06-04 07:05:36 | [diff] [blame] | 114 | : spec_(std::move(canonical_spec)), is_valid_(is_valid), parsed_(parsed) { |
[email protected] | 19b61f97 | 2013-07-26 13:30:09 | [diff] [blame] | 115 | InitializeFromCanonicalSpec(); |
| 116 | } |
| 117 | |
[email protected] | 369e84f7 | 2013-11-23 01:53:52 | [diff] [blame] | 118 | template<typename STR> |
brettw | dfbcc3b | 2016-01-20 01:49:17 | [diff] [blame] | 119 | void GURL::InitCanonical(base::BasicStringPiece<STR> input_spec, |
| 120 | bool trim_path_end) { |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 121 | url::StdStringCanonOutput output(&spec_); |
| 122 | is_valid_ = url::Canonicalize( |
[email protected] | 369e84f7 | 2013-11-23 01:53:52 | [diff] [blame] | 123 | input_spec.data(), static_cast<int>(input_spec.length()), trim_path_end, |
| 124 | NULL, &output, &parsed_); |
| 125 | |
| 126 | output.Complete(); // Must be done before using string. |
| 127 | if (is_valid_ && SchemeIsFileSystem()) { |
| 128 | inner_url_.reset(new GURL(spec_.data(), parsed_.Length(), |
| 129 | *parsed_.inner_parsed(), true)); |
| 130 | } |
csharrison | 475851da | 2016-12-17 02:19:42 | [diff] [blame] | 131 | // Valid URLs always have non-empty specs. |
| 132 | DCHECK(!is_valid_ || !spec_.empty()); |
[email protected] | 369e84f7 | 2013-11-23 01:53:52 | [diff] [blame] | 133 | } |
| 134 | |
[email protected] | 19b61f97 | 2013-07-26 13:30:09 | [diff] [blame] | 135 | void GURL::InitializeFromCanonicalSpec() { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 136 | if (is_valid_ && SchemeIsFileSystem()) { |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 137 | inner_url_.reset( |
| 138 | new GURL(spec_.data(), parsed_.Length(), |
| 139 | *parsed_.inner_parsed(), true)); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | #ifndef NDEBUG |
| 143 | // For testing purposes, check that the parsed canonical URL is identical to |
| 144 | // what we would have produced. Skip checking for invalid URLs have no meaning |
qyearsley | 2bc727d | 2015-08-14 20:17:15 | [diff] [blame] | 145 | // and we can't always canonicalize then reproducibly. |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 146 | if (is_valid_) { |
csharrison | 475851da | 2016-12-17 02:19:42 | [diff] [blame] | 147 | DCHECK(!spec_.empty()); |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 148 | url::Component scheme; |
[email protected] | 369e84f7 | 2013-11-23 01:53:52 | [diff] [blame] | 149 | // We can't do this check on the inner_url of a filesystem URL, as |
| 150 | // canonical_spec actually points to the start of the outer URL, so we'd |
| 151 | // end up with infinite recursion in this constructor. |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 152 | if (!url::FindAndCompareScheme(spec_.data(), spec_.length(), |
[email protected] | 08dc705 | 2014-06-18 07:57:49 | [diff] [blame] | 153 | url::kFileSystemScheme, &scheme) || |
[email protected] | 19b61f97 | 2013-07-26 13:30:09 | [diff] [blame] | 154 | scheme.begin == parsed_.scheme.begin) { |
[email protected] | 369e84f7 | 2013-11-23 01:53:52 | [diff] [blame] | 155 | // We need to retain trailing whitespace on path URLs, as the |parsed_| |
| 156 | // spec we originally received may legitimately contain trailing white- |
| 157 | // space on the path or components e.g. if the #ref has been |
| 158 | // removed from a "foo:hello #ref" URL (see http://crbug.com/291747). |
| 159 | GURL test_url(spec_, RETAIN_TRAILING_PATH_WHITEPACE); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 160 | |
| 161 | DCHECK(test_url.is_valid_ == is_valid_); |
| 162 | DCHECK(test_url.spec_ == spec_); |
| 163 | |
| 164 | DCHECK(test_url.parsed_.scheme == parsed_.scheme); |
| 165 | DCHECK(test_url.parsed_.username == parsed_.username); |
| 166 | DCHECK(test_url.parsed_.password == parsed_.password); |
| 167 | DCHECK(test_url.parsed_.host == parsed_.host); |
| 168 | DCHECK(test_url.parsed_.port == parsed_.port); |
| 169 | DCHECK(test_url.parsed_.path == parsed_.path); |
| 170 | DCHECK(test_url.parsed_.query == parsed_.query); |
| 171 | DCHECK(test_url.parsed_.ref == parsed_.ref); |
| 172 | } |
| 173 | } |
| 174 | #endif |
| 175 | } |
| 176 | |
| 177 | GURL::~GURL() { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 178 | } |
| 179 | |
sclittle | 376085b3 | 2017-03-14 21:08:41 | [diff] [blame] | 180 | GURL& GURL::operator=(const GURL& other) { |
| 181 | spec_ = other.spec_; |
| 182 | is_valid_ = other.is_valid_; |
| 183 | parsed_ = other.parsed_; |
| 184 | |
| 185 | if (!other.inner_url_) |
| 186 | inner_url_.reset(); |
| 187 | else if (inner_url_) |
| 188 | *inner_url_ = *other.inner_url_; |
| 189 | else |
| 190 | inner_url_.reset(new GURL(*other.inner_url_)); |
| 191 | |
| 192 | return *this; |
| 193 | } |
| 194 | |
| 195 | GURL& GURL::operator=(GURL&& other) { |
| 196 | spec_ = std::move(other.spec_); |
| 197 | is_valid_ = other.is_valid_; |
| 198 | parsed_ = other.parsed_; |
| 199 | inner_url_ = std::move(other.inner_url_); |
| 200 | |
| 201 | other.is_valid_ = false; |
| 202 | other.parsed_ = url::Parsed(); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 203 | return *this; |
| 204 | } |
| 205 | |
| 206 | const std::string& GURL::spec() const { |
| 207 | if (is_valid_ || spec_.empty()) |
| 208 | return spec_; |
| 209 | |
| 210 | DCHECK(false) << "Trying to get the spec of an invalid URL!"; |
| 211 | return EmptyStringForGURL(); |
| 212 | } |
| 213 | |
dcheng | 3a08877 | 2014-12-06 09:58:21 | [diff] [blame] | 214 | bool GURL::operator<(const GURL& other) const { |
| 215 | return spec_ < other.spec_; |
| 216 | } |
| 217 | |
| 218 | bool GURL::operator>(const GURL& other) const { |
| 219 | return spec_ > other.spec_; |
| 220 | } |
| 221 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 222 | // Note: code duplicated below (it's inconvenient to use a template here). |
mkwst | 45f25db | 2015-07-21 04:03:50 | [diff] [blame] | 223 | GURL GURL::Resolve(const std::string& relative) const { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 224 | // Not allowed for invalid URLs. |
| 225 | if (!is_valid_) |
| 226 | return GURL(); |
| 227 | |
| 228 | GURL result; |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 229 | url::StdStringCanonOutput output(&result.spec_); |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 230 | if (!url::ResolveRelative(spec_.data(), static_cast<int>(spec_.length()), |
| 231 | parsed_, relative.data(), |
| 232 | static_cast<int>(relative.length()), |
mkwst | 45f25db | 2015-07-21 04:03:50 | [diff] [blame] | 233 | nullptr, &output, &result.parsed_)) { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 234 | // Error resolving, return an empty URL. |
| 235 | return GURL(); |
| 236 | } |
| 237 | |
| 238 | output.Complete(); |
| 239 | result.is_valid_ = true; |
| 240 | if (result.SchemeIsFileSystem()) { |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 241 | result.inner_url_.reset( |
| 242 | new GURL(result.spec_.data(), result.parsed_.Length(), |
| 243 | *result.parsed_.inner_parsed(), true)); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 244 | } |
| 245 | return result; |
| 246 | } |
| 247 | |
| 248 | // Note: code duplicated above (it's inconvenient to use a template here). |
mkwst | 45f25db | 2015-07-21 04:03:50 | [diff] [blame] | 249 | GURL GURL::Resolve(const base::string16& relative) const { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 250 | // Not allowed for invalid URLs. |
| 251 | if (!is_valid_) |
| 252 | return GURL(); |
| 253 | |
| 254 | GURL result; |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 255 | url::StdStringCanonOutput output(&result.spec_); |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 256 | if (!url::ResolveRelative(spec_.data(), static_cast<int>(spec_.length()), |
| 257 | parsed_, relative.data(), |
| 258 | static_cast<int>(relative.length()), |
mkwst | 45f25db | 2015-07-21 04:03:50 | [diff] [blame] | 259 | nullptr, &output, &result.parsed_)) { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 260 | // Error resolving, return an empty URL. |
| 261 | return GURL(); |
| 262 | } |
| 263 | |
| 264 | output.Complete(); |
| 265 | result.is_valid_ = true; |
| 266 | if (result.SchemeIsFileSystem()) { |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 267 | result.inner_url_.reset( |
| 268 | new GURL(result.spec_.data(), result.parsed_.Length(), |
| 269 | *result.parsed_.inner_parsed(), true)); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 270 | } |
| 271 | return result; |
| 272 | } |
| 273 | |
| 274 | // Note: code duplicated below (it's inconvenient to use a template here). |
| 275 | GURL GURL::ReplaceComponents( |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 276 | const url::Replacements<char>& replacements) const { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 277 | GURL result; |
| 278 | |
| 279 | // Not allowed for invalid URLs. |
| 280 | if (!is_valid_) |
| 281 | return GURL(); |
| 282 | |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 283 | url::StdStringCanonOutput output(&result.spec_); |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 284 | result.is_valid_ = url::ReplaceComponents( |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 285 | spec_.data(), static_cast<int>(spec_.length()), parsed_, replacements, |
| 286 | NULL, &output, &result.parsed_); |
| 287 | |
| 288 | output.Complete(); |
| 289 | if (result.is_valid_ && result.SchemeIsFileSystem()) { |
mmenke | 73cea7e4a | 2016-06-13 19:04:57 | [diff] [blame] | 290 | result.inner_url_.reset(new GURL(result.spec_.data(), |
| 291 | result.parsed_.Length(), |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 292 | *result.parsed_.inner_parsed(), true)); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 293 | } |
| 294 | return result; |
| 295 | } |
| 296 | |
| 297 | // Note: code duplicated above (it's inconvenient to use a template here). |
| 298 | GURL GURL::ReplaceComponents( |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 299 | const url::Replacements<base::char16>& replacements) const { |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 300 | GURL result; |
| 301 | |
| 302 | // Not allowed for invalid URLs. |
| 303 | if (!is_valid_) |
| 304 | return GURL(); |
| 305 | |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 306 | url::StdStringCanonOutput output(&result.spec_); |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 307 | result.is_valid_ = url::ReplaceComponents( |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 308 | spec_.data(), static_cast<int>(spec_.length()), parsed_, replacements, |
| 309 | NULL, &output, &result.parsed_); |
| 310 | |
| 311 | output.Complete(); |
| 312 | if (result.is_valid_ && result.SchemeIsFileSystem()) { |
mmenke | 73cea7e4a | 2016-06-13 19:04:57 | [diff] [blame] | 313 | result.inner_url_.reset(new GURL(result.spec_.data(), |
| 314 | result.parsed_.Length(), |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 315 | *result.parsed_.inner_parsed(), true)); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 316 | } |
| 317 | return result; |
| 318 | } |
| 319 | |
| 320 | GURL GURL::GetOrigin() const { |
| 321 | // This doesn't make sense for invalid or nonstandard URLs, so return |
qyearsley | 2bc727d | 2015-08-14 20:17:15 | [diff] [blame] | 322 | // the empty URL. |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 323 | if (!is_valid_ || !IsStandard()) |
| 324 | return GURL(); |
| 325 | |
| 326 | if (SchemeIsFileSystem()) |
| 327 | return inner_url_->GetOrigin(); |
| 328 | |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 329 | url::Replacements<char> replacements; |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 330 | replacements.ClearUsername(); |
| 331 | replacements.ClearPassword(); |
| 332 | replacements.ClearPath(); |
| 333 | replacements.ClearQuery(); |
| 334 | replacements.ClearRef(); |
| 335 | |
| 336 | return ReplaceComponents(replacements); |
| 337 | } |
| 338 | |
[email protected] | 6b775ee | 2014-03-20 20:27:25 | [diff] [blame] | 339 | GURL GURL::GetAsReferrer() const { |
lizeb | 5120f6dc | 2016-02-19 09:29:44 | [diff] [blame] | 340 | if (!SchemeIsValidForReferrer()) |
jochen | 4245039 | 2014-11-24 19:47:22 | [diff] [blame] | 341 | return GURL(); |
| 342 | |
| 343 | if (!has_ref() && !has_username() && !has_password()) |
[email protected] | 6b775ee | 2014-03-20 20:27:25 | [diff] [blame] | 344 | return GURL(*this); |
| 345 | |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 346 | url::Replacements<char> replacements; |
[email protected] | 6b775ee | 2014-03-20 20:27:25 | [diff] [blame] | 347 | replacements.ClearRef(); |
| 348 | replacements.ClearUsername(); |
| 349 | replacements.ClearPassword(); |
| 350 | return ReplaceComponents(replacements); |
| 351 | } |
| 352 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 353 | GURL GURL::GetWithEmptyPath() const { |
| 354 | // This doesn't make sense for invalid or nonstandard URLs, so return |
| 355 | // the empty URL. |
| 356 | if (!is_valid_ || !IsStandard()) |
| 357 | return GURL(); |
| 358 | |
| 359 | // We could optimize this since we know that the URL is canonical, and we are |
| 360 | // appending a canonical path, so avoiding re-parsing. |
| 361 | GURL other(*this); |
| 362 | if (parsed_.path.len == 0) |
| 363 | return other; |
| 364 | |
| 365 | // Clear everything after the path. |
| 366 | other.parsed_.query.reset(); |
| 367 | other.parsed_.ref.reset(); |
| 368 | |
| 369 | // Set the path, since the path is longer than one, we can just set the |
| 370 | // first character and resize. |
| 371 | other.spec_[other.parsed_.path.begin] = '/'; |
| 372 | other.parsed_.path.len = 1; |
| 373 | other.spec_.resize(other.parsed_.path.begin + 1); |
| 374 | return other; |
| 375 | } |
| 376 | |
| 377 | bool GURL::IsStandard() const { |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 378 | return url::IsStandard(spec_.data(), parsed_.scheme); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 379 | } |
| 380 | |
clamy | 12bca18b | 2017-02-10 15:33:07 | [diff] [blame] | 381 | bool GURL::IsAboutBlank() const { |
| 382 | if (!SchemeIs(url::kAboutScheme)) |
| 383 | return false; |
| 384 | |
| 385 | if (has_host() || has_username() || has_password() || has_port()) |
| 386 | return false; |
| 387 | |
| 388 | if (path() != url::kAboutBlankPath && path() != url::kAboutBlankWithHashPath) |
| 389 | return false; |
| 390 | |
| 391 | return true; |
| 392 | } |
| 393 | |
brettw | adc84688 | 2015-09-25 01:16:22 | [diff] [blame] | 394 | bool GURL::SchemeIs(base::StringPiece lower_ascii_scheme) const { |
| 395 | DCHECK(base::IsStringASCII(lower_ascii_scheme)); |
| 396 | DCHECK(base::ToLowerASCII(lower_ascii_scheme) == lower_ascii_scheme); |
| 397 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 398 | if (parsed_.scheme.len <= 0) |
brettw | adc84688 | 2015-09-25 01:16:22 | [diff] [blame] | 399 | return lower_ascii_scheme.empty(); |
| 400 | return scheme_piece() == lower_ascii_scheme; |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 401 | } |
| 402 | |
[email protected] | 91f568903 | 2013-08-22 01:43:33 | [diff] [blame] | 403 | bool GURL::SchemeIsHTTPOrHTTPS() const { |
[email protected] | 9d5877e | 2014-06-02 07:34:35 | [diff] [blame] | 404 | return SchemeIs(url::kHttpScheme) || SchemeIs(url::kHttpsScheme); |
[email protected] | 91f568903 | 2013-08-22 01:43:33 | [diff] [blame] | 405 | } |
| 406 | |
lizeb | 5120f6dc | 2016-02-19 09:29:44 | [diff] [blame] | 407 | bool GURL::SchemeIsValidForReferrer() const { |
| 408 | return is_valid_ && IsReferrerScheme(spec_.data(), parsed_.scheme); |
| 409 | } |
| 410 | |
[email protected] | 9690b99 | 2013-11-22 07:40:46 | [diff] [blame] | 411 | bool GURL::SchemeIsWSOrWSS() const { |
[email protected] | 9d5877e | 2014-06-02 07:34:35 | [diff] [blame] | 412 | return SchemeIs(url::kWsScheme) || SchemeIs(url::kWssScheme); |
[email protected] | 9690b99 | 2013-11-22 07:40:46 | [diff] [blame] | 413 | } |
| 414 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 415 | int GURL::IntPort() const { |
| 416 | if (parsed_.port.is_nonempty()) |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 417 | return url::ParsePort(spec_.data(), parsed_.port); |
| 418 | return url::PORT_UNSPECIFIED; |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 419 | } |
| 420 | |
| 421 | int GURL::EffectiveIntPort() const { |
| 422 | int int_port = IntPort(); |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 423 | if (int_port == url::PORT_UNSPECIFIED && IsStandard()) |
| 424 | return url::DefaultPortForScheme(spec_.data() + parsed_.scheme.begin, |
| 425 | parsed_.scheme.len); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 426 | return int_port; |
| 427 | } |
| 428 | |
| 429 | std::string GURL::ExtractFileName() const { |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 430 | url::Component file_component; |
| 431 | url::ExtractFileName(spec_.data(), parsed_.path, &file_component); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 432 | return ComponentString(file_component); |
| 433 | } |
| 434 | |
| 435 | std::string GURL::PathForRequest() const { |
qyearsley | 2bc727d | 2015-08-14 20:17:15 | [diff] [blame] | 436 | DCHECK(parsed_.path.len > 0) |
| 437 | << "Canonical path for requests should be non-empty"; |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 438 | if (parsed_.ref.len >= 0) { |
qyearsley | 2bc727d | 2015-08-14 20:17:15 | [diff] [blame] | 439 | // Clip off the reference when it exists. The reference starts after the |
| 440 | // #-sign, so we have to subtract one to also remove it. |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 441 | return std::string(spec_, parsed_.path.begin, |
| 442 | parsed_.ref.begin - parsed_.path.begin - 1); |
| 443 | } |
| 444 | // Compute the actual path length, rather than depending on the spec's |
qyearsley | 2bc727d | 2015-08-14 20:17:15 | [diff] [blame] | 445 | // terminator. If we're an inner_url, our spec continues on into our outer |
| 446 | // URL's path/query/ref. |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 447 | int path_len = parsed_.path.len; |
| 448 | if (parsed_.query.is_valid()) |
| 449 | path_len = parsed_.query.end() - parsed_.path.begin; |
| 450 | |
| 451 | return std::string(spec_, parsed_.path.begin, path_len); |
| 452 | } |
| 453 | |
| 454 | std::string GURL::HostNoBrackets() const { |
| 455 | // If host looks like an IPv6 literal, strip the square brackets. |
[email protected] | 0318f92 | 2014-04-22 00:09:23 | [diff] [blame] | 456 | url::Component h(parsed_.host); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 457 | if (h.len >= 2 && spec_[h.begin] == '[' && spec_[h.end() - 1] == ']') { |
| 458 | h.begin++; |
| 459 | h.len -= 2; |
| 460 | } |
| 461 | return ComponentString(h); |
| 462 | } |
| 463 | |
[email protected] | 5f50c5d | 2013-10-24 19:05:17 | [diff] [blame] | 464 | std::string GURL::GetContent() const { |
| 465 | return is_valid_ ? ComponentString(parsed_.GetContent()) : std::string(); |
| 466 | } |
| 467 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 468 | bool GURL::HostIsIPAddress() const { |
csharrison | 475851da | 2016-12-17 02:19:42 | [diff] [blame] | 469 | return is_valid_ && url::HostIsIPAddress(host_piece()); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | #ifdef WIN32 |
| 473 | |
| 474 | const GURL& GURL::EmptyGURL() { |
| 475 | // Avoid static object construction/destruction on startup/shutdown. |
| 476 | if (!empty_gurl) { |
| 477 | // Create the string. Be careful that we don't break in the case that this |
| 478 | // is being called from multiple threads. |
| 479 | GURL* new_empty_gurl = new GURL; |
| 480 | if (InterlockedCompareExchangePointer( |
| 481 | reinterpret_cast<PVOID*>(&empty_gurl), new_empty_gurl, NULL)) { |
| 482 | // The old value was non-NULL, so no replacement was done. Another |
| 483 | // thread did the initialization out from under us. |
| 484 | delete new_empty_gurl; |
| 485 | } |
| 486 | } |
| 487 | return *empty_gurl; |
| 488 | } |
| 489 | |
| 490 | #else |
| 491 | |
| 492 | void EmptyGURLOnce(void) { |
| 493 | empty_gurl = new GURL; |
| 494 | } |
| 495 | |
| 496 | const GURL& GURL::EmptyGURL() { |
| 497 | // Avoid static object construction/destruction on startup/shutdown. |
| 498 | pthread_once(&empty_gurl_once, EmptyGURLOnce); |
| 499 | return *empty_gurl; |
| 500 | } |
| 501 | |
| 502 | #endif // WIN32 |
| 503 | |
qyearsley | 7ffaa68 | 2015-08-03 07:03:49 | [diff] [blame] | 504 | bool GURL::DomainIs(base::StringPiece lower_ascii_domain) const { |
pkalinnikov | 054f403 | 2016-08-31 10:54:17 | [diff] [blame] | 505 | if (!is_valid_) |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 506 | return false; |
| 507 | |
pkalinnikov | 054f403 | 2016-08-31 10:54:17 | [diff] [blame] | 508 | // FileSystem URLs have empty host_piece, so check this first. |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 509 | if (SchemeIsFileSystem() && inner_url_) |
qyearsley | 7ffaa68 | 2015-08-03 07:03:49 | [diff] [blame] | 510 | return inner_url_->DomainIs(lower_ascii_domain); |
pkalinnikov | 054f403 | 2016-08-31 10:54:17 | [diff] [blame] | 511 | return url::DomainIs(host_piece(), lower_ascii_domain); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 512 | } |
| 513 | |
arthursonzogni | 9c873d8c | 2017-02-08 17:58:05 | [diff] [blame] | 514 | bool GURL::EqualsIgnoringRef(const GURL& other) const { |
| 515 | int ref_position = parsed_.CountCharactersBefore(url::Parsed::REF, true); |
| 516 | int ref_position_other = |
| 517 | other.parsed_.CountCharactersBefore(url::Parsed::REF, true); |
| 518 | return base::StringPiece(spec_).substr(0, ref_position) == |
| 519 | base::StringPiece(other.spec_).substr(0, ref_position_other); |
| 520 | } |
| 521 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 522 | void GURL::Swap(GURL* other) { |
| 523 | spec_.swap(other->spec_); |
| 524 | std::swap(is_valid_, other->is_valid_); |
| 525 | std::swap(parsed_, other->parsed_); |
[email protected] | e05d81f | 2013-10-22 21:20:31 | [diff] [blame] | 526 | inner_url_.swap(other->inner_url_); |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 527 | } |
| 528 | |
dskiba | 3bc10ee8 | 2017-02-01 01:22:19 | [diff] [blame] | 529 | size_t GURL::EstimateMemoryUsage() const { |
| 530 | return base::trace_event::EstimateMemoryUsage(spec_) + |
| 531 | base::trace_event::EstimateMemoryUsage(inner_url_) + |
| 532 | (parsed_.inner_parsed() ? sizeof(url::Parsed) : 0); |
| 533 | } |
| 534 | |
[email protected] | e7bba5f8 | 2013-04-10 20:10:52 | [diff] [blame] | 535 | std::ostream& operator<<(std::ostream& out, const GURL& url) { |
| 536 | return out << url.possibly_invalid_spec(); |
| 537 | } |
csharrison | ebeca8e | 2016-10-18 02:35:36 | [diff] [blame] | 538 | |
| 539 | bool operator==(const GURL& x, const GURL& y) { |
| 540 | return x.possibly_invalid_spec() == y.possibly_invalid_spec(); |
| 541 | } |
| 542 | |
| 543 | bool operator!=(const GURL& x, const GURL& y) { |
| 544 | return !(x == y); |
| 545 | } |
| 546 | |
| 547 | bool operator==(const GURL& x, const base::StringPiece& spec) { |
cfredric | 370250a | 2016-11-15 22:38:56 | [diff] [blame] | 548 | DCHECK_EQ(GURL(spec).possibly_invalid_spec(), spec); |
csharrison | ebeca8e | 2016-10-18 02:35:36 | [diff] [blame] | 549 | return x.possibly_invalid_spec() == spec; |
| 550 | } |
| 551 | |
| 552 | bool operator!=(const GURL& x, const base::StringPiece& spec) { |
| 553 | return !(x == spec); |
| 554 | } |