• 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 <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/gprpp/host_port.h"
22 
23 #include "absl/strings/str_format.h"
24 #include "absl/strings/string_view.h"
25 
26 #include <grpc/support/log.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   GPR_DEBUG_ASSERT(host != nullptr && host->empty());
95   GPR_DEBUG_ASSERT(port != nullptr && port->empty());
96   absl::string_view host_view;
97   absl::string_view port_view;
98   bool has_port;
99   const bool ret = DoSplitHostPort(name, &host_view, &port_view, &has_port);
100   if (ret) {
101     // We always set the host, but port is set only when DoSplitHostPort find a
102     // port in the string, to remain backward compatible with the old
103     // gpr_split_host_port API.
104     *host = std::string(host_view);
105     if (has_port) {
106       *port = std::string(port_view);
107     }
108   }
109   return ret;
110 }
111 
112 }  // namespace grpc_core
113