1 // Copyright 2015 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.
5 #include "url/scheme_host_port.h"
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/strings/string_number_conversions.h"
13 #include "url/url_canon.h"
14 #include "url/url_canon_stdstring.h"
15 #include "url/url_constants.h"
16 #include "url/url_util.h"
22 bool IsCanonicalHost(const base::StringPiece
& host
) {
23 std::string canon_host
;
25 // Try to canonicalize the host (copy/pasted from net/base. :( ).
26 const Component
raw_host_component(0,
27 base::checked_cast
<int>(host
.length()));
28 StdStringCanonOutput
canon_host_output(&canon_host
);
29 CanonHostInfo host_info
;
30 CanonicalizeHostVerbose(host
.data(), raw_host_component
,
31 &canon_host_output
, &host_info
);
33 if (host_info
.out_host
.is_nonempty() &&
34 host_info
.family
!= CanonHostInfo::BROKEN
) {
35 // Success! Assert that there's no extra garbage.
36 canon_host_output
.Complete();
37 DCHECK_EQ(host_info
.out_host
.len
, static_cast<int>(canon_host
.length()));
39 // Empty host, or canonicalization failed.
43 return host
== canon_host
;
46 bool IsValidInput(const base::StringPiece
& scheme
,
47 const base::StringPiece
& host
,
49 SchemeType scheme_type
= SCHEME_WITH_PORT
;
50 bool is_standard
= GetStandardSchemeType(
52 Component(0, base::checked_cast
<int>(scheme
.length())),
57 // These schemes do not follow the generic URL syntax, so we treat them as
58 // invalid (scheme, host, port) tuples (even though such URLs' _Origin_ might
59 // have a (scheme, host, port) tuple, they themselves do not).
60 if (scheme
== kFileSystemScheme
|| scheme
== kBlobScheme
)
63 switch (scheme_type
) {
64 case SCHEME_WITH_PORT
:
65 // A URL with |scheme| is required to have the host and port (may be
66 // omitted in a serialization if it's the same as the default value).
67 // Return an invalid instance if either of them is not given.
68 if (host
.empty() || port
== 0)
71 if (!IsCanonicalHost(host
))
76 case SCHEME_WITHOUT_PORT
:
78 // Return an invalid object if a URL with the scheme never represents
79 // the port data but the given |port| is non-zero.
83 if (!IsCanonicalHost(host
))
88 case SCHEME_WITHOUT_AUTHORITY
:
99 SchemeHostPort::SchemeHostPort() : port_(0) {
102 SchemeHostPort::SchemeHostPort(base::StringPiece scheme
,
103 base::StringPiece host
,
106 if (!IsValidInput(scheme
, host
, port
))
109 scheme
.CopyToString(&scheme_
);
110 host
.CopyToString(&host_
);
114 SchemeHostPort::SchemeHostPort(const GURL
& url
) : port_(0) {
118 const std::string
& scheme
= url
.scheme();
119 const std::string
& host
= url
.host();
121 // A valid GURL never returns PORT_INVALID.
122 int port
= url
.EffectiveIntPort();
123 if (port
== PORT_UNSPECIFIED
)
126 if (!IsValidInput(scheme
, host
, port
))
134 SchemeHostPort::~SchemeHostPort() {
137 bool SchemeHostPort::IsInvalid() const {
138 return scheme_
.empty() && host_
.empty() && !port_
;
141 std::string
SchemeHostPort::Serialize() const {
146 result
.append(scheme_
);
147 result
.append(kStandardSchemeSeparator
);
148 result
.append(host_
);
153 // Omit the port component if the port matches with the default port
154 // defined for the scheme, if any.
155 int default_port
= DefaultPortForScheme(scheme_
.data(),
156 static_cast<int>(scheme_
.length()));
157 if (default_port
== PORT_UNSPECIFIED
)
159 if (port_
!= default_port
) {
160 result
.push_back(':');
161 result
.append(base::UintToString(port_
));
167 bool SchemeHostPort::Equals(const SchemeHostPort
& other
) const {
168 return port_
== other
.port() && scheme_
== other
.scheme() &&
169 host_
== other
.host();
172 bool SchemeHostPort::operator<(const SchemeHostPort
& other
) const {
173 if (port_
!= other
.port_
)
174 return port_
< other
.port_
;
175 if (scheme_
!= other
.scheme_
)
176 return scheme_
< other
.scheme_
;
177 if (host_
!= other
.host_
)
178 return host_
< other
.host_
;