LCOV - code coverage report
Current view: top level - core/channel - http_client_filter.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 94 98 95.9 %
Date: 2015-12-10 22:15:08 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015, Google Inc.
       3             :  * All rights reserved.
       4             :  *
       5             :  * Redistribution and use in source and binary forms, with or without
       6             :  * modification, are permitted provided that the following conditions are
       7             :  * met:
       8             :  *
       9             :  *     * Redistributions of source code must retain the above copyright
      10             :  * notice, this list of conditions and the following disclaimer.
      11             :  *     * Redistributions in binary form must reproduce the above
      12             :  * copyright notice, this list of conditions and the following disclaimer
      13             :  * in the documentation and/or other materials provided with the
      14             :  * distribution.
      15             :  *     * Neither the name of Google Inc. nor the names of its
      16             :  * contributors may be used to endorse or promote products derived from
      17             :  * this software without specific prior written permission.
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      20             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      21             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      22             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      23             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      24             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      25             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      29             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30             :  *
      31             :  */
      32             : 
      33             : #include "src/core/channel/http_client_filter.h"
      34             : #include <grpc/support/alloc.h>
      35             : #include <grpc/support/log.h>
      36             : #include <grpc/support/string_util.h>
      37             : #include <string.h>
      38             : #include "src/core/profiling/timers.h"
      39             : #include "src/core/support/string.h"
      40             : #include "src/core/transport/static_metadata.h"
      41             : 
      42             : typedef struct call_data {
      43             :   grpc_linked_mdelem method;
      44             :   grpc_linked_mdelem scheme;
      45             :   grpc_linked_mdelem authority;
      46             :   grpc_linked_mdelem te_trailers;
      47             :   grpc_linked_mdelem content_type;
      48             :   grpc_linked_mdelem user_agent;
      49             : 
      50             :   grpc_metadata_batch *recv_initial_metadata;
      51             : 
      52             :   /** Closure to call when finished with the hc_on_recv hook */
      53             :   grpc_closure *on_done_recv;
      54             :   /** Receive closures are chained: we inject this closure as the on_done_recv
      55             :       up-call on transport_op, and remember to call our on_done_recv member
      56             :       after handling it. */
      57             :   grpc_closure hc_on_recv;
      58             : } call_data;
      59             : 
      60             : typedef struct channel_data {
      61             :   grpc_mdelem *static_scheme;
      62             :   grpc_mdelem *user_agent;
      63             : } channel_data;
      64             : 
      65             : typedef struct {
      66             :   grpc_call_element *elem;
      67             :   grpc_exec_ctx *exec_ctx;
      68             : } client_recv_filter_args;
      69             : 
      70     8874948 : static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
      71     8874615 :   client_recv_filter_args *a = user_data;
      72     8874948 :   if (md == GRPC_MDELEM_STATUS_200) {
      73     2271433 :     return NULL;
      74     6603441 :   } else if (md->key == GRPC_MDSTR_STATUS) {
      75           0 :     grpc_call_element_send_cancel(a->exec_ctx, a->elem);
      76           0 :     return NULL;
      77     6603441 :   } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
      78     2270757 :     return NULL;
      79             :   }
      80     4332610 :   return md;
      81             : }
      82             : 
      83     2272069 : static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
      84     2271982 :   grpc_call_element *elem = user_data;
      85     2272069 :   call_data *calld = elem->call_data;
      86             :   client_recv_filter_args a;
      87     2272069 :   a.elem = elem;
      88     2272069 :   a.exec_ctx = exec_ctx;
      89     2272069 :   grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter,
      90             :                              &a);
      91     2271440 :   calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
      92     2272032 : }
      93             : 
      94    10441062 : static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
      95             :   /* eat the things we'd like to set ourselves */
      96    10441062 :   if (md->key == GRPC_MDSTR_METHOD) return NULL;
      97    10441062 :   if (md->key == GRPC_MDSTR_SCHEME) return NULL;
      98    10441062 :   if (md->key == GRPC_MDSTR_TE) return NULL;
      99    10441062 :   if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL;
     100    10441062 :   if (md->key == GRPC_MDSTR_USER_AGENT) return NULL;
     101    10440793 :   return md;
     102             : }
     103             : 
     104     4276400 : static void hc_mutate_op(grpc_call_element *elem,
     105             :                          grpc_transport_stream_op *op) {
     106             :   /* grab pointers to our data from the call element */
     107     4276400 :   call_data *calld = elem->call_data;
     108     4276400 :   channel_data *channeld = elem->channel_data;
     109     4276400 :   if (op->send_initial_metadata != NULL) {
     110     2272216 :     grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter,
     111             :                                elem);
     112             :     /* Send : prefixed headers, which have to be before any application
     113             :        layer headers. */
     114     2272064 :     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
     115             :                                  GRPC_MDELEM_METHOD_POST);
     116     2271844 :     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
     117             :                                  channeld->static_scheme);
     118     2271652 :     grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
     119             :                                  GRPC_MDELEM_TE_TRAILERS);
     120     2271535 :     grpc_metadata_batch_add_tail(
     121             :         op->send_initial_metadata, &calld->content_type,
     122             :         GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
     123     2271582 :     grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent,
     124             :                                  GRPC_MDELEM_REF(channeld->user_agent));
     125             :   }
     126             : 
     127     4278055 :   if (op->recv_initial_metadata != NULL) {
     128             :     /* substitute our callback for the higher callback */
     129     2271781 :     calld->recv_initial_metadata = op->recv_initial_metadata;
     130     2271781 :     calld->on_done_recv = op->on_complete;
     131     2271781 :     op->on_complete = &calld->hc_on_recv;
     132             :   }
     133     4278055 : }
     134             : 
     135     4276802 : static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
     136             :                                   grpc_call_element *elem,
     137             :                                   grpc_transport_stream_op *op) {
     138             :   GPR_TIMER_BEGIN("hc_start_transport_op", 0);
     139     4276802 :   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
     140     4276802 :   hc_mutate_op(elem, op);
     141             :   GPR_TIMER_END("hc_start_transport_op", 0);
     142     4275430 :   grpc_call_next_op(exec_ctx, elem, op);
     143     4278559 : }
     144             : 
     145             : /* Constructor for call_data */
     146     2271453 : static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
     147             :                            grpc_call_element_args *args) {
     148     2271453 :   call_data *calld = elem->call_data;
     149     2271453 :   calld->on_done_recv = NULL;
     150     2271453 :   grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
     151     2271709 : }
     152             : 
     153             : /* Destructor for call_data */
     154     2272067 : static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
     155     2272067 :                               grpc_call_element *elem) {}
     156             : 
     157        2982 : static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
     158             :   unsigned i;
     159             :   size_t j;
     160        2982 :   grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP,
     161             :                                   GRPC_MDELEM_SCHEME_HTTPS};
     162        2982 :   if (args != NULL) {
     163        4592 :     for (i = 0; i < args->num_args; ++i) {
     164        3888 :       if (args->args[i].type == GRPC_ARG_STRING &&
     165        1293 :           strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) {
     166         940 :         for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) {
     167         956 :           if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value),
     168         922 :                           args->args[i].value.string)) {
     169         478 :             return valid_schemes[j];
     170             :           }
     171             :         }
     172             :       }
     173             :     }
     174             :   }
     175        2481 :   return GRPC_MDELEM_SCHEME_HTTP;
     176             : }
     177             : 
     178        2983 : static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
     179             :   gpr_strvec v;
     180             :   size_t i;
     181        2942 :   int is_first = 1;
     182             :   char *tmp;
     183             :   grpc_mdstr *result;
     184             : 
     185        2983 :   gpr_strvec_init(&v);
     186             : 
     187        6056 :   for (i = 0; args && i < args->num_args; i++) {
     188        3073 :     if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) {
     189         245 :       if (args->args[i].type != GRPC_ARG_STRING) {
     190           0 :         gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
     191             :                 GRPC_ARG_PRIMARY_USER_AGENT_STRING);
     192             :       } else {
     193         245 :         if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
     194         206 :         is_first = 0;
     195         245 :         gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
     196             :       }
     197             :     }
     198             :   }
     199             : 
     200        2983 :   gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ",
     201             :                grpc_version_string(), GPR_PLATFORM_STRING);
     202        2942 :   is_first = 0;
     203        2983 :   gpr_strvec_add(&v, tmp);
     204             : 
     205        6057 :   for (i = 0; args && i < args->num_args; i++) {
     206        3074 :     if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) {
     207          72 :       if (args->args[i].type != GRPC_ARG_STRING) {
     208           0 :         gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
     209             :                 GRPC_ARG_SECONDARY_USER_AGENT_STRING);
     210             :       } else {
     211          72 :         if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
     212          72 :         is_first = 0;
     213          72 :         gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
     214             :       }
     215             :     }
     216             :   }
     217             : 
     218        2983 :   tmp = gpr_strvec_flatten(&v, NULL);
     219        2983 :   gpr_strvec_destroy(&v);
     220        2983 :   result = grpc_mdstr_from_string(tmp);
     221        2983 :   gpr_free(tmp);
     222             : 
     223        2983 :   return result;
     224             : }
     225             : 
     226             : /* Constructor for channel_data */
     227        2983 : static void init_channel_elem(grpc_exec_ctx *exec_ctx,
     228             :                               grpc_channel_element *elem,
     229             :                               grpc_channel_element_args *args) {
     230        2983 :   channel_data *chand = elem->channel_data;
     231        2983 :   GPR_ASSERT(!args->is_last);
     232        2983 :   chand->static_scheme = scheme_from_args(args->channel_args);
     233        2983 :   chand->user_agent = grpc_mdelem_from_metadata_strings(
     234             :       GRPC_MDSTR_USER_AGENT, user_agent_from_args(args->channel_args));
     235        2983 : }
     236             : 
     237             : /* Destructor for channel data */
     238        2940 : static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
     239             :                                  grpc_channel_element *elem) {
     240        2940 :   channel_data *chand = elem->channel_data;
     241        2940 :   GRPC_MDELEM_UNREF(chand->user_agent);
     242        2940 : }
     243             : 
     244             : const grpc_channel_filter grpc_http_client_filter = {
     245             :     hc_start_transport_op, grpc_channel_next_op, sizeof(call_data),
     246             :     init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
     247             :     sizeof(channel_data), init_channel_elem, destroy_channel_elem,
     248             :     grpc_call_next_get_peer, "http-client"};

Generated by: LCOV version 1.11