Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / src / core / ext / filters / client_channel / http_proxy.cc
1 /*
2  *
3  * Copyright 2016 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/ext/filters/client_channel/http_proxy.h"
22
23 #include <stdbool.h>
24 #include <string.h>
25
26 #include <grpc/support/alloc.h>
27 #include <grpc/support/log.h>
28 #include <grpc/support/string_util.h>
29
30 #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
31 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
32 #include "src/core/lib/channel/channel_args.h"
33 #include "src/core/lib/gpr/env.h"
34 #include "src/core/lib/gpr/string.h"
35 #include "src/core/lib/gprpp/host_port.h"
36 #include "src/core/lib/slice/b64.h"
37 #include "src/core/lib/uri/uri_parser.h"
38
39 /**
40  * Parses the 'https_proxy' env var (fallback on 'http_proxy') and returns the
41  * proxy hostname to resolve or nullptr on error. Also sets 'user_cred' to user
42  * credentials if present in the 'http_proxy' env var, otherwise leaves it
43  * unchanged. It is caller's responsibility to gpr_free user_cred.
44  */
45 static char* get_http_proxy_server(char** user_cred) {
46   GPR_ASSERT(user_cred != nullptr);
47   char* proxy_name = nullptr;
48   char** authority_strs = nullptr;
49   size_t authority_nstrs;
50   /* Prefer using 'grpc_proxy'. Fallback on 'http_proxy' if it is not set.
51    * Also prefer using 'https_proxy' with fallback on 'http_proxy'. The
52    * fallback behavior can be removed if there's a demand for it.
53    */
54   char* uri_str = gpr_getenv("grpc_proxy");
55   if (uri_str == nullptr) uri_str = gpr_getenv("https_proxy");
56   if (uri_str == nullptr) uri_str = gpr_getenv("http_proxy");
57   if (uri_str == nullptr) return nullptr;
58   grpc_uri* uri = grpc_uri_parse(uri_str, false /* suppress_errors */);
59   if (uri == nullptr || uri->authority == nullptr) {
60     gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var");
61     goto done;
62   }
63   if (strcmp(uri->scheme, "http") != 0) {
64     gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme);
65     goto done;
66   }
67   /* Split on '@' to separate user credentials from host */
68   gpr_string_split(uri->authority, "@", &authority_strs, &authority_nstrs);
69   GPR_ASSERT(authority_nstrs != 0); /* should have at least 1 string */
70   if (authority_nstrs == 1) {
71     /* User cred not present in authority */
72     proxy_name = authority_strs[0];
73   } else if (authority_nstrs == 2) {
74     /* User cred found */
75     *user_cred = authority_strs[0];
76     proxy_name = authority_strs[1];
77     gpr_log(GPR_DEBUG, "userinfo found in proxy URI");
78   } else {
79     /* Bad authority */
80     for (size_t i = 0; i < authority_nstrs; i++) {
81       gpr_free(authority_strs[i]);
82     }
83     proxy_name = nullptr;
84   }
85   gpr_free(authority_strs);
86 done:
87   gpr_free(uri_str);
88   grpc_uri_destroy(uri);
89   return proxy_name;
90 }
91
92 /**
93  * Checks the value of GRPC_ARG_ENABLE_HTTP_PROXY to determine if http_proxy
94  * should be used.
95  */
96 bool http_proxy_enabled(const grpc_channel_args* args) {
97   const grpc_arg* arg =
98       grpc_channel_args_find(args, GRPC_ARG_ENABLE_HTTP_PROXY);
99   return grpc_channel_arg_get_bool(arg, true);
100 }
101
102 static bool proxy_mapper_map_name(grpc_proxy_mapper* mapper,
103                                   const char* server_uri,
104                                   const grpc_channel_args* args,
105                                   char** name_to_resolve,
106                                   grpc_channel_args** new_args) {
107   if (!http_proxy_enabled(args)) {
108     return false;
109   }
110   char* user_cred = nullptr;
111   *name_to_resolve = get_http_proxy_server(&user_cred);
112   if (*name_to_resolve == nullptr) return false;
113   char* no_proxy_str = nullptr;
114   grpc_uri* uri = grpc_uri_parse(server_uri, false /* suppress_errors */);
115   if (uri == nullptr || uri->path[0] == '\0') {
116     gpr_log(GPR_ERROR,
117             "'http_proxy' environment variable set, but cannot "
118             "parse server URI '%s' -- not using proxy",
119             server_uri);
120     goto no_use_proxy;
121   }
122   if (strcmp(uri->scheme, "unix") == 0) {
123     gpr_log(GPR_INFO, "not using proxy for Unix domain socket '%s'",
124             server_uri);
125     goto no_use_proxy;
126   }
127   /* Prefer using 'no_grpc_proxy'. Fallback on 'no_proxy' if it is not set. */
128   no_proxy_str = gpr_getenv("no_grpc_proxy");
129   if (no_proxy_str == nullptr) no_proxy_str = gpr_getenv("no_proxy");
130   if (no_proxy_str != nullptr) {
131     static const char* NO_PROXY_SEPARATOR = ",";
132     bool use_proxy = true;
133     grpc_core::UniquePtr<char> server_host;
134     grpc_core::UniquePtr<char> server_port;
135     if (!grpc_core::SplitHostPort(
136             uri->path[0] == '/' ? uri->path + 1 : uri->path, &server_host,
137             &server_port)) {
138       gpr_log(GPR_INFO,
139               "unable to split host and port, not checking no_proxy list for "
140               "host '%s'",
141               server_uri);
142       gpr_free(no_proxy_str);
143     } else {
144       size_t uri_len = strlen(server_host.get());
145       char** no_proxy_hosts;
146       size_t num_no_proxy_hosts;
147       gpr_string_split(no_proxy_str, NO_PROXY_SEPARATOR, &no_proxy_hosts,
148                        &num_no_proxy_hosts);
149       for (size_t i = 0; i < num_no_proxy_hosts; i++) {
150         char* no_proxy_entry = no_proxy_hosts[i];
151         size_t no_proxy_len = strlen(no_proxy_entry);
152         if (no_proxy_len <= uri_len &&
153             gpr_stricmp(no_proxy_entry,
154                         &(server_host.get()[uri_len - no_proxy_len])) == 0) {
155           gpr_log(GPR_INFO, "not using proxy for host in no_proxy list '%s'",
156                   server_uri);
157           use_proxy = false;
158           break;
159         }
160       }
161       for (size_t i = 0; i < num_no_proxy_hosts; i++) {
162         gpr_free(no_proxy_hosts[i]);
163       }
164       gpr_free(no_proxy_hosts);
165       gpr_free(no_proxy_str);
166       if (!use_proxy) goto no_use_proxy;
167     }
168   }
169   grpc_arg args_to_add[2];
170   args_to_add[0] = grpc_channel_arg_string_create(
171       (char*)GRPC_ARG_HTTP_CONNECT_SERVER,
172       uri->path[0] == '/' ? uri->path + 1 : uri->path);
173   if (user_cred != nullptr) {
174     /* Use base64 encoding for user credentials as stated in RFC 7617 */
175     char* encoded_user_cred =
176         grpc_base64_encode(user_cred, strlen(user_cred), 0, 0);
177     char* header;
178     gpr_asprintf(&header, "Proxy-Authorization:Basic %s", encoded_user_cred);
179     gpr_free(encoded_user_cred);
180     args_to_add[1] = grpc_channel_arg_string_create(
181         (char*)GRPC_ARG_HTTP_CONNECT_HEADERS, header);
182     *new_args = grpc_channel_args_copy_and_add(args, args_to_add, 2);
183     gpr_free(header);
184   } else {
185     *new_args = grpc_channel_args_copy_and_add(args, args_to_add, 1);
186   }
187   grpc_uri_destroy(uri);
188   gpr_free(user_cred);
189   return true;
190 no_use_proxy:
191   if (uri != nullptr) grpc_uri_destroy(uri);
192   gpr_free(*name_to_resolve);
193   *name_to_resolve = nullptr;
194   gpr_free(user_cred);
195   return false;
196 }
197
198 static bool proxy_mapper_map_address(grpc_proxy_mapper* mapper,
199                                      const grpc_resolved_address* address,
200                                      const grpc_channel_args* args,
201                                      grpc_resolved_address** new_address,
202                                      grpc_channel_args** new_args) {
203   return false;
204 }
205
206 static void proxy_mapper_destroy(grpc_proxy_mapper* mapper) {}
207
208 static const grpc_proxy_mapper_vtable proxy_mapper_vtable = {
209     proxy_mapper_map_name, proxy_mapper_map_address, proxy_mapper_destroy};
210
211 static grpc_proxy_mapper proxy_mapper = {&proxy_mapper_vtable};
212
213 void grpc_register_http_proxy_mapper() {
214   grpc_proxy_mapper_register(true /* at_start */, &proxy_mapper);
215 }