aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/ext/filters/workarounds
diff options
context:
space:
mode:
authorGravatar Muxi Yan <mxyan@google.com>2017-04-27 11:14:18 -0700
committerGravatar Muxi Yan <mxyan@google.com>2017-04-27 11:14:18 -0700
commitf63afec89d2dcd7afc0c082618286358241549fd (patch)
treece67d4e4d8c56cc64a2b2d3bdf1f1ef82b45b495 /src/core/ext/filters/workarounds
parentb53fd4df37617364e6de2d9f880c03f3a9907450 (diff)
user-agent string filtering
Diffstat (limited to 'src/core/ext/filters/workarounds')
-rw-r--r--src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c88
-rw-r--r--src/core/ext/filters/workarounds/workaround_utils.c57
-rw-r--r--src/core/ext/filters/workarounds/workaround_utils.h54
3 files changed, 186 insertions, 13 deletions
diff --git a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
index f78cfa2f55..6d00900ccc 100644
--- a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
+++ b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
@@ -31,22 +31,15 @@
#include "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h"
+#include <stdio.h>
#include <string.h>
-#include "src/core/lib/surface/channel_init.h"
-#include "src/core/lib/channel/channel_stack_builder.h"
-/*
-#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/support/string.h"
-#include "src/core/lib/transport/service_config.h"
-*/
-
-#define GRPC_WORKAROUND_PRIORITY_HIGH 9999
+#include "src/core/ext/filters/workarounds/workaround_utils.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/transport/metadata.h"
typedef struct call_data {
// Receive closures are chained: we inject this closure as the
@@ -57,18 +50,46 @@ typedef struct call_data {
grpc_metadata_batch *recv_initial_metadata;
// Original recv_initial_metadata_ready callback, invoked after our own.
grpc_closure* next_recv_initial_metadata_ready;
+
+ // Marks whether the workaround is active
+ bool workaround_active;
} call_data;
typedef struct channel_data {
} channel_data;
+// Find the user agent metadata element in the batch
+static bool get_user_agent_mdelem(const grpc_metadata_batch *batch,
+ grpc_mdelem *md) {
+ grpc_linked_mdelem *t = batch->list.head;
+ while (t != NULL) {
+ *md = t->md;
+ if (grpc_slice_eq(GRPC_MDKEY(*md), GRPC_MDSTR_USER_AGENT)) {
+ return true;
+ }
+ t = t->next;
+ }
+
+ return false;
+}
+
// Callback invoked when we receive an initial metadata.
static void recv_initial_metadata_ready(grpc_exec_ctx* exec_ctx, void* user_data,
grpc_error* error) {
grpc_call_element* elem = user_data;
call_data* calld = elem->call_data;
-
+ if (GRPC_ERROR_NONE == error) {
+ grpc_mdelem md;
+ if (get_user_agent_mdelem(calld->recv_initial_metadata, &md)) {
+ grpc_user_agent_md *user_agent_md = grpc_parse_user_agent(md);
+ if (user_agent_md->workaround_active[GRPC_WORKAROUND_ID_CRONET_COMPRESSION]) {
+ calld->workaround_active = true;
+ }
+ // Remove with caching
+ gpr_free(user_agent_md);
+ }
+ }
// Invoke the next callback.
grpc_closure_run(exec_ctx, calld->next_recv_initial_metadata_ready, GRPC_ERROR_REF(error));
@@ -98,6 +119,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
const grpc_call_element_args* args) {
call_data* calld = elem->call_data;
calld->next_recv_initial_metadata_ready = NULL;
+ calld->workaround_active = false;
grpc_closure_init(&calld->recv_initial_metadata_ready, recv_initial_metadata_ready, elem,
grpc_schedule_on_exec_ctx);
return GRPC_ERROR_NONE;
@@ -119,6 +141,44 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_element* elem) {}
+// Parse the user agent
+static bool parse_user_agent(grpc_mdelem md) {
+ const char grpc_objc_specifier[] = "grpc-objc/";
+ const size_t grpc_objc_specifier_len = sizeof(grpc_objc_specifier) - 1;
+ const char cronet_specifier[] = "cronet_http";
+ const size_t cronet_specifier_len = sizeof(cronet_specifier) - 1;
+
+ char *user_agent_str = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ bool grpc_objc_specifier_seen = false;
+ bool cronet_specifier_seen = false;
+ char *major_version = user_agent_str, *minor_version;
+
+ char *head = strtok(user_agent_str, " ");
+ while (head != NULL) {
+ if (!grpc_objc_specifier_seen &&
+ 0 == strncmp(head, grpc_objc_specifier, grpc_objc_specifier_len)) {
+ major_version = head + grpc_objc_specifier_len;
+ grpc_objc_specifier_seen = true;
+ } else if (grpc_objc_specifier_seen &&
+ 0 == strncmp(head, cronet_specifier, cronet_specifier_len)) {
+ cronet_specifier_seen = true;
+ break;
+ }
+
+ head = strtok(NULL, " ");
+ }
+ if (grpc_objc_specifier_seen) {
+ major_version = strtok(major_version, ".");
+ minor_version = strtok(NULL, ".");
+ }
+
+ gpr_free(user_agent_str);
+ return (grpc_objc_specifier_seen &&
+ cronet_specifier_seen &&
+ (atol(major_version) < 1 ||
+ (atol(major_version) == 1 && atol(minor_version) <= 3)));
+}
+
const grpc_channel_filter grpc_workaround_cronet_compression_filter = {
start_transport_stream_op_batch,
grpc_channel_next_op,
@@ -136,6 +196,8 @@ const grpc_channel_filter grpc_workaround_cronet_compression_filter = {
static bool register_workaround_cronet_compression(grpc_exec_ctx* exec_ctx,
grpc_channel_stack_builder* builder,
void* arg) {
+ grpc_register_workaround(GRPC_WORKAROUND_ID_CRONET_COMPRESSION,
+ parse_user_agent);
return grpc_channel_stack_builder_prepend_filter(
builder, &grpc_workaround_cronet_compression_filter, NULL, NULL);
}
diff --git a/src/core/ext/filters/workarounds/workaround_utils.c b/src/core/ext/filters/workarounds/workaround_utils.c
new file mode 100644
index 0000000000..14ed84599c
--- /dev/null
+++ b/src/core/ext/filters/workarounds/workaround_utils.c
@@ -0,0 +1,57 @@
+//
+// Copyright 2017, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "src/core/ext/filters/workarounds/workaround_utils.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+static user_agent_parser user_agent_parsers[GRPC_MAX_WORKAROUND_ID];
+
+grpc_user_agent_md *grpc_parse_user_agent(grpc_mdelem md) {
+ grpc_user_agent_md *user_agent_md;
+
+ // USE THE CACHE WHEN ABLE
+
+ user_agent_md = gpr_malloc(sizeof(grpc_user_agent_md));
+ for (int i = 0; i < GRPC_MAX_WORKAROUND_ID; i++) {
+ if (user_agent_parsers[i]) {
+ user_agent_md->workaround_active[i] = user_agent_parsers[i](md);
+ }
+ }
+
+ return user_agent_md;
+}
+
+void grpc_register_workaround(uint32_t id, user_agent_parser parser) {
+ GPR_ASSERT(id < GRPC_MAX_WORKAROUND_ID);
+ user_agent_parsers[id] = parser;
+}
diff --git a/src/core/ext/filters/workarounds/workaround_utils.h b/src/core/ext/filters/workarounds/workaround_utils.h
new file mode 100644
index 0000000000..99363248cb
--- /dev/null
+++ b/src/core/ext/filters/workarounds/workaround_utils.h
@@ -0,0 +1,54 @@
+//
+// Copyright 2017, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS
+#define GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS
+
+#include "src/core/lib/transport/metadata.h"
+
+#define GRPC_WORKAROUND_PRIORITY_HIGH 9999
+
+typedef enum {
+ GRPC_WORKAROUND_ID_CRONET_COMPRESSION = 0,
+ GRPC_MAX_WORKAROUND_ID,
+} grpc_workaround_list;
+
+typedef struct grpc_user_agent_md {
+ bool workaround_active[GRPC_MAX_WORKAROUND_ID];
+} grpc_user_agent_md;
+
+grpc_user_agent_md *grpc_parse_user_agent(grpc_mdelem md);
+
+typedef bool (*user_agent_parser)(grpc_mdelem);
+
+void grpc_register_workaround(uint32_t id, user_agent_parser parser);
+
+#endif