• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/util/host_port.h"
20 
21 #include <grpc/support/port_platform.h>
22 #include <stddef.h>
23 
24 #include "absl/log/check.h"
25 #include "absl/strings/str_format.h"
26 #include "absl/strings/string_view.h"
27 
28 namespace grpc_core {
29 
JoinHostPort(absl::string_view host,int port)30 std::string JoinHostPort(absl::string_view host, int port) {
31   if (!host.empty() && host[0] != '[' && host.rfind(':') != host.npos) {
32     // IPv6 literals must be enclosed in brackets.
33     return absl::StrFormat("[%s]:%d", host, port);
34   }
35   // Ordinary non-bracketed host:port.
36   return absl::StrFormat("%s:%d", host, port);
37 }
38 
39 namespace {
DoSplitHostPort(absl::string_view name,absl::string_view * host,absl::string_view * port,bool * has_port)40 bool DoSplitHostPort(absl::string_view name, absl::string_view* host,
41                      absl::string_view* port, bool* has_port) {
42   *has_port = false;
43   if (!name.empty() && name[0] == '[') {
44     // Parse a bracketed host, typically an IPv6 literal.
45     const size_t rbracket = name.find(']', 1);
46     if (rbracket == absl::string_view::npos) {
47       // Unmatched [
48       return false;
49     }
50     if (rbracket == name.size() - 1) {
51       // ]<end>
52       *port = absl::string_view();
53     } else if (name[rbracket + 1] == ':') {
54       // ]:<port?>
55       *port = name.substr(rbracket + 2, name.size() - rbracket - 2);
56       *has_port = true;
57     } else {
58       // ]<invalid>
59       return false;
60     }
61     *host = name.substr(1, rbracket - 1);
62     if (host->find(':') == absl::string_view::npos) {
63       // Require all bracketed hosts to contain a colon, because a hostname or
64       // IPv4 address should never use brackets.
65       *host = absl::string_view();
66       return false;
67     }
68   } else {
69     size_t colon = name.find(':');
70     if (colon != absl::string_view::npos &&
71         name.find(':', colon + 1) == absl::string_view::npos) {
72       // Exactly 1 colon.  Split into host:port.
73       *host = name.substr(0, colon);
74       *port = name.substr(colon + 1, name.size() - colon - 1);
75       *has_port = true;
76     } else {
77       // 0 or 2+ colons.  Bare hostname or IPv6 litearal.
78       *host = name;
79       *port = absl::string_view();
80     }
81   }
82   return true;
83 }
84 }  // namespace
85 
SplitHostPort(absl::string_view name,absl::string_view * host,absl::string_view * port)86 bool SplitHostPort(absl::string_view name, absl::string_view* host,
87                    absl::string_view* port) {
88   bool unused;
89   return DoSplitHostPort(name, host, port, &unused);
90 }
91 
SplitHostPort(absl::string_view name,std::string * host,std::string * port)92 bool SplitHostPort(absl::string_view name, std::string* host,
93                    std::string* port) {
94   DCHECK(host != nullptr);
95   DCHECK(host->empty());
96   DCHECK(port != nullptr);
97   DCHECK(port->empty());
98   absl::string_view host_view;
99   absl::string_view port_view;
100   bool has_port;
101   const bool ret = DoSplitHostPort(name, &host_view, &port_view, &has_port);
102   if (ret) {
103     // We always set the host, but port is set only when DoSplitHostPort find a
104     // port in the string, to remain backward compatible with the old
105     // gpr_split_host_port API.
106     *host = std::string(host_view);
107     if (has_port) {
108       *port = std::string(port_view);
109     }
110   }
111   return ret;
112 }
113 
114 }  // namespace grpc_core
115