| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/base/host_port_pair.h" |
| |
| #include "base/logging.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/trace_event/memory_usage_estimator.h" |
| #include "base/values.h" |
| #include "net/base/ip_endpoint.h" |
| #include "net/base/url_util.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "url/gurl.h" |
| #include "url/scheme_host_port.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| // Value dictionary keys |
| constexpr base::StringPiece kValueHostKey = "host"; |
| constexpr base::StringPiece kValuePortKey = "port"; |
| |
| } // namespace |
| |
| HostPortPair::HostPortPair() : port_(0) {} |
| HostPortPair::HostPortPair(base::StringPiece in_host, uint16_t in_port) |
| : host_(in_host), port_(in_port) {} |
| |
| // static |
| HostPortPair HostPortPair::FromURL(const GURL& url) { |
| return HostPortPair(url.HostNoBrackets(), |
| static_cast<uint16_t>(url.EffectiveIntPort())); |
| } |
| |
| // static |
| HostPortPair HostPortPair::FromSchemeHostPort( |
| const url::SchemeHostPort& scheme_host_port) { |
| DCHECK(scheme_host_port.IsValid()); |
| |
| // HostPortPair assumes hostnames do not have surrounding brackets (as is |
| // commonly used for IPv6 literals), so strip them if present. |
| base::StringPiece host = scheme_host_port.host(); |
| if (host.size() >= 2 && host.front() == '[' && host.back() == ']') { |
| host = host.substr(1, host.size() - 2); |
| } |
| |
| return HostPortPair(host, scheme_host_port.port()); |
| } |
| |
| // static |
| HostPortPair HostPortPair::FromIPEndPoint(const IPEndPoint& ipe) { |
| return HostPortPair(ipe.ToStringWithoutPort(), ipe.port()); |
| } |
| |
| // static |
| HostPortPair HostPortPair::FromString(base::StringPiece str) { |
| // Input with more than one ':' is ambiguous unless it contains an IPv6 |
| // literal (signified by starting with a '['). ParseHostAndPort() allows such |
| // input and always uses the last ':' as the host/port delimiter, but because |
| // HostPortPair often deals with IPv6 literals without brackets, disallow such |
| // input here to prevent a common error. |
| if (base::SplitStringPiece(str, ":", base::KEEP_WHITESPACE, |
| base::SPLIT_WANT_ALL) |
| .size() > 2 && |
| str.front() != '[') { |
| return HostPortPair(); |
| } |
| |
| std::string host; |
| int port; |
| if (!ParseHostAndPort(str, &host, &port)) |
| return HostPortPair(); |
| |
| // Require a valid port. |
| if (port == -1) |
| return HostPortPair(); |
| DCHECK(base::IsValueInRangeForNumericType<uint16_t>(port)); |
| |
| return HostPortPair(host, port); |
| } |
| |
| // static |
| absl::optional<HostPortPair> HostPortPair::FromValue(const base::Value& value) { |
| const base::Value::Dict* dict = value.GetIfDict(); |
| if (!dict) |
| return absl::nullopt; |
| |
| const std::string* host = dict->FindString(kValueHostKey); |
| absl::optional<int> port = dict->FindInt(kValuePortKey); |
| |
| if (host == nullptr || !port.has_value() || |
| !base::IsValueInRangeForNumericType<uint16_t>(port.value())) { |
| return absl::nullopt; |
| } |
| |
| return HostPortPair(*host, base::checked_cast<uint16_t>(port.value())); |
| } |
| |
| std::string HostPortPair::ToString() const { |
| std::string ret(HostForURL()); |
| ret += ':'; |
| ret += base::NumberToString(port_); |
| return ret; |
| } |
| |
| std::string HostPortPair::HostForURL() const { |
| // TODO(rtenneti): Add support for |host| to have '\0'. |
| if (host_.find('\0') != std::string::npos) { |
| std::string host_for_log(host_); |
| size_t nullpos; |
| while ((nullpos = host_for_log.find('\0')) != std::string::npos) { |
| host_for_log.replace(nullpos, 1, "%00"); |
| } |
| LOG(DFATAL) << "Host has a null char: " << host_for_log; |
| } |
| // Check to see if the host is an IPv6 address. If so, added brackets. |
| if (host_.find(':') != std::string::npos) { |
| DCHECK_NE(host_[0], '['); |
| return base::StringPrintf("[%s]", host_.c_str()); |
| } |
| |
| return host_; |
| } |
| |
| base::Value HostPortPair::ToValue() const { |
| base::Value::Dict dict; |
| dict.Set(kValueHostKey, host_); |
| dict.Set(kValuePortKey, port_); |
| |
| return base::Value(std::move(dict)); |
| } |
| |
| } // namespace net |