blob: d52cc7d0184220ffb3ddd02d5e0122c0263ea088 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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
Craig Tiller9533d042016-03-25 17:11:06 -070034#include "src/core/lib/channel/http_server_filter.h"
ctillerd74729d2015-01-12 13:31:36 -080035
Craig Tillerc50e3982015-01-20 16:30:54 -080036#include <grpc/support/alloc.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080037#include <grpc/support/log.h>
yang-gd88e1d82015-12-02 13:23:33 -080038#include <string.h>
Craig Tiller9533d042016-03-25 17:11:06 -070039#include "src/core/lib/profiling/timers.h"
40#include "src/core/lib/transport/static_metadata.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080041
Mark D. Roth640d71d2016-04-27 07:17:58 -070042#define EXPECTED_CONTENT_TYPE "application/grpc"
43#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
44
Craig Tillera82950e2015-09-22 12:33:20 -070045typedef struct call_data {
Craig Tiller7536af02015-12-22 13:49:30 -080046 uint8_t seen_path;
Craig Tiller4d40ba32016-03-09 17:48:40 -080047 uint8_t seen_method;
Craig Tiller7536af02015-12-22 13:49:30 -080048 uint8_t sent_status;
49 uint8_t seen_scheme;
50 uint8_t seen_te_trailers;
51 uint8_t seen_authority;
Craig Tiller6902ad22015-04-16 08:01:49 -070052 grpc_linked_mdelem status;
Craig Tillercb014172015-09-08 16:40:26 -070053 grpc_linked_mdelem content_type;
Craig Tiller83f88d92015-04-21 16:02:05 -070054
Craig Tiller577c9b22015-11-02 14:11:15 -080055 grpc_metadata_batch *recv_initial_metadata;
Craig Tiller4d40ba32016-03-09 17:48:40 -080056 bool *recv_idempotent_request;
Craig Tiller98bf7e62015-06-24 08:47:07 -070057 /** Closure to call when finished with the hs_on_recv hook */
Craig Tiller33825112015-09-18 07:44:19 -070058 grpc_closure *on_done_recv;
Craig Tiller98bf7e62015-06-24 08:47:07 -070059 /** Receive closures are chained: we inject this closure as the on_done_recv
60 up-call on transport_op, and remember to call our on_done_recv member
61 after handling it. */
Craig Tiller33825112015-09-18 07:44:19 -070062 grpc_closure hs_on_recv;
ctillerd74729d2015-01-12 13:31:36 -080063} call_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080064
Craig Tiller7536af02015-12-22 13:49:30 -080065typedef struct channel_data { uint8_t unused; } channel_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080066
Craig Tillera82950e2015-09-22 12:33:20 -070067typedef struct {
Craig Tillerd1bec032015-09-18 17:29:00 -070068 grpc_call_element *elem;
Craig Tiller8af4c332015-09-22 12:32:31 -070069 grpc_exec_ctx *exec_ctx;
Craig Tillerd1bec032015-09-18 17:29:00 -070070} server_filter_args;
71
Craig Tillera82950e2015-09-22 12:33:20 -070072static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
Craig Tillerd1bec032015-09-18 17:29:00 -070073 server_filter_args *a = user_data;
74 grpc_call_element *elem = a->elem;
Craig Tillerfd7d3ec2015-01-21 13:37:09 -080075 call_data *calld = elem->call_data;
Craig Tillerfd7d3ec2015-01-21 13:37:09 -080076
Craig Tiller6902ad22015-04-16 08:01:49 -070077 /* Check if it is one of the headers we care about. */
Craig Tillerebdef9d2015-11-19 17:09:49 -080078 if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
Craig Tiller4d40ba32016-03-09 17:48:40 -080079 md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_SCHEME_HTTP ||
80 md == GRPC_MDELEM_SCHEME_HTTPS ||
Craig Tillerebdef9d2015-11-19 17:09:49 -080081 md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
Craig Tillera82950e2015-09-22 12:33:20 -070082 /* swallow it */
Craig Tillerebdef9d2015-11-19 17:09:49 -080083 if (md == GRPC_MDELEM_METHOD_POST) {
Craig Tiller4d40ba32016-03-09 17:48:40 -080084 calld->seen_method = 1;
85 *calld->recv_idempotent_request = false;
86 } else if (md == GRPC_MDELEM_METHOD_PUT) {
87 calld->seen_method = 1;
88 *calld->recv_idempotent_request = true;
Craig Tillerebdef9d2015-11-19 17:09:49 -080089 } else if (md->key == GRPC_MDSTR_SCHEME) {
Craig Tillera82950e2015-09-22 12:33:20 -070090 calld->seen_scheme = 1;
Craig Tillerebdef9d2015-11-19 17:09:49 -080091 } else if (md == GRPC_MDELEM_TE_TRAILERS) {
Craig Tillera82950e2015-09-22 12:33:20 -070092 calld->seen_te_trailers = 1;
93 }
94 /* TODO(klempner): Track that we've seen all the headers we should
95 require */
96 return NULL;
Craig Tillerebdef9d2015-11-19 17:09:49 -080097 } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
Mark D. Roth1f3319b2016-04-27 10:59:19 -070098 const char *value_str = grpc_mdstr_as_c_string(md->value);
Mark D. Roth640d71d2016-04-27 07:17:58 -070099 if (strncmp(value_str, EXPECTED_CONTENT_TYPE,
100 EXPECTED_CONTENT_TYPE_LENGTH) == 0 &&
101 (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' ||
102 value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) {
Craig Tillera82950e2015-09-22 12:33:20 -0700103 /* Although the C implementation doesn't (currently) generate them,
104 any custom +-suffix is explicitly valid. */
105 /* TODO(klempner): We should consider preallocating common values such
106 as +proto or +json, or at least stashing them if we see them. */
107 /* TODO(klempner): Should we be surfacing this to application code? */
108 } else {
109 /* TODO(klempner): We're currently allowing this, but we shouldn't
110 see it without a proxy so log for now. */
David Garcia Quintas8ba60db2016-05-20 13:53:14 -0700111 gpr_log(GPR_INFO, "Unexpected content-type '%s'", value_str);
Craig Tillera82950e2015-09-22 12:33:20 -0700112 }
113 return NULL;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800114 } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
115 md->key == GRPC_MDSTR_SCHEME) {
Craig Tillera82950e2015-09-22 12:33:20 -0700116 gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
117 grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
118 /* swallow it and error everything out. */
119 /* TODO(klempner): We ought to generate more descriptive error messages
120 on the wire here. */
121 grpc_call_element_send_cancel(a->exec_ctx, elem);
122 return NULL;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800123 } else if (md->key == GRPC_MDSTR_PATH) {
Craig Tillera82950e2015-09-22 12:33:20 -0700124 if (calld->seen_path) {
125 gpr_log(GPR_ERROR, "Received :path twice");
Craig Tiller6902ad22015-04-16 08:01:49 -0700126 return NULL;
127 }
Craig Tillera82950e2015-09-22 12:33:20 -0700128 calld->seen_path = 1;
129 return md;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800130 } else if (md->key == GRPC_MDSTR_AUTHORITY) {
Craig Tillera82950e2015-09-22 12:33:20 -0700131 calld->seen_authority = 1;
132 return md;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800133 } else if (md->key == GRPC_MDSTR_HOST) {
Craig Tillera82950e2015-09-22 12:33:20 -0700134 /* translate host to :authority since :authority may be
135 omitted */
136 grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
Craig Tillerb2b42612015-11-20 12:02:17 -0800137 GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
Craig Tillera82950e2015-09-22 12:33:20 -0700138 calld->seen_authority = 1;
139 return authority;
140 } else {
141 return md;
142 }
Craig Tillerce6e3502015-01-19 18:04:42 -0800143}
144
Craig Tillerc027e772016-05-03 16:27:00 -0700145static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
146 grpc_error *err) {
Craig Tiller83f88d92015-04-21 16:02:05 -0700147 grpc_call_element *elem = user_data;
148 call_data *calld = elem->call_data;
Craig Tillerc027e772016-05-03 16:27:00 -0700149 if (err == GRPC_ERROR_NONE) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800150 server_filter_args a;
151 a.elem = elem;
152 a.exec_ctx = exec_ctx;
153 grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a);
154 /* Have we seen the required http2 transport headers?
155 (:method, :scheme, content-type, with :path and :authority covered
156 at the channel level right now) */
Craig Tiller4d40ba32016-03-09 17:48:40 -0800157 if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers &&
Craig Tiller577c9b22015-11-02 14:11:15 -0800158 calld->seen_path && calld->seen_authority) {
159 /* do nothing */
160 } else {
Craig Tillerc027e772016-05-03 16:27:00 -0700161 err = GRPC_ERROR_CREATE("Bad incoming HTTP headers");
Craig Tiller577c9b22015-11-02 14:11:15 -0800162 if (!calld->seen_path) {
Craig Tillerc027e772016-05-03 16:27:00 -0700163 err = grpc_error_add_child(err,
164 GRPC_ERROR_CREATE("Missing :path header"));
Craig Tillera82950e2015-09-22 12:33:20 -0700165 }
Craig Tiller577c9b22015-11-02 14:11:15 -0800166 if (!calld->seen_authority) {
Craig Tillerc027e772016-05-03 16:27:00 -0700167 err = grpc_error_add_child(
168 err, GRPC_ERROR_CREATE("Missing :authority header"));
Craig Tiller577c9b22015-11-02 14:11:15 -0800169 }
Craig Tiller4d40ba32016-03-09 17:48:40 -0800170 if (!calld->seen_method) {
Craig Tillerc027e772016-05-03 16:27:00 -0700171 err = grpc_error_add_child(err,
172 GRPC_ERROR_CREATE("Missing :method header"));
Craig Tiller577c9b22015-11-02 14:11:15 -0800173 }
174 if (!calld->seen_scheme) {
Craig Tillerc027e772016-05-03 16:27:00 -0700175 err = grpc_error_add_child(err,
176 GRPC_ERROR_CREATE("Missing :scheme header"));
Craig Tiller577c9b22015-11-02 14:11:15 -0800177 }
178 if (!calld->seen_te_trailers) {
Craig Tillerc027e772016-05-03 16:27:00 -0700179 err = grpc_error_add_child(
180 err, GRPC_ERROR_CREATE("Missing te: trailers header"));
Craig Tiller577c9b22015-11-02 14:11:15 -0800181 }
182 /* Error this call out */
Craig Tiller577c9b22015-11-02 14:11:15 -0800183 grpc_call_element_send_cancel(exec_ctx, elem);
Craig Tiller83f88d92015-04-21 16:02:05 -0700184 }
Craig Tiller8e5c9342016-05-12 15:34:59 -0700185 } else {
186 GRPC_ERROR_REF(err);
Craig Tillera82950e2015-09-22 12:33:20 -0700187 }
Craig Tillerc027e772016-05-03 16:27:00 -0700188 calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, err);
Craig Tiller8e5c9342016-05-12 15:34:59 -0700189 GRPC_ERROR_UNREF(err);
Craig Tiller83f88d92015-04-21 16:02:05 -0700190}
191
Craig Tillera82950e2015-09-22 12:33:20 -0700192static void hs_mutate_op(grpc_call_element *elem,
193 grpc_transport_stream_op *op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800194 /* grab pointers to our data from the call element */
195 call_data *calld = elem->call_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800196
Craig Tiller577c9b22015-11-02 14:11:15 -0800197 if (op->send_initial_metadata != NULL && !calld->sent_status) {
198 calld->sent_status = 1;
199 grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status,
Craig Tillerebdef9d2015-11-19 17:09:49 -0800200 GRPC_MDELEM_STATUS_200);
201 grpc_metadata_batch_add_tail(
202 op->send_initial_metadata, &calld->content_type,
203 GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
Craig Tillera82950e2015-09-22 12:33:20 -0700204 }
Craig Tiller83f88d92015-04-21 16:02:05 -0700205
Craig Tiller577c9b22015-11-02 14:11:15 -0800206 if (op->recv_initial_metadata) {
Craig Tillera82950e2015-09-22 12:33:20 -0700207 /* substitute our callback for the higher callback */
Craig Tillerc1b6bdd2016-03-10 07:10:38 -0800208 GPR_ASSERT(op->recv_idempotent_request != NULL);
Craig Tiller577c9b22015-11-02 14:11:15 -0800209 calld->recv_initial_metadata = op->recv_initial_metadata;
Craig Tillerc1b6bdd2016-03-10 07:10:38 -0800210 calld->recv_idempotent_request = op->recv_idempotent_request;
Craig Tillera44cbfc2016-02-03 16:02:49 -0800211 calld->on_done_recv = op->recv_initial_metadata_ready;
212 op->recv_initial_metadata_ready = &calld->hs_on_recv;
Craig Tillera82950e2015-09-22 12:33:20 -0700213 }
Craig Tiller50d9db52015-04-23 10:52:14 -0700214}
Craig Tiller83f88d92015-04-21 16:02:05 -0700215
Craig Tillera82950e2015-09-22 12:33:20 -0700216static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
217 grpc_call_element *elem,
218 grpc_transport_stream_op *op) {
219 GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
Craig Tiller0ba432d2015-10-09 16:57:11 -0700220 GPR_TIMER_BEGIN("hs_start_transport_op", 0);
Craig Tillera82950e2015-09-22 12:33:20 -0700221 hs_mutate_op(elem, op);
222 grpc_call_next_op(exec_ctx, elem, op);
Craig Tiller0ba432d2015-10-09 16:57:11 -0700223 GPR_TIMER_END("hs_start_transport_op", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800224}
225
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800226/* Constructor for call_data */
Craig Tillera82950e2015-09-22 12:33:20 -0700227static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
Craig Tiller577c9b22015-11-02 14:11:15 -0800228 grpc_call_element_args *args) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800229 /* grab pointers to our data from the call element */
230 call_data *calld = elem->call_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800231 /* initialize members */
Craig Tillera82950e2015-09-22 12:33:20 -0700232 memset(calld, 0, sizeof(*calld));
233 grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800234}
235
236/* Destructor for call_data */
Craig Tiller2c8063c2016-03-22 22:12:15 -0700237static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
David Garcia Quintas5dde14c2016-07-28 17:29:27 -0700238 const grpc_call_final_info *final_info,
239 void *ignored) {}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800240
241/* Constructor for channel_data */
Craig Tillera82950e2015-09-22 12:33:20 -0700242static void init_channel_elem(grpc_exec_ctx *exec_ctx,
Craig Tiller577c9b22015-11-02 14:11:15 -0800243 grpc_channel_element *elem,
244 grpc_channel_element_args *args) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800245 GPR_ASSERT(!args->is_last);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800246}
247
248/* Destructor for channel data */
Craig Tillera82950e2015-09-22 12:33:20 -0700249static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
Craig Tillerab33b482015-11-21 08:11:04 -0800250 grpc_channel_element *elem) {}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800251
252const grpc_channel_filter grpc_http_server_filter = {
Craig Tillerf40df232016-03-25 13:38:14 -0700253 hs_start_transport_op,
254 grpc_channel_next_op,
255 sizeof(call_data),
256 init_call_elem,
David Garcia Quintas4afce7e2016-04-18 16:25:17 -0700257 grpc_call_stack_ignore_set_pollset_or_pollset_set,
Craig Tillerf40df232016-03-25 13:38:14 -0700258 destroy_call_elem,
259 sizeof(channel_data),
260 init_channel_elem,
261 destroy_channel_elem,
262 grpc_call_next_get_peer,
263 "http-server"};