blob: 98e26aa563ec1cbed2306eaf09a759182d50d9b6 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
3 * Copyright 2014, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/core/channel/http_client_filter.h"
35#include <grpc/support/log.h>
36
klempnerc463f742014-12-19 13:03:35 -080037typedef struct call_data { int sent_headers; } call_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080038
klempnerc463f742014-12-19 13:03:35 -080039typedef struct channel_data {
40 grpc_mdelem *te_trailers;
41 grpc_mdelem *method;
42 grpc_mdelem *scheme;
43 grpc_mdelem *content_type;
44} channel_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080045
46/* used to silence 'variable not used' warnings */
47static void ignore_unused(void *ignored) {}
48
49/* Called either:
50 - in response to an API call (or similar) from above, to send something
51 - a network event (or similar) from below, to receive something
52 op contains type and call direction information, in addition to the data
53 that is being sent or received. */
ctillerf962f522014-12-10 15:28:27 -080054static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
55 grpc_call_op *op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080056 /* grab pointers to our data from the call element */
57 call_data *calld = elem->call_data;
58 channel_data *channeld = elem->channel_data;
59 GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
60
61 ignore_unused(calld);
62
63 switch (op->type) {
klempnerc463f742014-12-19 13:03:35 -080064 case GRPC_SEND_METADATA:
65 if (!calld->sent_headers) {
66 /* Send : prefixed headers, which have to be before any application
67 * layer headers. */
68 calld->sent_headers = 1;
69 grpc_call_element_send_metadata(elem, channeld->method);
70 grpc_call_element_send_metadata(elem, channeld->scheme);
71 }
72 grpc_call_next_op(elem, op);
73 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080074 case GRPC_SEND_START:
klempnerc463f742014-12-19 13:03:35 -080075 if (!calld->sent_headers) {
76 /* Send : prefixed headers, if we haven't already */
77 calld->sent_headers = 1;
78 grpc_call_element_send_metadata(elem, channeld->method);
79 grpc_call_element_send_metadata(elem, channeld->scheme);
80 }
81 /* Send non : prefixed headers */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080082 grpc_call_element_send_metadata(elem, channeld->te_trailers);
klempnerc463f742014-12-19 13:03:35 -080083 grpc_call_element_send_metadata(elem, channeld->content_type);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080084 grpc_call_next_op(elem, op);
85 break;
86 default:
87 /* pass control up or down the stack depending on op->dir */
88 grpc_call_next_op(elem, op);
89 break;
90 }
91}
92
93/* Called on special channel events, such as disconnection or new incoming
94 calls on the server */
ctillerf962f522014-12-10 15:28:27 -080095static void channel_op(grpc_channel_element *elem,
96 grpc_channel_element *from_elem, grpc_channel_op *op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080097 /* grab pointers to our data from the channel element */
98 channel_data *channeld = elem->channel_data;
99
100 ignore_unused(channeld);
101
102 switch (op->type) {
103 default:
104 /* pass control up or down the stack depending on op->dir */
105 grpc_channel_next_op(elem, op);
106 break;
107 }
108}
109
110/* Constructor for call_data */
111static void init_call_elem(grpc_call_element *elem,
112 const void *server_transport_data) {
113 /* grab pointers to our data from the call element */
114 call_data *calld = elem->call_data;
115 channel_data *channeld = elem->channel_data;
116
117 ignore_unused(channeld);
118
119 /* initialize members */
klempnerc463f742014-12-19 13:03:35 -0800120 calld->sent_headers = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800121}
122
123/* Destructor for call_data */
124static void destroy_call_elem(grpc_call_element *elem) {
125 /* grab pointers to our data from the call element */
126 call_data *calld = elem->call_data;
127 channel_data *channeld = elem->channel_data;
128
129 ignore_unused(calld);
130 ignore_unused(channeld);
131}
132
133/* Constructor for channel_data */
134static void init_channel_elem(grpc_channel_element *elem,
135 const grpc_channel_args *args, grpc_mdctx *mdctx,
136 int is_first, int is_last) {
137 /* grab pointers to our data from the channel element */
138 channel_data *channeld = elem->channel_data;
139
140 /* The first and the last filters tend to be implemented differently to
141 handle the case that there's no 'next' filter to call on the up or down
142 path */
143 GPR_ASSERT(!is_first);
144 GPR_ASSERT(!is_last);
145
146 /* initialize members */
147 channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
klempnerc463f742014-12-19 13:03:35 -0800148 channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST");
149 channeld->scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
150 channeld->content_type =
151 grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800152}
153
154/* Destructor for channel data */
155static void destroy_channel_elem(grpc_channel_element *elem) {
156 /* grab pointers to our data from the channel element */
157 channel_data *channeld = elem->channel_data;
158
159 grpc_mdelem_unref(channeld->te_trailers);
klempnerc463f742014-12-19 13:03:35 -0800160 grpc_mdelem_unref(channeld->method);
161 grpc_mdelem_unref(channeld->scheme);
162 grpc_mdelem_unref(channeld->content_type);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800163}
164
165const grpc_channel_filter grpc_http_client_filter = {
166 call_op, channel_op,
167
168 sizeof(call_data), init_call_elem, destroy_call_elem,
169
170 sizeof(channel_data), init_channel_elem, destroy_channel_elem,
171
172 "http-client"};