diff options
Diffstat (limited to 'chromium/net/third_party/quiche/src/quiche/common/platform/api/quiche_hostname_utils.cc')
-rw-r--r-- | chromium/net/third_party/quiche/src/quiche/common/platform/api/quiche_hostname_utils.cc | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/chromium/net/third_party/quiche/src/quiche/common/platform/api/quiche_hostname_utils.cc b/chromium/net/third_party/quiche/src/quiche/common/platform/api/quiche_hostname_utils.cc new file mode 100644 index 00000000000..19ac83e61cc --- /dev/null +++ b/chromium/net/third_party/quiche/src/quiche/common/platform/api/quiche_hostname_utils.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2017 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 "quiche/common/platform/api/quiche_hostname_utils.h" + +#include <string> + +#include "absl/strings/string_view.h" +#include "url/url_canon.h" +#include "url/url_canon_stdstring.h" +#include "quiche/common/platform/api/quiche_logging.h" + +namespace quiche { + +// TODO(vasilvv): the functions below are forked from Chromium's +// net/base/url_util.h; those should be moved to googleurl. +namespace { + +std::string CanonicalizeHost(absl::string_view host, + url::CanonHostInfo* host_info) { + // Try to canonicalize the host. + const url::Component raw_host_component(0, static_cast<int>(host.length())); + std::string canon_host; + url::StdStringCanonOutput canon_host_output(&canon_host); + 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(); + QUICHE_DCHECK_EQ(host_info->out_host.len, + static_cast<int>(canon_host.length())); + } else { + // Empty host, or canonicalization failed. We'll return empty. + canon_host.clear(); + } + + return canon_host; +} + +bool IsHostCharAlphanumeric(char c) { + // We can just check lowercase because uppercase characters have already been + // normalized. + return ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')); +} + +bool IsCanonicalizedHostCompliant(const std::string& host) { + if (host.empty()) { + return false; + } + + bool in_component = false; + bool most_recent_component_started_alphanumeric = false; + + for (char c : host) { + if (!in_component) { + most_recent_component_started_alphanumeric = IsHostCharAlphanumeric(c); + if (!most_recent_component_started_alphanumeric && (c != '-') && + (c != '_')) { + return false; + } + in_component = true; + } else if (c == '.') { + in_component = false; + } else if (!IsHostCharAlphanumeric(c) && (c != '-') && (c != '_')) { + return false; + } + } + + return most_recent_component_started_alphanumeric; +} + +} // namespace + +// static +bool QuicheHostnameUtils::IsValidSNI(absl::string_view sni) { + // TODO(rtenneti): Support RFC2396 hostname. + // NOTE: Microsoft does NOT enforce this spec, so if we throw away hostnames + // based on the above spec, we may be losing some hostnames that windows + // would consider valid. By far the most common hostname character NOT + // accepted by the above spec is '_'. + url::CanonHostInfo host_info; + std::string canonicalized_host = CanonicalizeHost(sni, &host_info); + return !host_info.IsIPAddress() && + IsCanonicalizedHostCompliant(canonicalized_host); +} + +// static +std::string QuicheHostnameUtils::NormalizeHostname(absl::string_view hostname) { + url::CanonHostInfo host_info; + std::string host = CanonicalizeHost(hostname, &host_info); + + // Walk backwards over the string, stopping at the first trailing dot. + size_t host_end = host.length(); + while (host_end != 0 && host[host_end - 1] == '.') { + host_end--; + } + + // Erase the trailing dots. + if (host_end != host.length()) { + host.erase(host_end, host.length() - host_end); + } + + return host; +} + +} // namespace quiche |