blob: 734aa0b8a82a5af261b0a029180ecff7594fb84c [file] [log] [blame]
[email protected]51bcc5d2013-04-24 01:41:371// 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]e7bba5f82013-04-10 20:10:524
avic0c60312015-12-21 21:03:505#include "url/gurl.h"
6
7#include <stddef.h>
[email protected]e7bba5f82013-04-10 20:10:528
9#include <algorithm>
Peter Boströmfb60ea02021-04-05 21:06:1210#include <memory>
[email protected]e7bba5f82013-04-10 20:10:5211#include <ostream>
Lukasz Anforowicz0bc073e2019-06-14 19:41:5212#include <utility>
[email protected]e7bba5f82013-04-10 20:10:5213
Hans Wennborg0e223682020-04-27 21:51:2914#include "base/check_op.h"
Victor Vasiliev6a2bb592019-08-19 23:03:1715#include "base/no_destructor.h"
qyearsley7ffaa682015-08-03 07:03:4916#include "base/strings/string_piece.h"
brettwbc17d2c82015-06-09 22:39:0817#include "base/strings/string_util.h"
dskiba3bc10ee82017-02-01 01:22:1918#include "base/trace_event/memory_usage_estimator.h"
Alexander Timine4fc8482021-02-10 15:27:4619#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
[email protected]318076b2013-04-18 21:19:4520#include "url/url_canon_stdstring.h"
21#include "url/url_util.h"
[email protected]e7bba5f82013-04-10 20:10:5222
[email protected]e05d81f2013-10-22 21:20:3123GURL::GURL() : is_valid_(false) {
[email protected]e7bba5f82013-04-10 20:10:5224}
25
26GURL::GURL(const GURL& other)
27 : spec_(other.spec_),
28 is_valid_(other.is_valid_),
[email protected]e05d81f2013-10-22 21:20:3129 parsed_(other.parsed_) {
[email protected]e7bba5f82013-04-10 20:10:5230 if (other.inner_url_)
Peter Boströmfb60ea02021-04-05 21:06:1231 inner_url_ = std::make_unique<GURL>(*other.inner_url_);
[email protected]e7bba5f82013-04-10 20:10:5232 // Valid filesystem urls should always have an inner_url_.
33 DCHECK(!is_valid_ || !SchemeIsFileSystem() || inner_url_);
34}
35
brettwf78cc272017-03-24 16:36:4236GURL::GURL(GURL&& other) noexcept
sclittle376085b32017-03-14 21:08:4137 : spec_(std::move(other.spec_)),
38 is_valid_(other.is_valid_),
39 parsed_(other.parsed_),
40 inner_url_(std::move(other.inner_url_)) {
41 other.is_valid_ = false;
42 other.parsed_ = url::Parsed();
43}
44
brettwdfbcc3b2016-01-20 01:49:1745GURL::GURL(base::StringPiece url_string) {
[email protected]369e84f72013-11-23 01:53:5246 InitCanonical(url_string, true);
[email protected]e7bba5f82013-04-10 20:10:5247}
48
brettwdfbcc3b2016-01-20 01:49:1749GURL::GURL(base::StringPiece16 url_string) {
[email protected]369e84f72013-11-23 01:53:5250 InitCanonical(url_string, true);
51}
52
53GURL::GURL(const std::string& url_string, RetainWhiteSpaceSelector) {
Peter Kasting4d49cd4b2021-05-18 15:39:4854 InitCanonical(url_string, false);
[email protected]e7bba5f82013-04-10 20:10:5255}
56
[email protected]0318f922014-04-22 00:09:2357GURL::GURL(const char* canonical_spec,
58 size_t canonical_spec_len,
59 const url::Parsed& parsed,
60 bool is_valid)
[email protected]e7bba5f82013-04-10 20:10:5261 : spec_(canonical_spec, canonical_spec_len),
62 is_valid_(is_valid),
[email protected]e05d81f2013-10-22 21:20:3163 parsed_(parsed) {
[email protected]19b61f972013-07-26 13:30:0964 InitializeFromCanonicalSpec();
65}
66
[email protected]0318f922014-04-22 00:09:2367GURL::GURL(std::string canonical_spec, const url::Parsed& parsed, bool is_valid)
ki.stfucebea5e2016-06-04 07:05:3668 : spec_(std::move(canonical_spec)), is_valid_(is_valid), parsed_(parsed) {
[email protected]19b61f972013-07-26 13:30:0969 InitializeFromCanonicalSpec();
70}
71
Peter Kasting4d49cd4b2021-05-18 15:39:4872template <typename T, typename CharT>
73void GURL::InitCanonical(T input_spec, bool trim_path_end) {
[email protected]0318f922014-04-22 00:09:2374 url::StdStringCanonOutput output(&spec_);
75 is_valid_ = url::Canonicalize(
[email protected]369e84f72013-11-23 01:53:5276 input_spec.data(), static_cast<int>(input_spec.length()), trim_path_end,
77 NULL, &output, &parsed_);
78
79 output.Complete(); // Must be done before using string.
80 if (is_valid_ && SchemeIsFileSystem()) {
Peter Boströmfb60ea02021-04-05 21:06:1281 inner_url_ = std::make_unique<GURL>(spec_.data(), parsed_.Length(),
82 *parsed_.inner_parsed(), true);
[email protected]369e84f72013-11-23 01:53:5283 }
csharrison475851da2016-12-17 02:19:4284 // Valid URLs always have non-empty specs.
85 DCHECK(!is_valid_ || !spec_.empty());
[email protected]369e84f72013-11-23 01:53:5286}
87
[email protected]19b61f972013-07-26 13:30:0988void GURL::InitializeFromCanonicalSpec() {
[email protected]e7bba5f82013-04-10 20:10:5289 if (is_valid_ && SchemeIsFileSystem()) {
Peter Boströmfb60ea02021-04-05 21:06:1290 inner_url_ = std::make_unique<GURL>(spec_.data(), parsed_.Length(),
91 *parsed_.inner_parsed(), true);
[email protected]e7bba5f82013-04-10 20:10:5292 }
93
94#ifndef NDEBUG
95 // For testing purposes, check that the parsed canonical URL is identical to
96 // what we would have produced. Skip checking for invalid URLs have no meaning
qyearsley2bc727d2015-08-14 20:17:1597 // and we can't always canonicalize then reproducibly.
[email protected]e7bba5f82013-04-10 20:10:5298 if (is_valid_) {
csharrison475851da2016-12-17 02:19:4299 DCHECK(!spec_.empty());
[email protected]0318f922014-04-22 00:09:23100 url::Component scheme;
[email protected]369e84f72013-11-23 01:53:52101 // We can't do this check on the inner_url of a filesystem URL, as
102 // canonical_spec actually points to the start of the outer URL, so we'd
103 // end up with infinite recursion in this constructor.
[email protected]0318f922014-04-22 00:09:23104 if (!url::FindAndCompareScheme(spec_.data(), spec_.length(),
[email protected]08dc7052014-06-18 07:57:49105 url::kFileSystemScheme, &scheme) ||
[email protected]19b61f972013-07-26 13:30:09106 scheme.begin == parsed_.scheme.begin) {
[email protected]369e84f72013-11-23 01:53:52107 // We need to retain trailing whitespace on path URLs, as the |parsed_|
108 // spec we originally received may legitimately contain trailing white-
109 // space on the path or components e.g. if the #ref has been
110 // removed from a "foo:hello #ref" URL (see http://crbug.com/291747).
111 GURL test_url(spec_, RETAIN_TRAILING_PATH_WHITEPACE);
[email protected]e7bba5f82013-04-10 20:10:52112
113 DCHECK(test_url.is_valid_ == is_valid_);
114 DCHECK(test_url.spec_ == spec_);
115
116 DCHECK(test_url.parsed_.scheme == parsed_.scheme);
117 DCHECK(test_url.parsed_.username == parsed_.username);
118 DCHECK(test_url.parsed_.password == parsed_.password);
119 DCHECK(test_url.parsed_.host == parsed_.host);
120 DCHECK(test_url.parsed_.port == parsed_.port);
121 DCHECK(test_url.parsed_.path == parsed_.path);
122 DCHECK(test_url.parsed_.query == parsed_.query);
123 DCHECK(test_url.parsed_.ref == parsed_.ref);
124 }
125 }
126#endif
127}
128
Chris Watkins3e06be12017-11-29 01:40:54129GURL::~GURL() = default;
[email protected]e7bba5f82013-04-10 20:10:52130
sclittle376085b32017-03-14 21:08:41131GURL& GURL::operator=(const GURL& other) {
132 spec_ = other.spec_;
133 is_valid_ = other.is_valid_;
134 parsed_ = other.parsed_;
135
136 if (!other.inner_url_)
137 inner_url_.reset();
138 else if (inner_url_)
139 *inner_url_ = *other.inner_url_;
140 else
Peter Boströmfb60ea02021-04-05 21:06:12141 inner_url_ = std::make_unique<GURL>(*other.inner_url_);
sclittle376085b32017-03-14 21:08:41142
143 return *this;
144}
145
Jüri Valdmannf841ac22018-05-18 22:36:28146GURL& GURL::operator=(GURL&& other) noexcept {
sclittle376085b32017-03-14 21:08:41147 spec_ = std::move(other.spec_);
148 is_valid_ = other.is_valid_;
149 parsed_ = other.parsed_;
150 inner_url_ = std::move(other.inner_url_);
151
152 other.is_valid_ = false;
153 other.parsed_ = url::Parsed();
[email protected]e7bba5f82013-04-10 20:10:52154 return *this;
155}
156
157const std::string& GURL::spec() const {
158 if (is_valid_ || spec_.empty())
159 return spec_;
160
161 DCHECK(false) << "Trying to get the spec of an invalid URL!";
Daniel Cheng0a9188d92018-08-04 04:48:23162 return base::EmptyString();
[email protected]e7bba5f82013-04-10 20:10:52163}
164
dcheng3a088772014-12-06 09:58:21165bool GURL::operator<(const GURL& other) const {
166 return spec_ < other.spec_;
167}
168
169bool GURL::operator>(const GURL& other) const {
170 return spec_ > other.spec_;
171}
172
[email protected]e7bba5f82013-04-10 20:10:52173// Note: code duplicated below (it's inconvenient to use a template here).
Victor Costane7732162018-08-30 18:29:40174GURL GURL::Resolve(base::StringPiece relative) const {
[email protected]e7bba5f82013-04-10 20:10:52175 // Not allowed for invalid URLs.
176 if (!is_valid_)
177 return GURL();
178
179 GURL result;
[email protected]0318f922014-04-22 00:09:23180 url::StdStringCanonOutput output(&result.spec_);
[email protected]0318f922014-04-22 00:09:23181 if (!url::ResolveRelative(spec_.data(), static_cast<int>(spec_.length()),
182 parsed_, relative.data(),
183 static_cast<int>(relative.length()),
mkwst45f25db2015-07-21 04:03:50184 nullptr, &output, &result.parsed_)) {
[email protected]e7bba5f82013-04-10 20:10:52185 // Error resolving, return an empty URL.
186 return GURL();
187 }
188
189 output.Complete();
190 result.is_valid_ = true;
191 if (result.SchemeIsFileSystem()) {
Peter Boströmfb60ea02021-04-05 21:06:12192 result.inner_url_ =
193 std::make_unique<GURL>(result.spec_.data(), result.parsed_.Length(),
194 *result.parsed_.inner_parsed(), true);
[email protected]e7bba5f82013-04-10 20:10:52195 }
196 return result;
197}
198
199// Note: code duplicated above (it's inconvenient to use a template here).
Victor Costane7732162018-08-30 18:29:40200GURL GURL::Resolve(base::StringPiece16 relative) const {
[email protected]e7bba5f82013-04-10 20:10:52201 // Not allowed for invalid URLs.
202 if (!is_valid_)
203 return GURL();
204
205 GURL result;
[email protected]0318f922014-04-22 00:09:23206 url::StdStringCanonOutput output(&result.spec_);
[email protected]0318f922014-04-22 00:09:23207 if (!url::ResolveRelative(spec_.data(), static_cast<int>(spec_.length()),
208 parsed_, relative.data(),
209 static_cast<int>(relative.length()),
mkwst45f25db2015-07-21 04:03:50210 nullptr, &output, &result.parsed_)) {
[email protected]e7bba5f82013-04-10 20:10:52211 // Error resolving, return an empty URL.
212 return GURL();
213 }
214
215 output.Complete();
216 result.is_valid_ = true;
217 if (result.SchemeIsFileSystem()) {
Peter Boströmfb60ea02021-04-05 21:06:12218 result.inner_url_ =
219 std::make_unique<GURL>(result.spec_.data(), result.parsed_.Length(),
220 *result.parsed_.inner_parsed(), true);
[email protected]e7bba5f82013-04-10 20:10:52221 }
222 return result;
223}
224
225// Note: code duplicated below (it's inconvenient to use a template here).
226GURL GURL::ReplaceComponents(
[email protected]0318f922014-04-22 00:09:23227 const url::Replacements<char>& replacements) const {
[email protected]e7bba5f82013-04-10 20:10:52228 GURL result;
229
230 // Not allowed for invalid URLs.
231 if (!is_valid_)
232 return GURL();
233
[email protected]0318f922014-04-22 00:09:23234 url::StdStringCanonOutput output(&result.spec_);
[email protected]0318f922014-04-22 00:09:23235 result.is_valid_ = url::ReplaceComponents(
[email protected]e7bba5f82013-04-10 20:10:52236 spec_.data(), static_cast<int>(spec_.length()), parsed_, replacements,
237 NULL, &output, &result.parsed_);
238
239 output.Complete();
Rakina Zata Amni9b5d9b22021-07-12 16:19:37240
241 ProcessFileOrFileSystemURLAfterReplaceComponents(result);
[email protected]e7bba5f82013-04-10 20:10:52242 return result;
243}
244
245// Note: code duplicated above (it's inconvenient to use a template here).
246GURL GURL::ReplaceComponents(
Jan Wilken Dörrie5aad5c22021-03-08 21:44:12247 const url::Replacements<char16_t>& replacements) const {
[email protected]e7bba5f82013-04-10 20:10:52248 GURL result;
249
250 // Not allowed for invalid URLs.
251 if (!is_valid_)
252 return GURL();
253
[email protected]0318f922014-04-22 00:09:23254 url::StdStringCanonOutput output(&result.spec_);
[email protected]0318f922014-04-22 00:09:23255 result.is_valid_ = url::ReplaceComponents(
[email protected]e7bba5f82013-04-10 20:10:52256 spec_.data(), static_cast<int>(spec_.length()), parsed_, replacements,
257 NULL, &output, &result.parsed_);
258
259 output.Complete();
Rakina Zata Amni9b5d9b22021-07-12 16:19:37260
261 ProcessFileOrFileSystemURLAfterReplaceComponents(result);
262
[email protected]e7bba5f82013-04-10 20:10:52263 return result;
264}
265
Rakina Zata Amni9b5d9b22021-07-12 16:19:37266void GURL::ProcessFileOrFileSystemURLAfterReplaceComponents(GURL& url) const {
267 if (!url.is_valid_)
268 return;
269 if (url.SchemeIsFileSystem()) {
270 url.inner_url_ =
271 std::make_unique<GURL>(url.spec_.data(), url.parsed_.Length(),
272 *url.parsed_.inner_parsed(), true);
273 }
274#ifdef WIN32
275 if (url.SchemeIsFile()) {
276 // On Win32, some file URLs created through ReplaceComponents used to lose
277 // its hostname after getting reparsed (e.g. when it's sent through IPC) due
278 // to special handling of file URLs with Windows-drive paths in the URL
279 // parser. To make the behavior for URLs modified through ReplaceComponents
280 // (instead of getting fully reparsed) the same, immediately reparse the
281 // URL here to trigger the special handling.
282 // See https://crbug.com/1214098.
283 url = GURL(url.spec());
284 }
285#endif
286}
287
[email protected]e7bba5f82013-04-10 20:10:52288GURL GURL::GetOrigin() const {
289 // This doesn't make sense for invalid or nonstandard URLs, so return
qyearsley2bc727d2015-08-14 20:17:15290 // the empty URL.
[email protected]e7bba5f82013-04-10 20:10:52291 if (!is_valid_ || !IsStandard())
292 return GURL();
293
294 if (SchemeIsFileSystem())
295 return inner_url_->GetOrigin();
296
[email protected]0318f922014-04-22 00:09:23297 url::Replacements<char> replacements;
[email protected]e7bba5f82013-04-10 20:10:52298 replacements.ClearUsername();
299 replacements.ClearPassword();
300 replacements.ClearPath();
301 replacements.ClearQuery();
302 replacements.ClearRef();
303
304 return ReplaceComponents(replacements);
305}
306
[email protected]6b775ee2014-03-20 20:27:25307GURL GURL::GetAsReferrer() const {
David Van Cleve5607fbe52020-06-24 19:52:16308 if (!is_valid() || !IsReferrerScheme(spec_.data(), parsed_.scheme))
jochen42450392014-11-24 19:47:22309 return GURL();
310
311 if (!has_ref() && !has_username() && !has_password())
[email protected]6b775ee2014-03-20 20:27:25312 return GURL(*this);
313
[email protected]0318f922014-04-22 00:09:23314 url::Replacements<char> replacements;
[email protected]6b775ee2014-03-20 20:27:25315 replacements.ClearRef();
316 replacements.ClearUsername();
317 replacements.ClearPassword();
318 return ReplaceComponents(replacements);
319}
320
[email protected]e7bba5f82013-04-10 20:10:52321GURL GURL::GetWithEmptyPath() const {
322 // This doesn't make sense for invalid or nonstandard URLs, so return
323 // the empty URL.
324 if (!is_valid_ || !IsStandard())
325 return GURL();
326
327 // We could optimize this since we know that the URL is canonical, and we are
328 // appending a canonical path, so avoiding re-parsing.
329 GURL other(*this);
330 if (parsed_.path.len == 0)
331 return other;
332
333 // Clear everything after the path.
334 other.parsed_.query.reset();
335 other.parsed_.ref.reset();
336
337 // Set the path, since the path is longer than one, we can just set the
338 // first character and resize.
339 other.spec_[other.parsed_.path.begin] = '/';
340 other.parsed_.path.len = 1;
341 other.spec_.resize(other.parsed_.path.begin + 1);
342 return other;
343}
344
Giovanni Ortuño Urquidi61b24eda2017-08-09 08:13:10345GURL GURL::GetWithoutFilename() const {
346 return Resolve(".");
347}
348
[email protected]e7bba5f82013-04-10 20:10:52349bool GURL::IsStandard() const {
[email protected]0318f922014-04-22 00:09:23350 return url::IsStandard(spec_.data(), parsed_.scheme);
[email protected]e7bba5f82013-04-10 20:10:52351}
352
clamy12bca18b2017-02-10 15:33:07353bool GURL::IsAboutBlank() const {
Lukasz Anforowicz0bc073e2019-06-14 19:41:52354 return IsAboutUrl(url::kAboutBlankPath);
355}
clamy12bca18b2017-02-10 15:33:07356
Lukasz Anforowicz0bc073e2019-06-14 19:41:52357bool GURL::IsAboutSrcdoc() const {
358 return IsAboutUrl(url::kAboutSrcdocPath);
clamy12bca18b2017-02-10 15:33:07359}
360
brettwadc846882015-09-25 01:16:22361bool GURL::SchemeIs(base::StringPiece lower_ascii_scheme) const {
362 DCHECK(base::IsStringASCII(lower_ascii_scheme));
363 DCHECK(base::ToLowerASCII(lower_ascii_scheme) == lower_ascii_scheme);
364
[email protected]e7bba5f82013-04-10 20:10:52365 if (parsed_.scheme.len <= 0)
brettwadc846882015-09-25 01:16:22366 return lower_ascii_scheme.empty();
367 return scheme_piece() == lower_ascii_scheme;
[email protected]e7bba5f82013-04-10 20:10:52368}
369
[email protected]91f5689032013-08-22 01:43:33370bool GURL::SchemeIsHTTPOrHTTPS() const {
[email protected]9d5877e2014-06-02 07:34:35371 return SchemeIs(url::kHttpScheme) || SchemeIs(url::kHttpsScheme);
[email protected]91f5689032013-08-22 01:43:33372}
373
[email protected]9690b992013-11-22 07:40:46374bool GURL::SchemeIsWSOrWSS() const {
[email protected]9d5877e2014-06-02 07:34:35375 return SchemeIs(url::kWsScheme) || SchemeIs(url::kWssScheme);
[email protected]9690b992013-11-22 07:40:46376}
377
Maks Orlovich44525ce2019-02-25 14:17:58378bool GURL::SchemeIsCryptographic() const {
379 if (parsed_.scheme.len <= 0)
380 return false;
381 return SchemeIsCryptographic(scheme_piece());
382}
383
384bool GURL::SchemeIsCryptographic(base::StringPiece lower_ascii_scheme) {
385 DCHECK(base::IsStringASCII(lower_ascii_scheme));
386 DCHECK(base::ToLowerASCII(lower_ascii_scheme) == lower_ascii_scheme);
387
388 return lower_ascii_scheme == url::kHttpsScheme ||
389 lower_ascii_scheme == url::kWssScheme;
390}
391
[email protected]e7bba5f82013-04-10 20:10:52392int GURL::IntPort() const {
393 if (parsed_.port.is_nonempty())
[email protected]0318f922014-04-22 00:09:23394 return url::ParsePort(spec_.data(), parsed_.port);
395 return url::PORT_UNSPECIFIED;
[email protected]e7bba5f82013-04-10 20:10:52396}
397
398int GURL::EffectiveIntPort() const {
399 int int_port = IntPort();
[email protected]0318f922014-04-22 00:09:23400 if (int_port == url::PORT_UNSPECIFIED && IsStandard())
401 return url::DefaultPortForScheme(spec_.data() + parsed_.scheme.begin,
402 parsed_.scheme.len);
[email protected]e7bba5f82013-04-10 20:10:52403 return int_port;
404}
405
406std::string GURL::ExtractFileName() const {
[email protected]0318f922014-04-22 00:09:23407 url::Component file_component;
408 url::ExtractFileName(spec_.data(), parsed_.path, &file_component);
[email protected]e7bba5f82013-04-10 20:10:52409 return ComponentString(file_component);
410}
411
David Van Cleve5f374442019-11-06 15:01:17412base::StringPiece GURL::PathForRequestPiece() const {
qyearsley2bc727d2015-08-14 20:17:15413 DCHECK(parsed_.path.len > 0)
414 << "Canonical path for requests should be non-empty";
[email protected]e7bba5f82013-04-10 20:10:52415 if (parsed_.ref.len >= 0) {
qyearsley2bc727d2015-08-14 20:17:15416 // Clip off the reference when it exists. The reference starts after the
417 // #-sign, so we have to subtract one to also remove it.
David Van Cleve5f374442019-11-06 15:01:17418 return base::StringPiece(&spec_[parsed_.path.begin],
419 parsed_.ref.begin - parsed_.path.begin - 1);
[email protected]e7bba5f82013-04-10 20:10:52420 }
421 // Compute the actual path length, rather than depending on the spec's
qyearsley2bc727d2015-08-14 20:17:15422 // terminator. If we're an inner_url, our spec continues on into our outer
423 // URL's path/query/ref.
[email protected]e7bba5f82013-04-10 20:10:52424 int path_len = parsed_.path.len;
425 if (parsed_.query.is_valid())
426 path_len = parsed_.query.end() - parsed_.path.begin;
427
David Van Cleve5f374442019-11-06 15:01:17428 return base::StringPiece(&spec_[parsed_.path.begin], path_len);
429}
430
431std::string GURL::PathForRequest() const {
Peter Kasting95e78e42021-04-29 23:37:51432 return std::string(PathForRequestPiece());
[email protected]e7bba5f82013-04-10 20:10:52433}
434
435std::string GURL::HostNoBrackets() const {
Peter Kasting95e78e42021-04-29 23:37:51436 return std::string(HostNoBracketsPiece());
ricea1c0de2f2017-07-03 08:21:43437}
438
439base::StringPiece GURL::HostNoBracketsPiece() const {
[email protected]e7bba5f82013-04-10 20:10:52440 // If host looks like an IPv6 literal, strip the square brackets.
[email protected]0318f922014-04-22 00:09:23441 url::Component h(parsed_.host);
[email protected]e7bba5f82013-04-10 20:10:52442 if (h.len >= 2 && spec_[h.begin] == '[' && spec_[h.end() - 1] == ']') {
443 h.begin++;
444 h.len -= 2;
445 }
ricea1c0de2f2017-07-03 08:21:43446 return ComponentStringPiece(h);
[email protected]e7bba5f82013-04-10 20:10:52447}
448
[email protected]5f50c5d2013-10-24 19:05:17449std::string GURL::GetContent() const {
Stephen McGruerb52ebdc2018-10-31 22:06:04450 if (!is_valid_)
451 return std::string();
452 std::string content = ComponentString(parsed_.GetContent());
453 if (!SchemeIs(url::kJavaScriptScheme) && parsed_.ref.len >= 0)
454 content.erase(content.size() - parsed_.ref.len - 1);
455 return content;
[email protected]5f50c5d2013-10-24 19:05:17456}
457
[email protected]e7bba5f82013-04-10 20:10:52458bool GURL::HostIsIPAddress() const {
csharrison475851da2016-12-17 02:19:42459 return is_valid_ && url::HostIsIPAddress(host_piece());
[email protected]e7bba5f82013-04-10 20:10:52460}
461
[email protected]e7bba5f82013-04-10 20:10:52462const GURL& GURL::EmptyGURL() {
Victor Vasiliev6a2bb592019-08-19 23:03:17463 static base::NoDestructor<GURL> empty_gurl;
464 return *empty_gurl;
[email protected]e7bba5f82013-04-10 20:10:52465}
466
Charles Harrison81dc2fb2017-08-30 23:41:12467bool GURL::DomainIs(base::StringPiece canonical_domain) const {
pkalinnikov054f4032016-08-31 10:54:17468 if (!is_valid_)
[email protected]e7bba5f82013-04-10 20:10:52469 return false;
470
pkalinnikov054f4032016-08-31 10:54:17471 // FileSystem URLs have empty host_piece, so check this first.
Charles Harrison81dc2fb2017-08-30 23:41:12472 if (inner_url_ && SchemeIsFileSystem())
473 return inner_url_->DomainIs(canonical_domain);
474 return url::DomainIs(host_piece(), canonical_domain);
[email protected]e7bba5f82013-04-10 20:10:52475}
476
arthursonzogni9c873d8c2017-02-08 17:58:05477bool GURL::EqualsIgnoringRef(const GURL& other) const {
478 int ref_position = parsed_.CountCharactersBefore(url::Parsed::REF, true);
479 int ref_position_other =
480 other.parsed_.CountCharactersBefore(url::Parsed::REF, true);
481 return base::StringPiece(spec_).substr(0, ref_position) ==
482 base::StringPiece(other.spec_).substr(0, ref_position_other);
483}
484
[email protected]e7bba5f82013-04-10 20:10:52485void GURL::Swap(GURL* other) {
486 spec_.swap(other->spec_);
487 std::swap(is_valid_, other->is_valid_);
488 std::swap(parsed_, other->parsed_);
[email protected]e05d81f2013-10-22 21:20:31489 inner_url_.swap(other->inner_url_);
[email protected]e7bba5f82013-04-10 20:10:52490}
491
dskiba3bc10ee82017-02-01 01:22:19492size_t GURL::EstimateMemoryUsage() const {
493 return base::trace_event::EstimateMemoryUsage(spec_) +
494 base::trace_event::EstimateMemoryUsage(inner_url_) +
495 (parsed_.inner_parsed() ? sizeof(url::Parsed) : 0);
496}
497
Lukasz Anforowicz0bc073e2019-06-14 19:41:52498bool GURL::IsAboutUrl(base::StringPiece allowed_path) const {
499 if (!SchemeIs(url::kAboutScheme))
500 return false;
501
502 if (has_host() || has_username() || has_password() || has_port())
503 return false;
504
Lukasz Anforowiczfb3733f2021-01-11 19:29:29505 return IsAboutPath(path_piece(), allowed_path);
506}
507
508// static
509bool GURL::IsAboutPath(base::StringPiece actual_path,
510 base::StringPiece allowed_path) {
511 if (!base::StartsWith(actual_path, allowed_path))
Lukasz Anforowicz0bc073e2019-06-14 19:41:52512 return false;
513
Lukasz Anforowiczfb3733f2021-01-11 19:29:29514 if (actual_path.size() == allowed_path.size()) {
515 DCHECK_EQ(actual_path, allowed_path);
Lukasz Anforowicz0bc073e2019-06-14 19:41:52516 return true;
517 }
518
Lukasz Anforowiczfb3733f2021-01-11 19:29:29519 if ((actual_path.size() == allowed_path.size() + 1) &&
520 actual_path.back() == '/') {
Peter Kasting95e78e42021-04-29 23:37:51521 DCHECK_EQ(actual_path, std::string(allowed_path) + '/');
Lukasz Anforowicz0bc073e2019-06-14 19:41:52522 return true;
523 }
524
525 return false;
526}
527
Alexander Timin1b6b2722021-04-21 01:34:27528void GURL::WriteIntoTrace(perfetto::TracedValue context) const {
Alexander Timine4fc8482021-02-10 15:27:46529 std::move(context).WriteString(possibly_invalid_spec());
530}
531
[email protected]e7bba5f82013-04-10 20:10:52532std::ostream& operator<<(std::ostream& out, const GURL& url) {
533 return out << url.possibly_invalid_spec();
534}
csharrisonebeca8e2016-10-18 02:35:36535
536bool operator==(const GURL& x, const GURL& y) {
537 return x.possibly_invalid_spec() == y.possibly_invalid_spec();
538}
539
540bool operator!=(const GURL& x, const GURL& y) {
541 return !(x == y);
542}
543
544bool operator==(const GURL& x, const base::StringPiece& spec) {
Charlie Harrison84e35ca2020-05-12 19:53:08545 DCHECK_EQ(GURL(spec).possibly_invalid_spec(), spec)
546 << "Comparisons of GURLs and strings must ensure as a precondition that "
547 "the string is fully canonicalized.";
csharrisonebeca8e2016-10-18 02:35:36548 return x.possibly_invalid_spec() == spec;
549}
550
Andrew Moylan892964682017-10-10 07:09:28551bool operator==(const base::StringPiece& spec, const GURL& x) {
552 return x == spec;
553}
554
csharrisonebeca8e2016-10-18 02:35:36555bool operator!=(const GURL& x, const base::StringPiece& spec) {
556 return !(x == spec);
557}
Andrew Moylan892964682017-10-10 07:09:28558
559bool operator!=(const base::StringPiece& spec, const GURL& x) {
560 return !(x == spec);
561}