Use UintToString() to convert port numbers.
[chromium-blink-merge.git] / url / scheme_host_port.cc
blob8f90f5cdb7de34fa9cd3c208f0b4b7eca7fbd61c
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"
7 #include <string.h>
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "url/gurl.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"
18 namespace url {
20 namespace {
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()));
38 } else {
39 // Empty host, or canonicalization failed.
40 canon_host.clear();
43 return host == canon_host;
46 bool IsValidInput(const base::StringPiece& scheme,
47 const base::StringPiece& host,
48 uint16 port) {
49 SchemeType scheme_type = SCHEME_WITH_PORT;
50 bool is_standard = GetStandardSchemeType(
51 scheme.data(),
52 Component(0, base::checked_cast<int>(scheme.length())),
53 &scheme_type);
54 if (!is_standard)
55 return false;
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)
61 return false;
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)
69 return false;
71 if (!IsCanonicalHost(host))
72 return false;
74 return true;
76 case SCHEME_WITHOUT_PORT:
77 if (port != 0) {
78 // Return an invalid object if a URL with the scheme never represents
79 // the port data but the given |port| is non-zero.
80 return false;
83 if (!IsCanonicalHost(host))
84 return false;
86 return true;
88 case SCHEME_WITHOUT_AUTHORITY:
89 return false;
91 default:
92 NOTREACHED();
93 return false;
97 } // namespace
99 SchemeHostPort::SchemeHostPort() : port_(0) {
102 SchemeHostPort::SchemeHostPort(base::StringPiece scheme,
103 base::StringPiece host,
104 uint16 port)
105 : port_(0) {
106 if (!IsValidInput(scheme, host, port))
107 return;
109 scheme.CopyToString(&scheme_);
110 host.CopyToString(&host_);
111 port_ = port;
114 SchemeHostPort::SchemeHostPort(const GURL& url) : port_(0) {
115 if (!url.is_valid())
116 return;
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)
124 port = 0;
126 if (!IsValidInput(scheme, host, port))
127 return;
129 scheme_ = scheme;
130 host_ = host;
131 port_ = port;
134 SchemeHostPort::~SchemeHostPort() {
137 bool SchemeHostPort::IsInvalid() const {
138 return scheme_.empty() && host_.empty() && !port_;
141 std::string SchemeHostPort::Serialize() const {
142 std::string result;
143 if (IsInvalid())
144 return result;
146 result.append(scheme_);
147 result.append(kStandardSchemeSeparator);
148 result.append(host_);
150 if (port_ == 0)
151 return result;
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)
158 return result;
159 if (port_ != default_port) {
160 result.push_back(':');
161 result.append(base::UintToString(port_));
164 return result;
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_;
179 return false;
182 } // namespace url