xref: /aosp_15_r20/external/cronet/url/scheme_host_port.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "url/scheme_host_port.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
8*6777b538SAndroid Build Coastguard Worker #include <string.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <ostream>
11*6777b538SAndroid Build Coastguard Worker #include <string_view>
12*6777b538SAndroid Build Coastguard Worker #include <tuple>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/containers/contains.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/memory_usage_estimator.h"
20*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
21*6777b538SAndroid Build Coastguard Worker #include "url/third_party/mozilla/url_parse.h"
22*6777b538SAndroid Build Coastguard Worker #include "url/url_canon.h"
23*6777b538SAndroid Build Coastguard Worker #include "url/url_canon_stdstring.h"
24*6777b538SAndroid Build Coastguard Worker #include "url/url_constants.h"
25*6777b538SAndroid Build Coastguard Worker #include "url/url_features.h"
26*6777b538SAndroid Build Coastguard Worker #include "url/url_util.h"
27*6777b538SAndroid Build Coastguard Worker 
28*6777b538SAndroid Build Coastguard Worker namespace url {
29*6777b538SAndroid Build Coastguard Worker 
30*6777b538SAndroid Build Coastguard Worker namespace {
31*6777b538SAndroid Build Coastguard Worker 
IsCanonicalHost(const std::string_view & host)32*6777b538SAndroid Build Coastguard Worker bool IsCanonicalHost(const std::string_view& host) {
33*6777b538SAndroid Build Coastguard Worker   std::string canon_host;
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker   // Try to canonicalize the host (copy/pasted from net/base. :( ).
36*6777b538SAndroid Build Coastguard Worker   const Component raw_host_component(0,
37*6777b538SAndroid Build Coastguard Worker                                      base::checked_cast<int>(host.length()));
38*6777b538SAndroid Build Coastguard Worker   StdStringCanonOutput canon_host_output(&canon_host);
39*6777b538SAndroid Build Coastguard Worker   CanonHostInfo host_info;
40*6777b538SAndroid Build Coastguard Worker   CanonicalizeHostVerbose(host.data(), raw_host_component,
41*6777b538SAndroid Build Coastguard Worker                           &canon_host_output, &host_info);
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker   if (host_info.out_host.is_nonempty() &&
44*6777b538SAndroid Build Coastguard Worker       host_info.family != CanonHostInfo::BROKEN) {
45*6777b538SAndroid Build Coastguard Worker     // Success!  Assert that there's no extra garbage.
46*6777b538SAndroid Build Coastguard Worker     canon_host_output.Complete();
47*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(host_info.out_host.len, static_cast<int>(canon_host.length()));
48*6777b538SAndroid Build Coastguard Worker   } else {
49*6777b538SAndroid Build Coastguard Worker     // Empty host, or canonicalization failed.
50*6777b538SAndroid Build Coastguard Worker     canon_host.clear();
51*6777b538SAndroid Build Coastguard Worker   }
52*6777b538SAndroid Build Coastguard Worker 
53*6777b538SAndroid Build Coastguard Worker   return host == canon_host;
54*6777b538SAndroid Build Coastguard Worker }
55*6777b538SAndroid Build Coastguard Worker 
56*6777b538SAndroid Build Coastguard Worker // Note: When changing IsValidInput, consider also updating
57*6777b538SAndroid Build Coastguard Worker // ShouldTreatAsOpaqueOrigin in Blink (there might be existing differences in
58*6777b538SAndroid Build Coastguard Worker // behavior between these 2 layers, but we should avoid introducing new
59*6777b538SAndroid Build Coastguard Worker // differences).
IsValidInput(const std::string_view & scheme,const std::string_view & host,uint16_t port,SchemeHostPort::ConstructPolicy policy)60*6777b538SAndroid Build Coastguard Worker bool IsValidInput(const std::string_view& scheme,
61*6777b538SAndroid Build Coastguard Worker                   const std::string_view& host,
62*6777b538SAndroid Build Coastguard Worker                   uint16_t port,
63*6777b538SAndroid Build Coastguard Worker                   SchemeHostPort::ConstructPolicy policy) {
64*6777b538SAndroid Build Coastguard Worker   // Empty schemes are never valid.
65*6777b538SAndroid Build Coastguard Worker   if (scheme.empty())
66*6777b538SAndroid Build Coastguard Worker     return false;
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker   // about:blank and other no-access schemes translate into an opaque origin.
69*6777b538SAndroid Build Coastguard Worker   // This helps consistency with ShouldTreatAsOpaqueOrigin in Blink.
70*6777b538SAndroid Build Coastguard Worker   if (base::Contains(GetNoAccessSchemes(), scheme))
71*6777b538SAndroid Build Coastguard Worker     return false;
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker   SchemeType scheme_type = SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION;
74*6777b538SAndroid Build Coastguard Worker   bool is_standard = GetStandardSchemeType(
75*6777b538SAndroid Build Coastguard Worker       scheme.data(),
76*6777b538SAndroid Build Coastguard Worker       Component(0, base::checked_cast<int>(scheme.length())),
77*6777b538SAndroid Build Coastguard Worker       &scheme_type);
78*6777b538SAndroid Build Coastguard Worker   if (!is_standard) {
79*6777b538SAndroid Build Coastguard Worker     // To be consistent with ShouldTreatAsOpaqueOrigin in Blink, local
80*6777b538SAndroid Build Coastguard Worker     // non-standard schemes are currently allowed to be tuple origins.
81*6777b538SAndroid Build Coastguard Worker     //
82*6777b538SAndroid Build Coastguard Worker     // TODO: Migrate "content:" and "externalfile:" to be standard schemes, and
83*6777b538SAndroid Build Coastguard Worker     // remove this local scheme exception.
84*6777b538SAndroid Build Coastguard Worker     if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
85*6777b538SAndroid Build Coastguard Worker       // If the flag is enabled, a host can be empty for non-special URLs.
86*6777b538SAndroid Build Coastguard Worker       // Therefore, we don't check a host nor port.
87*6777b538SAndroid Build Coastguard Worker       if (base::Contains(GetLocalSchemes(), scheme)) {
88*6777b538SAndroid Build Coastguard Worker         return true;
89*6777b538SAndroid Build Coastguard Worker       }
90*6777b538SAndroid Build Coastguard Worker     } else {
91*6777b538SAndroid Build Coastguard Worker       if (base::Contains(GetLocalSchemes(), scheme) && host.empty() &&
92*6777b538SAndroid Build Coastguard Worker           port == 0) {
93*6777b538SAndroid Build Coastguard Worker         return true;
94*6777b538SAndroid Build Coastguard Worker       }
95*6777b538SAndroid Build Coastguard Worker     }
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker     // Otherwise, allow non-standard schemes only if the Android WebView
98*6777b538SAndroid Build Coastguard Worker     // workaround is enabled.
99*6777b538SAndroid Build Coastguard Worker     return AllowNonStandardSchemesForAndroidWebView();
100*6777b538SAndroid Build Coastguard Worker   }
101*6777b538SAndroid Build Coastguard Worker 
102*6777b538SAndroid Build Coastguard Worker   switch (scheme_type) {
103*6777b538SAndroid Build Coastguard Worker     case SCHEME_WITH_HOST_AND_PORT:
104*6777b538SAndroid Build Coastguard Worker     case SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION:
105*6777b538SAndroid Build Coastguard Worker       // A URL with |scheme| is required to have the host and port, so return an
106*6777b538SAndroid Build Coastguard Worker       // invalid instance if host is not given.  Note that a valid port is
107*6777b538SAndroid Build Coastguard Worker       // always provided by SchemeHostPort(const GURL&) constructor (a missing
108*6777b538SAndroid Build Coastguard Worker       // port is replaced with a default port if needed by
109*6777b538SAndroid Build Coastguard Worker       // GURL::EffectiveIntPort()).
110*6777b538SAndroid Build Coastguard Worker       if (host.empty())
111*6777b538SAndroid Build Coastguard Worker         return false;
112*6777b538SAndroid Build Coastguard Worker 
113*6777b538SAndroid Build Coastguard Worker       // Don't do an expensive canonicalization if the host is already
114*6777b538SAndroid Build Coastguard Worker       // canonicalized.
115*6777b538SAndroid Build Coastguard Worker       DCHECK(policy == SchemeHostPort::CHECK_CANONICALIZATION ||
116*6777b538SAndroid Build Coastguard Worker              IsCanonicalHost(host));
117*6777b538SAndroid Build Coastguard Worker       if (policy == SchemeHostPort::CHECK_CANONICALIZATION &&
118*6777b538SAndroid Build Coastguard Worker           !IsCanonicalHost(host)) {
119*6777b538SAndroid Build Coastguard Worker         return false;
120*6777b538SAndroid Build Coastguard Worker       }
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker       return true;
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker     case SCHEME_WITH_HOST:
125*6777b538SAndroid Build Coastguard Worker       if (port != 0) {
126*6777b538SAndroid Build Coastguard Worker         // Return an invalid object if a URL with the scheme never represents
127*6777b538SAndroid Build Coastguard Worker         // the port data but the given |port| is non-zero.
128*6777b538SAndroid Build Coastguard Worker         return false;
129*6777b538SAndroid Build Coastguard Worker       }
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker       // Don't do an expensive canonicalization if the host is already
132*6777b538SAndroid Build Coastguard Worker       // canonicalized.
133*6777b538SAndroid Build Coastguard Worker       DCHECK(policy == SchemeHostPort::CHECK_CANONICALIZATION ||
134*6777b538SAndroid Build Coastguard Worker              IsCanonicalHost(host));
135*6777b538SAndroid Build Coastguard Worker       if (policy == SchemeHostPort::CHECK_CANONICALIZATION &&
136*6777b538SAndroid Build Coastguard Worker           !IsCanonicalHost(host)) {
137*6777b538SAndroid Build Coastguard Worker         return false;
138*6777b538SAndroid Build Coastguard Worker       }
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker       return true;
141*6777b538SAndroid Build Coastguard Worker 
142*6777b538SAndroid Build Coastguard Worker     case SCHEME_WITHOUT_AUTHORITY:
143*6777b538SAndroid Build Coastguard Worker       return false;
144*6777b538SAndroid Build Coastguard Worker 
145*6777b538SAndroid Build Coastguard Worker     default:
146*6777b538SAndroid Build Coastguard Worker       NOTREACHED();
147*6777b538SAndroid Build Coastguard Worker       return false;
148*6777b538SAndroid Build Coastguard Worker   }
149*6777b538SAndroid Build Coastguard Worker }
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker }  // namespace
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker SchemeHostPort::SchemeHostPort() = default;
154*6777b538SAndroid Build Coastguard Worker 
SchemeHostPort(std::string scheme,std::string host,uint16_t port,ConstructPolicy policy)155*6777b538SAndroid Build Coastguard Worker SchemeHostPort::SchemeHostPort(std::string scheme,
156*6777b538SAndroid Build Coastguard Worker                                std::string host,
157*6777b538SAndroid Build Coastguard Worker                                uint16_t port,
158*6777b538SAndroid Build Coastguard Worker                                ConstructPolicy policy) {
159*6777b538SAndroid Build Coastguard Worker   if (ShouldDiscardHostAndPort(scheme)) {
160*6777b538SAndroid Build Coastguard Worker     host = "";
161*6777b538SAndroid Build Coastguard Worker     port = 0;
162*6777b538SAndroid Build Coastguard Worker   }
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   if (!IsValidInput(scheme, host, port, policy)) {
165*6777b538SAndroid Build Coastguard Worker     DCHECK(!IsValid());
166*6777b538SAndroid Build Coastguard Worker     return;
167*6777b538SAndroid Build Coastguard Worker   }
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker   scheme_ = std::move(scheme);
170*6777b538SAndroid Build Coastguard Worker   host_ = std::move(host);
171*6777b538SAndroid Build Coastguard Worker   port_ = port;
172*6777b538SAndroid Build Coastguard Worker   DCHECK(IsValid()) << "Scheme: " << scheme_ << " Host: " << host_
173*6777b538SAndroid Build Coastguard Worker                     << " Port: " << port;
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker 
SchemeHostPort(std::string_view scheme,std::string_view host,uint16_t port)176*6777b538SAndroid Build Coastguard Worker SchemeHostPort::SchemeHostPort(std::string_view scheme,
177*6777b538SAndroid Build Coastguard Worker                                std::string_view host,
178*6777b538SAndroid Build Coastguard Worker                                uint16_t port)
179*6777b538SAndroid Build Coastguard Worker     : SchemeHostPort(std::string(scheme),
180*6777b538SAndroid Build Coastguard Worker                      std::string(host),
181*6777b538SAndroid Build Coastguard Worker                      port,
182*6777b538SAndroid Build Coastguard Worker                      ConstructPolicy::CHECK_CANONICALIZATION) {}
183*6777b538SAndroid Build Coastguard Worker 
SchemeHostPort(const GURL & url)184*6777b538SAndroid Build Coastguard Worker SchemeHostPort::SchemeHostPort(const GURL& url) {
185*6777b538SAndroid Build Coastguard Worker   if (!url.is_valid())
186*6777b538SAndroid Build Coastguard Worker     return;
187*6777b538SAndroid Build Coastguard Worker 
188*6777b538SAndroid Build Coastguard Worker   std::string_view scheme = url.scheme_piece();
189*6777b538SAndroid Build Coastguard Worker   std::string_view host = url.host_piece();
190*6777b538SAndroid Build Coastguard Worker 
191*6777b538SAndroid Build Coastguard Worker   // A valid GURL never returns PORT_INVALID.
192*6777b538SAndroid Build Coastguard Worker   int port = url.EffectiveIntPort();
193*6777b538SAndroid Build Coastguard Worker   if (port == PORT_UNSPECIFIED) {
194*6777b538SAndroid Build Coastguard Worker     port = 0;
195*6777b538SAndroid Build Coastguard Worker   } else {
196*6777b538SAndroid Build Coastguard Worker     DCHECK_GE(port, 0);
197*6777b538SAndroid Build Coastguard Worker     DCHECK_LE(port, 65535);
198*6777b538SAndroid Build Coastguard Worker   }
199*6777b538SAndroid Build Coastguard Worker 
200*6777b538SAndroid Build Coastguard Worker   if (ShouldDiscardHostAndPort(scheme)) {
201*6777b538SAndroid Build Coastguard Worker     host = "";
202*6777b538SAndroid Build Coastguard Worker     port = 0;
203*6777b538SAndroid Build Coastguard Worker   }
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker   if (!IsValidInput(scheme, host, port, ALREADY_CANONICALIZED))
206*6777b538SAndroid Build Coastguard Worker     return;
207*6777b538SAndroid Build Coastguard Worker 
208*6777b538SAndroid Build Coastguard Worker   scheme_ = std::string(scheme);
209*6777b538SAndroid Build Coastguard Worker   host_ = std::string(host);
210*6777b538SAndroid Build Coastguard Worker   port_ = port;
211*6777b538SAndroid Build Coastguard Worker }
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker SchemeHostPort::~SchemeHostPort() = default;
214*6777b538SAndroid Build Coastguard Worker 
IsValid() const215*6777b538SAndroid Build Coastguard Worker bool SchemeHostPort::IsValid() const {
216*6777b538SAndroid Build Coastguard Worker   // It suffices to just check |scheme_| for emptiness; the other fields are
217*6777b538SAndroid Build Coastguard Worker   // never present without it.
218*6777b538SAndroid Build Coastguard Worker   DCHECK(!scheme_.empty() || host_.empty());
219*6777b538SAndroid Build Coastguard Worker   DCHECK(!scheme_.empty() || port_ == 0);
220*6777b538SAndroid Build Coastguard Worker   return !scheme_.empty();
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker 
Serialize() const223*6777b538SAndroid Build Coastguard Worker std::string SchemeHostPort::Serialize() const {
224*6777b538SAndroid Build Coastguard Worker   // Null checking for |parsed| in SerializeInternal is probably slower than
225*6777b538SAndroid Build Coastguard Worker   // just filling it in and discarding it here.
226*6777b538SAndroid Build Coastguard Worker   url::Parsed parsed;
227*6777b538SAndroid Build Coastguard Worker   return SerializeInternal(&parsed);
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker 
GetURL() const230*6777b538SAndroid Build Coastguard Worker GURL SchemeHostPort::GetURL() const {
231*6777b538SAndroid Build Coastguard Worker   url::Parsed parsed;
232*6777b538SAndroid Build Coastguard Worker   std::string serialized = SerializeInternal(&parsed);
233*6777b538SAndroid Build Coastguard Worker 
234*6777b538SAndroid Build Coastguard Worker   if (!IsValid())
235*6777b538SAndroid Build Coastguard Worker     return GURL(std::move(serialized), parsed, false);
236*6777b538SAndroid Build Coastguard Worker 
237*6777b538SAndroid Build Coastguard Worker   // SchemeHostPort does not have enough information to determine if an empty
238*6777b538SAndroid Build Coastguard Worker   // host is valid or not for the given scheme. Force re-parsing.
239*6777b538SAndroid Build Coastguard Worker   DCHECK(!scheme_.empty());
240*6777b538SAndroid Build Coastguard Worker   if (host_.empty())
241*6777b538SAndroid Build Coastguard Worker     return GURL(serialized);
242*6777b538SAndroid Build Coastguard Worker 
243*6777b538SAndroid Build Coastguard Worker   // If the serialized string is passed to GURL for parsing, it will append an
244*6777b538SAndroid Build Coastguard Worker   // empty path "/" for standard URLs. Add that here. Note: per RFC 6454 we
245*6777b538SAndroid Build Coastguard Worker   // cannot do this for normal Origin serialization.
246*6777b538SAndroid Build Coastguard Worker   DCHECK(!parsed.path.is_valid());
247*6777b538SAndroid Build Coastguard Worker   if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
248*6777b538SAndroid Build Coastguard Worker     // Append "/" only if the URL is standard. If the flag is enabled,
249*6777b538SAndroid Build Coastguard Worker     // non-special URLs can have an empty path and GURL doesn't append "/" to
250*6777b538SAndroid Build Coastguard Worker     // that.
251*6777b538SAndroid Build Coastguard Worker     if (IsStandardScheme(scheme_)) {
252*6777b538SAndroid Build Coastguard Worker       parsed.path = Component(serialized.length(), 1);
253*6777b538SAndroid Build Coastguard Worker       serialized.append("/");
254*6777b538SAndroid Build Coastguard Worker     }
255*6777b538SAndroid Build Coastguard Worker   } else {
256*6777b538SAndroid Build Coastguard Worker     parsed.path = Component(serialized.length(), 1);
257*6777b538SAndroid Build Coastguard Worker     serialized.append("/");
258*6777b538SAndroid Build Coastguard Worker   }
259*6777b538SAndroid Build Coastguard Worker   return GURL(std::move(serialized), parsed, true);
260*6777b538SAndroid Build Coastguard Worker }
261*6777b538SAndroid Build Coastguard Worker 
EstimateMemoryUsage() const262*6777b538SAndroid Build Coastguard Worker size_t SchemeHostPort::EstimateMemoryUsage() const {
263*6777b538SAndroid Build Coastguard Worker   return base::trace_event::EstimateMemoryUsage(scheme_) +
264*6777b538SAndroid Build Coastguard Worker          base::trace_event::EstimateMemoryUsage(host_);
265*6777b538SAndroid Build Coastguard Worker }
266*6777b538SAndroid Build Coastguard Worker 
operator <(const SchemeHostPort & other) const267*6777b538SAndroid Build Coastguard Worker bool SchemeHostPort::operator<(const SchemeHostPort& other) const {
268*6777b538SAndroid Build Coastguard Worker   return std::tie(port_, scheme_, host_) <
269*6777b538SAndroid Build Coastguard Worker          std::tie(other.port_, other.scheme_, other.host_);
270*6777b538SAndroid Build Coastguard Worker }
271*6777b538SAndroid Build Coastguard Worker 
SerializeInternal(url::Parsed * parsed) const272*6777b538SAndroid Build Coastguard Worker std::string SchemeHostPort::SerializeInternal(url::Parsed* parsed) const {
273*6777b538SAndroid Build Coastguard Worker   std::string result;
274*6777b538SAndroid Build Coastguard Worker   if (!IsValid())
275*6777b538SAndroid Build Coastguard Worker     return result;
276*6777b538SAndroid Build Coastguard Worker 
277*6777b538SAndroid Build Coastguard Worker   // Reserve enough space for the "normal" case of scheme://host/.
278*6777b538SAndroid Build Coastguard Worker   result.reserve(scheme_.size() + host_.size() + 4);
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker   if (!scheme_.empty()) {
281*6777b538SAndroid Build Coastguard Worker     parsed->scheme = Component(0, scheme_.length());
282*6777b538SAndroid Build Coastguard Worker     result.append(scheme_);
283*6777b538SAndroid Build Coastguard Worker   }
284*6777b538SAndroid Build Coastguard Worker 
285*6777b538SAndroid Build Coastguard Worker   result.append(kStandardSchemeSeparator);
286*6777b538SAndroid Build Coastguard Worker 
287*6777b538SAndroid Build Coastguard Worker   if (!host_.empty()) {
288*6777b538SAndroid Build Coastguard Worker     parsed->host = Component(result.length(), host_.length());
289*6777b538SAndroid Build Coastguard Worker     result.append(host_);
290*6777b538SAndroid Build Coastguard Worker   }
291*6777b538SAndroid Build Coastguard Worker 
292*6777b538SAndroid Build Coastguard Worker   // Omit the port component if the port matches with the default port
293*6777b538SAndroid Build Coastguard Worker   // defined for the scheme, if any.
294*6777b538SAndroid Build Coastguard Worker   int default_port = DefaultPortForScheme(scheme_.data(),
295*6777b538SAndroid Build Coastguard Worker                                           static_cast<int>(scheme_.length()));
296*6777b538SAndroid Build Coastguard Worker   if (default_port == PORT_UNSPECIFIED)
297*6777b538SAndroid Build Coastguard Worker     return result;
298*6777b538SAndroid Build Coastguard Worker   if (port_ != default_port) {
299*6777b538SAndroid Build Coastguard Worker     result.push_back(':');
300*6777b538SAndroid Build Coastguard Worker     std::string port(base::NumberToString(port_));
301*6777b538SAndroid Build Coastguard Worker     parsed->port = Component(result.length(), port.length());
302*6777b538SAndroid Build Coastguard Worker     result.append(std::move(port));
303*6777b538SAndroid Build Coastguard Worker   }
304*6777b538SAndroid Build Coastguard Worker 
305*6777b538SAndroid Build Coastguard Worker   return result;
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker 
ShouldDiscardHostAndPort(const std::string_view scheme)308*6777b538SAndroid Build Coastguard Worker bool SchemeHostPort::ShouldDiscardHostAndPort(const std::string_view scheme) {
309*6777b538SAndroid Build Coastguard Worker   return IsAndroidWebViewHackEnabledScheme(scheme) &&
310*6777b538SAndroid Build Coastguard Worker          IsUsingStandardCompliantNonSpecialSchemeURLParsing();
311*6777b538SAndroid Build Coastguard Worker }
312*6777b538SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const SchemeHostPort & scheme_host_port)313*6777b538SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out,
314*6777b538SAndroid Build Coastguard Worker                          const SchemeHostPort& scheme_host_port) {
315*6777b538SAndroid Build Coastguard Worker   return out << scheme_host_port.Serialize();
316*6777b538SAndroid Build Coastguard Worker }
317*6777b538SAndroid Build Coastguard Worker 
318*6777b538SAndroid Build Coastguard Worker }  // namespace url
319