|
|
@ -36,13 +36,16 @@ |
|
|
|
#include "src/core/lib/slice/b64.h" |
|
|
|
#include "src/core/lib/slice/b64.h" |
|
|
|
#include "src/core/lib/uri/uri_parser.h" |
|
|
|
#include "src/core/lib/uri/uri_parser.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Parses the 'https_proxy' env var (fallback on 'http_proxy') and returns the |
|
|
|
* Parses the 'https_proxy' env var (fallback on 'http_proxy') and returns the |
|
|
|
* proxy hostname to resolve or nullptr on error. Also sets 'user_cred' to user |
|
|
|
* proxy hostname to resolve or nullptr on error. Also sets 'user_cred' to user |
|
|
|
* credentials if present in the 'http_proxy' env var, otherwise leaves it |
|
|
|
* credentials if present in the 'http_proxy' env var, otherwise leaves it |
|
|
|
* unchanged. It is caller's responsibility to gpr_free user_cred. |
|
|
|
* unchanged. It is caller's responsibility to gpr_free user_cred. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static char* get_http_proxy_server(char** user_cred) { |
|
|
|
char* GetHttpProxyServer(char** user_cred) { |
|
|
|
GPR_ASSERT(user_cred != nullptr); |
|
|
|
GPR_ASSERT(user_cred != nullptr); |
|
|
|
char* proxy_name = nullptr; |
|
|
|
char* proxy_name = nullptr; |
|
|
|
char** authority_strs = nullptr; |
|
|
|
char** authority_strs = nullptr; |
|
|
@ -89,127 +92,115 @@ done: |
|
|
|
return proxy_name; |
|
|
|
return proxy_name; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
class HttpProxyMapper : public ProxyMapperInterface { |
|
|
|
* Checks the value of GRPC_ARG_ENABLE_HTTP_PROXY to determine if http_proxy |
|
|
|
public: |
|
|
|
* should be used. |
|
|
|
bool MapName(const char* server_uri, const grpc_channel_args* args, |
|
|
|
*/ |
|
|
|
char** name_to_resolve, grpc_channel_args** new_args) override { |
|
|
|
bool http_proxy_enabled(const grpc_channel_args* args) { |
|
|
|
if (!grpc_channel_args_find_bool(args, GRPC_ARG_ENABLE_HTTP_PROXY, true)) { |
|
|
|
const grpc_arg* arg = |
|
|
|
return false; |
|
|
|
grpc_channel_args_find(args, GRPC_ARG_ENABLE_HTTP_PROXY); |
|
|
|
} |
|
|
|
return grpc_channel_arg_get_bool(arg, true); |
|
|
|
char* user_cred = nullptr; |
|
|
|
} |
|
|
|
*name_to_resolve = GetHttpProxyServer(&user_cred); |
|
|
|
|
|
|
|
if (*name_to_resolve == nullptr) return false; |
|
|
|
static bool proxy_mapper_map_name(grpc_proxy_mapper* /*mapper*/, |
|
|
|
char* no_proxy_str = nullptr; |
|
|
|
const char* server_uri, |
|
|
|
grpc_uri* uri = grpc_uri_parse(server_uri, false /* suppress_errors */); |
|
|
|
const grpc_channel_args* args, |
|
|
|
if (uri == nullptr || uri->path[0] == '\0') { |
|
|
|
char** name_to_resolve, |
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
grpc_channel_args** new_args) { |
|
|
|
"'http_proxy' environment variable set, but cannot " |
|
|
|
if (!http_proxy_enabled(args)) { |
|
|
|
"parse server URI '%s' -- not using proxy", |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
char* user_cred = nullptr; |
|
|
|
|
|
|
|
*name_to_resolve = get_http_proxy_server(&user_cred); |
|
|
|
|
|
|
|
if (*name_to_resolve == nullptr) return false; |
|
|
|
|
|
|
|
char* no_proxy_str = nullptr; |
|
|
|
|
|
|
|
grpc_uri* uri = grpc_uri_parse(server_uri, false /* suppress_errors */); |
|
|
|
|
|
|
|
if (uri == nullptr || uri->path[0] == '\0') { |
|
|
|
|
|
|
|
gpr_log(GPR_ERROR, |
|
|
|
|
|
|
|
"'http_proxy' environment variable set, but cannot " |
|
|
|
|
|
|
|
"parse server URI '%s' -- not using proxy", |
|
|
|
|
|
|
|
server_uri); |
|
|
|
|
|
|
|
goto no_use_proxy; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (strcmp(uri->scheme, "unix") == 0) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "not using proxy for Unix domain socket '%s'", |
|
|
|
|
|
|
|
server_uri); |
|
|
|
|
|
|
|
goto no_use_proxy; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Prefer using 'no_grpc_proxy'. Fallback on 'no_proxy' if it is not set. */ |
|
|
|
|
|
|
|
no_proxy_str = gpr_getenv("no_grpc_proxy"); |
|
|
|
|
|
|
|
if (no_proxy_str == nullptr) no_proxy_str = gpr_getenv("no_proxy"); |
|
|
|
|
|
|
|
if (no_proxy_str != nullptr) { |
|
|
|
|
|
|
|
static const char* NO_PROXY_SEPARATOR = ","; |
|
|
|
|
|
|
|
bool use_proxy = true; |
|
|
|
|
|
|
|
grpc_core::UniquePtr<char> server_host; |
|
|
|
|
|
|
|
grpc_core::UniquePtr<char> server_port; |
|
|
|
|
|
|
|
if (!grpc_core::SplitHostPort( |
|
|
|
|
|
|
|
uri->path[0] == '/' ? uri->path + 1 : uri->path, &server_host, |
|
|
|
|
|
|
|
&server_port)) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
|
|
|
"unable to split host and port, not checking no_proxy list for " |
|
|
|
|
|
|
|
"host '%s'", |
|
|
|
|
|
|
|
server_uri); |
|
|
|
server_uri); |
|
|
|
gpr_free(no_proxy_str); |
|
|
|
goto no_use_proxy; |
|
|
|
} else { |
|
|
|
} |
|
|
|
size_t uri_len = strlen(server_host.get()); |
|
|
|
if (strcmp(uri->scheme, "unix") == 0) { |
|
|
|
char** no_proxy_hosts; |
|
|
|
gpr_log(GPR_INFO, "not using proxy for Unix domain socket '%s'", |
|
|
|
size_t num_no_proxy_hosts; |
|
|
|
server_uri); |
|
|
|
gpr_string_split(no_proxy_str, NO_PROXY_SEPARATOR, &no_proxy_hosts, |
|
|
|
goto no_use_proxy; |
|
|
|
&num_no_proxy_hosts); |
|
|
|
} |
|
|
|
for (size_t i = 0; i < num_no_proxy_hosts; i++) { |
|
|
|
/* Prefer using 'no_grpc_proxy'. Fallback on 'no_proxy' if it is not set. */ |
|
|
|
char* no_proxy_entry = no_proxy_hosts[i]; |
|
|
|
no_proxy_str = gpr_getenv("no_grpc_proxy"); |
|
|
|
size_t no_proxy_len = strlen(no_proxy_entry); |
|
|
|
if (no_proxy_str == nullptr) no_proxy_str = gpr_getenv("no_proxy"); |
|
|
|
if (no_proxy_len <= uri_len && |
|
|
|
if (no_proxy_str != nullptr) { |
|
|
|
gpr_stricmp(no_proxy_entry, |
|
|
|
static const char* NO_PROXY_SEPARATOR = ","; |
|
|
|
&(server_host.get()[uri_len - no_proxy_len])) == 0) { |
|
|
|
bool use_proxy = true; |
|
|
|
gpr_log(GPR_INFO, "not using proxy for host in no_proxy list '%s'", |
|
|
|
grpc_core::UniquePtr<char> server_host; |
|
|
|
server_uri); |
|
|
|
grpc_core::UniquePtr<char> server_port; |
|
|
|
use_proxy = false; |
|
|
|
if (!grpc_core::SplitHostPort( |
|
|
|
break; |
|
|
|
uri->path[0] == '/' ? uri->path + 1 : uri->path, &server_host, |
|
|
|
|
|
|
|
&server_port)) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
|
|
|
"unable to split host and port, not checking no_proxy list for " |
|
|
|
|
|
|
|
"host '%s'", |
|
|
|
|
|
|
|
server_uri); |
|
|
|
|
|
|
|
gpr_free(no_proxy_str); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
size_t uri_len = strlen(server_host.get()); |
|
|
|
|
|
|
|
char** no_proxy_hosts; |
|
|
|
|
|
|
|
size_t num_no_proxy_hosts; |
|
|
|
|
|
|
|
gpr_string_split(no_proxy_str, NO_PROXY_SEPARATOR, &no_proxy_hosts, |
|
|
|
|
|
|
|
&num_no_proxy_hosts); |
|
|
|
|
|
|
|
for (size_t i = 0; i < num_no_proxy_hosts; i++) { |
|
|
|
|
|
|
|
char* no_proxy_entry = no_proxy_hosts[i]; |
|
|
|
|
|
|
|
size_t no_proxy_len = strlen(no_proxy_entry); |
|
|
|
|
|
|
|
if (no_proxy_len <= uri_len && |
|
|
|
|
|
|
|
gpr_stricmp(no_proxy_entry, |
|
|
|
|
|
|
|
&(server_host.get()[uri_len - no_proxy_len])) == 0) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "not using proxy for host in no_proxy list '%s'", |
|
|
|
|
|
|
|
server_uri); |
|
|
|
|
|
|
|
use_proxy = false; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (size_t i = 0; i < num_no_proxy_hosts; i++) { |
|
|
|
|
|
|
|
gpr_free(no_proxy_hosts[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
gpr_free(no_proxy_hosts); |
|
|
|
|
|
|
|
gpr_free(no_proxy_str); |
|
|
|
|
|
|
|
if (!use_proxy) goto no_use_proxy; |
|
|
|
} |
|
|
|
} |
|
|
|
for (size_t i = 0; i < num_no_proxy_hosts; i++) { |
|
|
|
|
|
|
|
gpr_free(no_proxy_hosts[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
gpr_free(no_proxy_hosts); |
|
|
|
|
|
|
|
gpr_free(no_proxy_str); |
|
|
|
|
|
|
|
if (!use_proxy) goto no_use_proxy; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
grpc_arg args_to_add[2]; |
|
|
|
|
|
|
|
args_to_add[0] = grpc_channel_arg_string_create( |
|
|
|
|
|
|
|
(char*)GRPC_ARG_HTTP_CONNECT_SERVER, |
|
|
|
|
|
|
|
uri->path[0] == '/' ? uri->path + 1 : uri->path); |
|
|
|
|
|
|
|
if (user_cred != nullptr) { |
|
|
|
|
|
|
|
/* Use base64 encoding for user credentials as stated in RFC 7617 */ |
|
|
|
|
|
|
|
char* encoded_user_cred = |
|
|
|
|
|
|
|
grpc_base64_encode(user_cred, strlen(user_cred), 0, 0); |
|
|
|
|
|
|
|
char* header; |
|
|
|
|
|
|
|
gpr_asprintf(&header, "Proxy-Authorization:Basic %s", encoded_user_cred); |
|
|
|
|
|
|
|
gpr_free(encoded_user_cred); |
|
|
|
|
|
|
|
args_to_add[1] = grpc_channel_arg_string_create( |
|
|
|
|
|
|
|
(char*)GRPC_ARG_HTTP_CONNECT_HEADERS, header); |
|
|
|
|
|
|
|
*new_args = grpc_channel_args_copy_and_add(args, args_to_add, 2); |
|
|
|
|
|
|
|
gpr_free(header); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
*new_args = grpc_channel_args_copy_and_add(args, args_to_add, 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
grpc_uri_destroy(uri); |
|
|
|
|
|
|
|
gpr_free(user_cred); |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
no_use_proxy: |
|
|
|
|
|
|
|
if (uri != nullptr) grpc_uri_destroy(uri); |
|
|
|
|
|
|
|
gpr_free(*name_to_resolve); |
|
|
|
|
|
|
|
*name_to_resolve = nullptr; |
|
|
|
|
|
|
|
gpr_free(user_cred); |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
grpc_arg args_to_add[2]; |
|
|
|
|
|
|
|
args_to_add[0] = grpc_channel_arg_string_create( |
|
|
|
|
|
|
|
(char*)GRPC_ARG_HTTP_CONNECT_SERVER, |
|
|
|
|
|
|
|
uri->path[0] == '/' ? uri->path + 1 : uri->path); |
|
|
|
|
|
|
|
if (user_cred != nullptr) { |
|
|
|
|
|
|
|
/* Use base64 encoding for user credentials as stated in RFC 7617 */ |
|
|
|
|
|
|
|
char* encoded_user_cred = |
|
|
|
|
|
|
|
grpc_base64_encode(user_cred, strlen(user_cred), 0, 0); |
|
|
|
|
|
|
|
char* header; |
|
|
|
|
|
|
|
gpr_asprintf(&header, "Proxy-Authorization:Basic %s", encoded_user_cred); |
|
|
|
|
|
|
|
gpr_free(encoded_user_cred); |
|
|
|
|
|
|
|
args_to_add[1] = grpc_channel_arg_string_create( |
|
|
|
|
|
|
|
(char*)GRPC_ARG_HTTP_CONNECT_HEADERS, header); |
|
|
|
|
|
|
|
*new_args = grpc_channel_args_copy_and_add(args, args_to_add, 2); |
|
|
|
|
|
|
|
gpr_free(header); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
*new_args = grpc_channel_args_copy_and_add(args, args_to_add, 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
grpc_uri_destroy(uri); |
|
|
|
|
|
|
|
gpr_free(user_cred); |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
no_use_proxy: |
|
|
|
|
|
|
|
if (uri != nullptr) grpc_uri_destroy(uri); |
|
|
|
|
|
|
|
gpr_free(*name_to_resolve); |
|
|
|
|
|
|
|
*name_to_resolve = nullptr; |
|
|
|
|
|
|
|
gpr_free(user_cred); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool proxy_mapper_map_address(grpc_proxy_mapper* /*mapper*/, |
|
|
|
|
|
|
|
const grpc_resolved_address* /*address*/, |
|
|
|
|
|
|
|
const grpc_channel_args* /*args*/, |
|
|
|
|
|
|
|
grpc_resolved_address** /*new_address*/, |
|
|
|
|
|
|
|
grpc_channel_args** /*new_args*/) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void proxy_mapper_destroy(grpc_proxy_mapper* /*mapper*/) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const grpc_proxy_mapper_vtable proxy_mapper_vtable = { |
|
|
|
bool MapAddress(const grpc_resolved_address& address, |
|
|
|
proxy_mapper_map_name, proxy_mapper_map_address, proxy_mapper_destroy}; |
|
|
|
const grpc_channel_args* args, |
|
|
|
|
|
|
|
grpc_resolved_address** new_address, |
|
|
|
|
|
|
|
grpc_channel_args** new_args) override { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static grpc_proxy_mapper proxy_mapper = {&proxy_mapper_vtable}; |
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
void grpc_register_http_proxy_mapper() { |
|
|
|
void RegisterHttpProxyMapper() { |
|
|
|
grpc_proxy_mapper_register(true /* at_start */, &proxy_mapper); |
|
|
|
ProxyMapperRegistry::Register( |
|
|
|
|
|
|
|
true /* at_start */, |
|
|
|
|
|
|
|
std::unique_ptr<ProxyMapperInterface>(new HttpProxyMapper())); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace grpc_core
|
|
|
|