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/strings/string_number_conversions.h"
12 #include "url/url_canon.h"
13 #include "url/url_canon_stdstring.h"
14 #include "url/url_constants.h"
15 #include "url/url_util.h"
19 SchemeHostPort::SchemeHostPort() : port_(0) {
22 SchemeHostPort::SchemeHostPort(base::StringPiece scheme
,
23 base::StringPiece host
,
25 : scheme_(scheme
.data(), scheme
.length()),
26 host_(host
.data(), host
.length()),
28 // Try to canonicalize the host (copy/pasted from net/base. :( ).
29 const url::Component
raw_host_component(0, static_cast<int>(host
.length()));
30 std::string canon_host
;
31 url::StdStringCanonOutput
canon_host_output(&canon_host
);
32 url::CanonHostInfo host_info
;
33 url::CanonicalizeHostVerbose(host
.data(), raw_host_component
,
34 &canon_host_output
, &host_info
);
36 if (host_info
.out_host
.is_nonempty() &&
37 host_info
.family
!= url::CanonHostInfo::BROKEN
) {
38 // Success! Assert that there's no extra garbage.
39 canon_host_output
.Complete();
40 DCHECK_EQ(host_info
.out_host
.len
, static_cast<int>(canon_host
.length()));
42 // Empty host, or canonicalization failed.
46 // Return an invalid SchemeHostPort object if any of the following conditions
49 // 1. The provided scheme is non-standard, 'blob:', or 'filesystem:'.
50 // 2. The provided host is non-canonical.
51 // 3. The scheme is 'file' and the port is non-zero.
52 // 4. The scheme is not 'file', and the port is zero or the host is empty.
53 bool isUnsupportedScheme
=
54 !url::IsStandard(scheme
.data(),
55 url::Component(0, static_cast<int>(scheme
.length()))) ||
56 scheme
== kFileSystemScheme
|| scheme
== kBlobScheme
;
57 bool isNoncanonicalHost
= host
!= canon_host
;
58 bool isFileSchemeWithPort
= scheme
== kFileScheme
&& port
!= 0;
59 bool isNonFileSchemeWithoutPortOrHost
=
60 scheme
!= kFileScheme
&& (port
== 0 || host
.empty());
61 if (isUnsupportedScheme
|| isNoncanonicalHost
|| isFileSchemeWithPort
||
62 isNonFileSchemeWithoutPortOrHost
) {
69 SchemeHostPort::SchemeHostPort(const GURL
& url
) : port_(0) {
70 if (!url
.is_valid() || !url
.IsStandard())
73 // These schemes do not follow the generic URL syntax, so we treat them as
74 // invalid (scheme, host, port) tuples (even though such URLs' _Origin_ might
75 // have a (scheme, host, port) tuple, they themselves do not).
76 if (url
.SchemeIsBlob() || url
.SchemeIsFileSystem())
79 scheme_
= url
.scheme();
81 port_
= url
.EffectiveIntPort() == url::PORT_UNSPECIFIED
83 : url
.EffectiveIntPort();
86 SchemeHostPort::~SchemeHostPort() {
89 bool SchemeHostPort::IsInvalid() const {
90 return scheme_
.empty() && host_
.empty() && !port_
;
93 std::string
SchemeHostPort::Serialize() const {
98 bool is_default_port
=
99 port_
== url::DefaultPortForScheme(scheme_
.data(),
100 static_cast<int>(scheme_
.length()));
102 result
.append(scheme_
);
103 result
.append(kStandardSchemeSeparator
);
104 result
.append(host_
);
106 if (scheme_
!= kFileScheme
&& !is_default_port
) {
107 result
.push_back(':');
108 result
.append(base::IntToString(port_
));
114 bool SchemeHostPort::Equals(const SchemeHostPort
& other
) const {
115 return port_
== other
.port() && scheme_
== other
.scheme() &&
116 host_
== other
.host();
119 bool SchemeHostPort::operator<(const SchemeHostPort
& other
) const {
120 if (port_
!= other
.port_
)
121 return port_
< other
.port_
;
122 if (scheme_
!= other
.scheme_
)
123 return scheme_
< other
.scheme_
;
124 if (host_
!= other
.host_
)
125 return host_
< other
.host_
;