aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/ext/filters/client_channel/http_proxy.cc
diff options
context:
space:
mode:
authorGravatar Yash Tibrewal <yashkt@google.com>2017-09-21 18:56:08 -0700
committerGravatar Yash Tibrewal <yashkt@google.com>2017-10-02 16:29:41 -0700
commit83062842c3601faeddcae8f901c515e3c78f3661 (patch)
tree58536b25350a5f2b3123161ab4ca9b8ce01a43a5 /src/core/ext/filters/client_channel/http_proxy.cc
parent1c9b584a153ff592c92b6cf6baa620d8602a37cd (diff)
Changes for C to C++. Adding extern C to header files for compatibility.
Also converting to .cc
Diffstat (limited to 'src/core/ext/filters/client_channel/http_proxy.cc')
-rw-r--r--src/core/ext/filters/client_channel/http_proxy.cc195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/core/ext/filters/client_channel/http_proxy.cc b/src/core/ext/filters/client_channel/http_proxy.cc
new file mode 100644
index 0000000000..a16b44d3dc
--- /dev/null
+++ b/src/core/ext/filters/client_channel/http_proxy.cc
@@ -0,0 +1,195 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/ext/filters/client_channel/http_proxy.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/slice/b64.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+
+/**
+ * Parses the 'http_proxy' env var and returns the proxy hostname to resolve or
+ * NULL on error. Also sets 'user_cred' to user credentials if present in the
+ * 'http_proxy' env var, otherwise leaves it unchanged. It is caller's
+ * responsibility to gpr_free user_cred.
+ */
+static char* get_http_proxy_server(grpc_exec_ctx* exec_ctx, char** user_cred) {
+ GPR_ASSERT(user_cred != NULL);
+ char* proxy_name = NULL;
+ char* uri_str = gpr_getenv("http_proxy");
+ char** authority_strs = NULL;
+ size_t authority_nstrs;
+ if (uri_str == NULL) return NULL;
+ grpc_uri* uri =
+ grpc_uri_parse(exec_ctx, uri_str, false /* suppress_errors */);
+ if (uri == NULL || uri->authority == NULL) {
+ gpr_log(GPR_ERROR, "cannot parse value of 'http_proxy' env var");
+ goto done;
+ }
+ if (strcmp(uri->scheme, "http") != 0) {
+ gpr_log(GPR_ERROR, "'%s' scheme not supported in proxy URI", uri->scheme);
+ goto done;
+ }
+ /* Split on '@' to separate user credentials from host */
+ gpr_string_split(uri->authority, "@", &authority_strs, &authority_nstrs);
+ GPR_ASSERT(authority_nstrs != 0); /* should have at least 1 string */
+ if (authority_nstrs == 1) {
+ /* User cred not present in authority */
+ proxy_name = authority_strs[0];
+ } else if (authority_nstrs == 2) {
+ /* User cred found */
+ *user_cred = authority_strs[0];
+ proxy_name = authority_strs[1];
+ gpr_log(GPR_DEBUG, "userinfo found in proxy URI");
+ } else {
+ /* Bad authority */
+ for (size_t i = 0; i < authority_nstrs; i++) {
+ gpr_free(authority_strs[i]);
+ }
+ proxy_name = NULL;
+ }
+ gpr_free(authority_strs);
+done:
+ gpr_free(uri_str);
+ grpc_uri_destroy(uri);
+ return proxy_name;
+}
+
+static bool proxy_mapper_map_name(grpc_exec_ctx* exec_ctx,
+ grpc_proxy_mapper* mapper,
+ const char* server_uri,
+ const grpc_channel_args* args,
+ char** name_to_resolve,
+ grpc_channel_args** new_args) {
+ char* user_cred = NULL;
+ *name_to_resolve = get_http_proxy_server(exec_ctx, &user_cred);
+ if (*name_to_resolve == NULL) return false;
+ char* no_proxy_str = NULL;
+ grpc_uri* uri =
+ grpc_uri_parse(exec_ctx, server_uri, false /* suppress_errors */);
+ if (uri == NULL || 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;
+ }
+ no_proxy_str = gpr_getenv("no_proxy");
+ if (no_proxy_str != NULL) {
+ static const char* NO_PROXY_SEPARATOR = ",";
+ bool use_proxy = true;
+ char* server_host;
+ char* server_port;
+ if (!gpr_split_host_port(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);
+ } else {
+ size_t uri_len = strlen(server_host);
+ 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[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(server_host);
+ gpr_free(server_port);
+ 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 != NULL) {
+ /* 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 != NULL) grpc_uri_destroy(uri);
+ gpr_free(*name_to_resolve);
+ *name_to_resolve = NULL;
+ gpr_free(user_cred);
+ return false;
+}
+
+static bool proxy_mapper_map_address(grpc_exec_ctx* exec_ctx,
+ 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 = {
+ proxy_mapper_map_name, proxy_mapper_map_address, proxy_mapper_destroy};
+
+static grpc_proxy_mapper proxy_mapper = {&proxy_mapper_vtable};
+
+void grpc_register_http_proxy_mapper() {
+ grpc_proxy_mapper_register(true /* at_start */, &proxy_mapper);
+}