| Index: scheme_host_port.cc | 
| diff --git a/scheme_host_port.cc b/scheme_host_port.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..c2fe830e377fa2edde0260265fd5a6b013fd4d35 | 
| --- /dev/null | 
| +++ b/scheme_host_port.cc | 
| @@ -0,0 +1,129 @@ | 
| +// Copyright 2015 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "url/scheme_host_port.h" | 
| + | 
| +#include <string.h> | 
| + | 
| +#include "base/logging.h" | 
| +#include "base/strings/string_number_conversions.h" | 
| +#include "url/gurl.h" | 
| +#include "url/url_canon.h" | 
| +#include "url/url_canon_stdstring.h" | 
| +#include "url/url_constants.h" | 
| +#include "url/url_util.h" | 
| + | 
| +namespace url { | 
| + | 
| +SchemeHostPort::SchemeHostPort() : port_(0) { | 
| +} | 
| + | 
| +SchemeHostPort::SchemeHostPort(base::StringPiece scheme, | 
| +                               base::StringPiece host, | 
| +                               uint16 port) | 
| +    : scheme_(scheme.data(), scheme.length()), | 
| +      host_(host.data(), host.length()), | 
| +      port_(port) { | 
| +  // Try to canonicalize the host (copy/pasted from net/base. :( ). | 
| +  const url::Component raw_host_component(0, static_cast<int>(host.length())); | 
| +  std::string canon_host; | 
| +  url::StdStringCanonOutput canon_host_output(&canon_host); | 
| +  url::CanonHostInfo host_info; | 
| +  url::CanonicalizeHostVerbose(host.data(), raw_host_component, | 
| +                               &canon_host_output, &host_info); | 
| + | 
| +  if (host_info.out_host.is_nonempty() && | 
| +      host_info.family != url::CanonHostInfo::BROKEN) { | 
| +    // Success!  Assert that there's no extra garbage. | 
| +    canon_host_output.Complete(); | 
| +    DCHECK_EQ(host_info.out_host.len, static_cast<int>(canon_host.length())); | 
| +  } else { | 
| +    // Empty host, or canonicalization failed. | 
| +    canon_host.clear(); | 
| +  } | 
| + | 
| +  // Return an invalid SchemeHostPort object if any of the following conditions | 
| +  // hold: | 
| +  // | 
| +  // 1. The provided scheme is non-standard, 'blob:', or 'filesystem:'. | 
| +  // 2. The provided host is non-canonical. | 
| +  // 3. The scheme is 'file' and the port is non-zero. | 
| +  // 4. The scheme is not 'file', and the port is zero or the host is empty. | 
| +  bool isUnsupportedScheme = | 
| +      !url::IsStandard(scheme.data(), | 
| +                       url::Component(0, static_cast<int>(scheme.length()))) || | 
| +      scheme == kFileSystemScheme || scheme == kBlobScheme; | 
| +  bool isNoncanonicalHost = host != canon_host; | 
| +  bool isFileSchemeWithPort = scheme == kFileScheme && port != 0; | 
| +  bool isNonFileSchemeWithoutPortOrHost = | 
| +      scheme != kFileScheme && (port == 0 || host.empty()); | 
| +  if (isUnsupportedScheme || isNoncanonicalHost || isFileSchemeWithPort || | 
| +      isNonFileSchemeWithoutPortOrHost) { | 
| +    scheme_.clear(); | 
| +    host_.clear(); | 
| +    port_ = 0; | 
| +  } | 
| +} | 
| + | 
| +SchemeHostPort::SchemeHostPort(const GURL& url) : port_(0) { | 
| +  if (!url.is_valid() || !url.IsStandard()) | 
| +    return; | 
| + | 
| +  // These schemes do not follow the generic URL syntax, so we treat them as | 
| +  // invalid (scheme, host, port) tuples (even though such URLs' _Origin_ might | 
| +  // have a (scheme, host, port) tuple, they themselves do not). | 
| +  if (url.SchemeIsBlob() || url.SchemeIsFileSystem()) | 
| +    return; | 
| + | 
| +  scheme_ = url.scheme(); | 
| +  host_ = url.host(); | 
| +  port_ = url.EffectiveIntPort() == url::PORT_UNSPECIFIED | 
| +              ? 0 | 
| +              : url.EffectiveIntPort(); | 
| +} | 
| + | 
| +SchemeHostPort::~SchemeHostPort() { | 
| +} | 
| + | 
| +bool SchemeHostPort::IsInvalid() const { | 
| +  return scheme_.empty() && host_.empty() && !port_; | 
| +} | 
| + | 
| +std::string SchemeHostPort::Serialize() const { | 
| +  std::string result; | 
| +  if (IsInvalid()) | 
| +    return result; | 
| + | 
| +  bool is_default_port = | 
| +      port_ == url::DefaultPortForScheme(scheme_.data(), | 
| +                                         static_cast<int>(scheme_.length())); | 
| + | 
| +  result.append(scheme_); | 
| +  result.append(kStandardSchemeSeparator); | 
| +  result.append(host_); | 
| + | 
| +  if (scheme_ != kFileScheme && !is_default_port) { | 
| +    result.push_back(':'); | 
| +    result.append(base::IntToString(port_)); | 
| +  } | 
| + | 
| +  return result; | 
| +} | 
| + | 
| +bool SchemeHostPort::Equals(const SchemeHostPort& other) const { | 
| +  return port_ == other.port() && scheme_ == other.scheme() && | 
| +         host_ == other.host(); | 
| +} | 
| + | 
| +bool SchemeHostPort::operator<(const SchemeHostPort& other) const { | 
| +  if (port_ != other.port_) | 
| +    return port_ < other.port_; | 
| +  if (scheme_ != other.scheme_) | 
| +    return scheme_ < other.scheme_; | 
| +  if (host_ != other.host_) | 
| +    return host_ < other.host_; | 
| +  return false; | 
| +} | 
| + | 
| +}  // namespace url | 
|  |