blob: 56e12342d7e9a1a1b91847cbf8460bafbd2c9a8d [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
Craig Tiller06059952015-02-18 08:34:56 -08002 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08003 * 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"
David Klempnera1e86932015-01-13 18:13:59 -080034#include <string.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035#include <grpc/support/log.h>
36
Yang Gao5fd0d292015-01-26 00:19:48 -080037typedef struct call_data {
Craig Tiller6902ad22015-04-16 08:01:49 -070038 grpc_linked_mdelem method;
39 grpc_linked_mdelem scheme;
40 grpc_linked_mdelem te_trailers;
41 grpc_linked_mdelem content_type;
Yang Gao5fd0d292015-01-26 00:19:48 -080042} call_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080043
klempnerc463f742014-12-19 13:03:35 -080044typedef struct channel_data {
45 grpc_mdelem *te_trailers;
46 grpc_mdelem *method;
47 grpc_mdelem *scheme;
48 grpc_mdelem *content_type;
Craig Tiller5b9efed2015-02-03 20:13:06 -080049 grpc_mdelem *status;
klempnerc463f742014-12-19 13:03:35 -080050} channel_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080051
52/* used to silence 'variable not used' warnings */
53static void ignore_unused(void *ignored) {}
54
Craig Tiller6902ad22015-04-16 08:01:49 -070055static grpc_mdelem *client_filter(void *user_data, grpc_mdelem *md) {
56 grpc_call_element *elem = user_data;
57 channel_data *channeld = elem->channel_data;
58 if (md == channeld->status) {
59 return NULL;
60 } else if (md->key == channeld->status->key) {
61 grpc_call_element_send_cancel(elem);
62 return NULL;
63 }
64 return md;
65}
66
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080067/* Called either:
68 - in response to an API call (or similar) from above, to send something
69 - a network event (or similar) from below, to receive something
70 op contains type and call direction information, in addition to the data
71 that is being sent or received. */
ctillerf962f522014-12-10 15:28:27 -080072static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
73 grpc_call_op *op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080074 /* grab pointers to our data from the call element */
75 call_data *calld = elem->call_data;
76 channel_data *channeld = elem->channel_data;
77 GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
78
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080079 switch (op->type) {
klempnerc463f742014-12-19 13:03:35 -080080 case GRPC_SEND_METADATA:
Craig Tiller6902ad22015-04-16 08:01:49 -070081 /* Send : prefixed headers, which have to be before any application
82 * layer headers. */
Craig Tiller205aee12015-04-16 14:46:41 -070083 grpc_metadata_batch_add_head(&op->data.metadata, &calld->method,
Craig Tiller1b5062c2015-04-21 11:53:02 -070084 grpc_mdelem_ref(channeld->method));
Craig Tiller205aee12015-04-16 14:46:41 -070085 grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme,
Craig Tiller1b5062c2015-04-21 11:53:02 -070086 grpc_mdelem_ref(channeld->scheme));
Craig Tiller205aee12015-04-16 14:46:41 -070087 grpc_metadata_batch_add_tail(&op->data.metadata, &calld->te_trailers,
Craig Tiller1b5062c2015-04-21 11:53:02 -070088 grpc_mdelem_ref(channeld->te_trailers));
Craig Tiller205aee12015-04-16 14:46:41 -070089 grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type,
Craig Tiller1b5062c2015-04-21 11:53:02 -070090 grpc_mdelem_ref(channeld->content_type));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080091 grpc_call_next_op(elem, op);
92 break;
Craig Tiller5b9efed2015-02-03 20:13:06 -080093 case GRPC_RECV_METADATA:
Craig Tiller205aee12015-04-16 14:46:41 -070094 grpc_metadata_batch_filter(&op->data.metadata, client_filter, elem);
Craig Tiller6902ad22015-04-16 08:01:49 -070095 grpc_call_next_op(elem, op);
Craig Tiller5b9efed2015-02-03 20:13:06 -080096 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080097 default:
98 /* pass control up or down the stack depending on op->dir */
99 grpc_call_next_op(elem, op);
100 break;
101 }
102}
103
104/* Called on special channel events, such as disconnection or new incoming
105 calls on the server */
ctillerf962f522014-12-10 15:28:27 -0800106static void channel_op(grpc_channel_element *elem,
107 grpc_channel_element *from_elem, grpc_channel_op *op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800108 /* grab pointers to our data from the channel element */
109 channel_data *channeld = elem->channel_data;
110
111 ignore_unused(channeld);
112
113 switch (op->type) {
114 default:
115 /* pass control up or down the stack depending on op->dir */
116 grpc_channel_next_op(elem, op);
117 break;
118 }
119}
120
121/* Constructor for call_data */
122static void init_call_elem(grpc_call_element *elem,
Craig Tiller87d5b192015-04-16 14:37:57 -0700123 const void *server_transport_data) {}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800124
125/* Destructor for call_data */
126static void destroy_call_elem(grpc_call_element *elem) {
127 /* grab pointers to our data from the call element */
128 call_data *calld = elem->call_data;
129 channel_data *channeld = elem->channel_data;
130
131 ignore_unused(calld);
132 ignore_unused(channeld);
133}
134
David Klempnered0cbc82015-01-14 14:46:10 -0800135static const char *scheme_from_args(const grpc_channel_args *args) {
Nicolas "Pixel" Noble213ed912015-01-30 02:11:35 +0100136 unsigned i;
David Klempnera1e86932015-01-13 18:13:59 -0800137 if (args != NULL) {
138 for (i = 0; i < args->num_args; ++i) {
139 if (args->args[i].type == GRPC_ARG_STRING &&
David Klempnered0cbc82015-01-14 14:46:10 -0800140 strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) {
David Klempnera1e86932015-01-13 18:13:59 -0800141 return args->args[i].value.string;
142 }
143 }
144 }
145 return "http";
146}
147
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800148/* Constructor for channel_data */
149static void init_channel_elem(grpc_channel_element *elem,
150 const grpc_channel_args *args, grpc_mdctx *mdctx,
151 int is_first, int is_last) {
152 /* grab pointers to our data from the channel element */
153 channel_data *channeld = elem->channel_data;
154
155 /* The first and the last filters tend to be implemented differently to
156 handle the case that there's no 'next' filter to call on the up or down
157 path */
158 GPR_ASSERT(!is_first);
159 GPR_ASSERT(!is_last);
160
161 /* initialize members */
162 channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
klempnerc463f742014-12-19 13:03:35 -0800163 channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST");
David Klempnera1e86932015-01-13 18:13:59 -0800164 channeld->scheme =
165 grpc_mdelem_from_strings(mdctx, ":scheme", scheme_from_args(args));
klempnerc463f742014-12-19 13:03:35 -0800166 channeld->content_type =
167 grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
Craig Tiller5b9efed2015-02-03 20:13:06 -0800168 channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800169}
170
171/* Destructor for channel data */
172static void destroy_channel_elem(grpc_channel_element *elem) {
173 /* grab pointers to our data from the channel element */
174 channel_data *channeld = elem->channel_data;
175
176 grpc_mdelem_unref(channeld->te_trailers);
klempnerc463f742014-12-19 13:03:35 -0800177 grpc_mdelem_unref(channeld->method);
178 grpc_mdelem_unref(channeld->scheme);
179 grpc_mdelem_unref(channeld->content_type);
Craig Tiller5b9efed2015-02-03 20:13:06 -0800180 grpc_mdelem_unref(channeld->status);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800181}
182
183const grpc_channel_filter grpc_http_client_filter = {
Craig Tiller87d5b192015-04-16 14:37:57 -0700184 call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem,
185 sizeof(channel_data), init_channel_elem, destroy_channel_elem,
186 "http-client"};