1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include "test/core/end2end/end2end_tests.h"
20 
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include <grpc/byte_buffer.h>
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 #include <grpc/support/time.h>
28 
29 #include "src/core/lib/channel/channel_args.h"
30 #include "src/core/lib/iomgr/exec_ctx.h"
31 #include "src/core/lib/slice/slice_internal.h"
32 #include "src/core/lib/transport/metadata.h"
33 
34 #include "test/core/end2end/cq_verifier.h"
35 
tag(intptr_t t)36 static void* tag(intptr_t t) { return (void*)t; }
37 
begin_test(grpc_end2end_test_config config,const char * test_name,grpc_channel_args * client_args,grpc_channel_args * server_args)38 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
39                                             const char* test_name,
40                                             grpc_channel_args* client_args,
41                                             grpc_channel_args* server_args) {
42   grpc_end2end_test_fixture f;
43   gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
44   // We intentionally do not pass the client and server args to
45   // create_fixture(), since we don't want the limit enforced on the
46   // proxy, only on the backend server.
47   f = config.create_fixture(nullptr, nullptr);
48   config.init_server(&f, server_args);
49   config.init_client(&f, client_args);
50   return f;
51 }
52 
n_seconds_from_now(int n)53 static gpr_timespec n_seconds_from_now(int n) {
54   return grpc_timeout_seconds_to_deadline(n);
55 }
56 
five_seconds_from_now(void)57 static gpr_timespec five_seconds_from_now(void) {
58   return n_seconds_from_now(5);
59 }
60 
drain_cq(grpc_completion_queue * cq)61 static void drain_cq(grpc_completion_queue* cq) {
62   grpc_event ev;
63   do {
64     ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
65   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
66 }
67 
shutdown_server(grpc_end2end_test_fixture * f)68 static void shutdown_server(grpc_end2end_test_fixture* f) {
69   if (!f->server) return;
70   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
71   grpc_event ev = grpc_completion_queue_next(
72       f->cq, grpc_timeout_seconds_to_deadline(5), nullptr);
73   GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
74   GPR_ASSERT(ev.tag == tag(1000));
75   grpc_server_destroy(f->server);
76   f->server = nullptr;
77 }
78 
shutdown_client(grpc_end2end_test_fixture * f)79 static void shutdown_client(grpc_end2end_test_fixture* f) {
80   if (!f->client) return;
81   grpc_channel_destroy(f->client);
82   f->client = nullptr;
83 }
84 
end_test(grpc_end2end_test_fixture * f)85 static void end_test(grpc_end2end_test_fixture* f) {
86   shutdown_server(f);
87   shutdown_client(f);
88 
89   grpc_completion_queue_shutdown(f->cq);
90   drain_cq(f->cq);
91   grpc_completion_queue_destroy(f->cq);
92   grpc_completion_queue_destroy(f->shutdown_cq);
93 }
94 
95 // Test with request larger than the limit.
96 // If send_limit is true, applies send limit on client; otherwise, applies
97 // recv limit on server.
test_max_message_length_on_request(grpc_end2end_test_config config,bool send_limit,bool use_service_config,bool use_string_json_value)98 static void test_max_message_length_on_request(grpc_end2end_test_config config,
99                                                bool send_limit,
100                                                bool use_service_config,
101                                                bool use_string_json_value) {
102   gpr_log(GPR_INFO,
103           "testing request with send_limit=%d use_service_config=%d "
104           "use_string_json_value=%d",
105           send_limit, use_service_config, use_string_json_value);
106 
107   grpc_end2end_test_fixture f;
108   grpc_call* c = nullptr;
109   grpc_call* s = nullptr;
110   cq_verifier* cqv;
111   grpc_op ops[6];
112   grpc_op* op;
113   grpc_slice request_payload_slice =
114       grpc_slice_from_copied_string("hello world");
115   grpc_byte_buffer* request_payload =
116       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
117   grpc_byte_buffer* recv_payload = nullptr;
118   grpc_metadata_array initial_metadata_recv;
119   grpc_metadata_array trailing_metadata_recv;
120   grpc_metadata_array request_metadata_recv;
121   grpc_call_details call_details;
122   grpc_status_code status;
123   grpc_call_error error;
124   grpc_slice details;
125   int was_cancelled = 2;
126 
127   grpc_channel_args* client_args = nullptr;
128   grpc_channel_args* server_args = nullptr;
129   if (use_service_config) {
130     // We don't currently support service configs on the server side.
131     GPR_ASSERT(send_limit);
132     grpc_arg arg;
133     arg.type = GRPC_ARG_STRING;
134     arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
135     arg.value.string =
136         use_string_json_value
137             ? const_cast<char*>(
138                   "{\n"
139                   "  \"methodConfig\": [ {\n"
140                   "    \"name\": [\n"
141                   "      { \"service\": \"service\", \"method\": \"method\" }\n"
142                   "    ],\n"
143                   "    \"maxRequestMessageBytes\": \"5\"\n"
144                   "  } ]\n"
145                   "}")
146             : const_cast<char*>(
147                   "{\n"
148                   "  \"methodConfig\": [ {\n"
149                   "    \"name\": [\n"
150                   "      { \"service\": \"service\", \"method\": \"method\" }\n"
151                   "    ],\n"
152                   "    \"maxRequestMessageBytes\": 5\n"
153                   "  } ]\n"
154                   "}");
155     client_args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
156   } else {
157     // Set limit via channel args.
158     grpc_arg arg;
159     arg.key = send_limit
160                   ? const_cast<char*>(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH)
161                   : const_cast<char*>(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH);
162     arg.type = GRPC_ARG_INTEGER;
163     arg.value.integer = 5;
164     grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
165     if (send_limit) {
166       client_args = args;
167     } else {
168       server_args = args;
169     }
170   }
171 
172   f = begin_test(config, "test_max_request_message_length", client_args,
173                  server_args);
174   {
175     grpc_core::ExecCtx exec_ctx;
176     if (client_args != nullptr) grpc_channel_args_destroy(client_args);
177     if (server_args != nullptr) grpc_channel_args_destroy(server_args);
178   }
179 
180   cqv = cq_verifier_create(f.cq);
181 
182   c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
183                                grpc_slice_from_static_string("/service/method"),
184                                nullptr, gpr_inf_future(GPR_CLOCK_REALTIME),
185                                nullptr);
186   GPR_ASSERT(c);
187 
188   grpc_metadata_array_init(&initial_metadata_recv);
189   grpc_metadata_array_init(&trailing_metadata_recv);
190   grpc_metadata_array_init(&request_metadata_recv);
191   grpc_call_details_init(&call_details);
192 
193   memset(ops, 0, sizeof(ops));
194   op = ops;
195   op->op = GRPC_OP_SEND_INITIAL_METADATA;
196   op->data.send_initial_metadata.count = 0;
197   op->flags = 0;
198   op->reserved = nullptr;
199   op++;
200   op->op = GRPC_OP_SEND_MESSAGE;
201   op->data.send_message.send_message = request_payload;
202   op->flags = 0;
203   op->reserved = nullptr;
204   op++;
205   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
206   op->flags = 0;
207   op->reserved = nullptr;
208   op++;
209   op->op = GRPC_OP_RECV_INITIAL_METADATA;
210   op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
211   op->flags = 0;
212   op->reserved = nullptr;
213   op++;
214   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
215   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
216   op->data.recv_status_on_client.status = &status;
217   op->data.recv_status_on_client.status_details = &details;
218   op->flags = 0;
219   op->reserved = nullptr;
220   op++;
221   error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
222                                 nullptr);
223   GPR_ASSERT(GRPC_CALL_OK == error);
224 
225   if (send_limit) {
226     CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
227     cq_verify(cqv);
228     goto done;
229   }
230 
231   error =
232       grpc_server_request_call(f.server, &s, &call_details,
233                                &request_metadata_recv, f.cq, f.cq, tag(101));
234   GPR_ASSERT(GRPC_CALL_OK == error);
235   CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
236   cq_verify(cqv);
237 
238   memset(ops, 0, sizeof(ops));
239   op = ops;
240   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
241   op->data.recv_close_on_server.cancelled = &was_cancelled;
242   op->flags = 0;
243   op->reserved = nullptr;
244   op++;
245   op->op = GRPC_OP_RECV_MESSAGE;
246   op->data.recv_message.recv_message = &recv_payload;
247   op->flags = 0;
248   op->reserved = nullptr;
249   op++;
250   error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
251                                 nullptr);
252   GPR_ASSERT(GRPC_CALL_OK == error);
253 
254   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
255   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
256   cq_verify(cqv);
257 
258   GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
259   GPR_ASSERT(was_cancelled == 1);
260 
261 done:
262   GPR_ASSERT(status == GRPC_STATUS_RESOURCE_EXHAUSTED);
263   GPR_ASSERT(
264       grpc_slice_str_cmp(
265           details, send_limit
266                        ? "Sent message larger than max (11 vs. 5)"
267                        : "Received message larger than max (11 vs. 5)") == 0);
268 
269   grpc_slice_unref(details);
270   grpc_metadata_array_destroy(&initial_metadata_recv);
271   grpc_metadata_array_destroy(&trailing_metadata_recv);
272   grpc_metadata_array_destroy(&request_metadata_recv);
273   grpc_call_details_destroy(&call_details);
274   grpc_byte_buffer_destroy(request_payload);
275   grpc_byte_buffer_destroy(recv_payload);
276 
277   grpc_call_unref(c);
278   if (s != nullptr) grpc_call_unref(s);
279 
280   cq_verifier_destroy(cqv);
281 
282   end_test(&f);
283   config.tear_down_data(&f);
284 }
285 
286 // Test with response larger than the limit.
287 // If send_limit is true, applies send limit on server; otherwise, applies
288 // recv limit on client.
test_max_message_length_on_response(grpc_end2end_test_config config,bool send_limit,bool use_service_config,bool use_string_json_value)289 static void test_max_message_length_on_response(grpc_end2end_test_config config,
290                                                 bool send_limit,
291                                                 bool use_service_config,
292                                                 bool use_string_json_value) {
293   gpr_log(GPR_INFO,
294           "testing response with send_limit=%d use_service_config=%d "
295           "use_string_json_value=%d",
296           send_limit, use_service_config, use_string_json_value);
297 
298   grpc_end2end_test_fixture f;
299   grpc_call* c = nullptr;
300   grpc_call* s = nullptr;
301   cq_verifier* cqv;
302   grpc_op ops[6];
303   grpc_op* op;
304   grpc_slice response_payload_slice =
305       grpc_slice_from_copied_string("hello world");
306   grpc_byte_buffer* response_payload =
307       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
308   grpc_byte_buffer* recv_payload = nullptr;
309   grpc_metadata_array initial_metadata_recv;
310   grpc_metadata_array trailing_metadata_recv;
311   grpc_metadata_array request_metadata_recv;
312   grpc_call_details call_details;
313   grpc_status_code status;
314   grpc_call_error error;
315   grpc_slice details;
316   int was_cancelled = 2;
317 
318   grpc_channel_args* client_args = nullptr;
319   grpc_channel_args* server_args = nullptr;
320   if (use_service_config) {
321     // We don't currently support service configs on the server side.
322     GPR_ASSERT(!send_limit);
323     grpc_arg arg;
324     arg.type = GRPC_ARG_STRING;
325     arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
326     arg.value.string = const_cast<char*>(
327         use_string_json_value
328             ? "{\n"
329               "  \"methodConfig\": [ {\n"
330               "    \"name\": [\n"
331               "      { \"service\": \"service\", \"method\": \"method\" }\n"
332               "    ],\n"
333               "    \"maxResponseMessageBytes\": \"5\"\n"
334               "  } ]\n"
335               "}"
336             : "{\n"
337               "  \"methodConfig\": [ {\n"
338               "    \"name\": [\n"
339               "      { \"service\": \"service\", \"method\": \"method\" }\n"
340               "    ],\n"
341               "    \"maxResponseMessageBytes\": 5\n"
342               "  } ]\n"
343               "}");
344     client_args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
345   } else {
346     // Set limit via channel args.
347     grpc_arg arg;
348     arg.key = send_limit
349                   ? const_cast<char*>(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH)
350                   : const_cast<char*>(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH);
351     arg.type = GRPC_ARG_INTEGER;
352     arg.value.integer = 5;
353     grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
354     if (send_limit) {
355       server_args = args;
356     } else {
357       client_args = args;
358     }
359   }
360 
361   f = begin_test(config, "test_max_response_message_length", client_args,
362                  server_args);
363   {
364     grpc_core::ExecCtx exec_ctx;
365     if (client_args != nullptr) grpc_channel_args_destroy(client_args);
366     if (server_args != nullptr) grpc_channel_args_destroy(server_args);
367   }
368   cqv = cq_verifier_create(f.cq);
369 
370   c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
371                                grpc_slice_from_static_string("/service/method"),
372                                nullptr, gpr_inf_future(GPR_CLOCK_REALTIME),
373                                nullptr);
374   GPR_ASSERT(c);
375 
376   grpc_metadata_array_init(&initial_metadata_recv);
377   grpc_metadata_array_init(&trailing_metadata_recv);
378   grpc_metadata_array_init(&request_metadata_recv);
379   grpc_call_details_init(&call_details);
380 
381   memset(ops, 0, sizeof(ops));
382   op = ops;
383   op->op = GRPC_OP_SEND_INITIAL_METADATA;
384   op->data.send_initial_metadata.count = 0;
385   op->flags = 0;
386   op->reserved = nullptr;
387   op++;
388   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
389   op->flags = 0;
390   op->reserved = nullptr;
391   op++;
392   op->op = GRPC_OP_RECV_INITIAL_METADATA;
393   op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
394   op->flags = 0;
395   op->reserved = nullptr;
396   op++;
397   op->op = GRPC_OP_RECV_MESSAGE;
398   op->data.recv_message.recv_message = &recv_payload;
399   op->flags = 0;
400   op->reserved = nullptr;
401   op++;
402   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
403   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
404   op->data.recv_status_on_client.status = &status;
405   op->data.recv_status_on_client.status_details = &details;
406   op->flags = 0;
407   op->reserved = nullptr;
408   op++;
409   error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
410                                 nullptr);
411   GPR_ASSERT(GRPC_CALL_OK == error);
412 
413   error =
414       grpc_server_request_call(f.server, &s, &call_details,
415                                &request_metadata_recv, f.cq, f.cq, tag(101));
416   GPR_ASSERT(GRPC_CALL_OK == error);
417   CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
418   cq_verify(cqv);
419 
420   memset(ops, 0, sizeof(ops));
421   op = ops;
422   op->op = GRPC_OP_SEND_INITIAL_METADATA;
423   op->data.send_initial_metadata.count = 0;
424   op->flags = 0;
425   op->reserved = nullptr;
426   op++;
427   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
428   op->data.recv_close_on_server.cancelled = &was_cancelled;
429   op->flags = 0;
430   op->reserved = nullptr;
431   op++;
432   op->op = GRPC_OP_SEND_MESSAGE;
433   op->data.send_message.send_message = response_payload;
434   op->flags = 0;
435   op->reserved = nullptr;
436   op++;
437   op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
438   op->data.send_status_from_server.trailing_metadata_count = 0;
439   op->data.send_status_from_server.status = GRPC_STATUS_OK;
440   grpc_slice status_details = grpc_slice_from_static_string("xyz");
441   op->data.send_status_from_server.status_details = &status_details;
442   op->flags = 0;
443   op->reserved = nullptr;
444   op++;
445   error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
446                                 nullptr);
447   GPR_ASSERT(GRPC_CALL_OK == error);
448 
449   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
450   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
451   cq_verify(cqv);
452 
453   GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
454   GPR_ASSERT(status == GRPC_STATUS_RESOURCE_EXHAUSTED);
455   GPR_ASSERT(
456       grpc_slice_str_cmp(
457           details, send_limit
458                        ? "Sent message larger than max (11 vs. 5)"
459                        : "Received message larger than max (11 vs. 5)") == 0);
460 
461   grpc_slice_unref(details);
462   grpc_metadata_array_destroy(&initial_metadata_recv);
463   grpc_metadata_array_destroy(&trailing_metadata_recv);
464   grpc_metadata_array_destroy(&request_metadata_recv);
465   grpc_call_details_destroy(&call_details);
466   grpc_byte_buffer_destroy(response_payload);
467   grpc_byte_buffer_destroy(recv_payload);
468 
469   grpc_call_unref(c);
470   if (s != nullptr) grpc_call_unref(s);
471 
472   cq_verifier_destroy(cqv);
473 
474   end_test(&f);
475   config.tear_down_data(&f);
476 }
477 
max_message_length(grpc_end2end_test_config config)478 void max_message_length(grpc_end2end_test_config config) {
479   test_max_message_length_on_request(config, false /* send_limit */,
480                                      false /* use_service_config */,
481                                      false /* use_string_json_value */);
482   test_max_message_length_on_request(config, true /* send_limit */,
483                                      false /* use_service_config */,
484                                      false /* use_string_json_value */);
485   test_max_message_length_on_response(config, false /* send_limit */,
486                                       false /* use_service_config */,
487                                       false /* use_string_json_value */);
488   test_max_message_length_on_response(config, true /* send_limit */,
489                                       false /* use_service_config */,
490                                       false /* use_string_json_value */);
491   test_max_message_length_on_request(config, true /* send_limit */,
492                                      true /* use_service_config */,
493                                      false /* use_string_json_value */);
494   test_max_message_length_on_request(config, true /* send_limit */,
495                                      true /* use_service_config */,
496                                      true /* use_string_json_value */);
497   test_max_message_length_on_response(config, false /* send_limit */,
498                                       true /* use_service_config */,
499                                       false /* use_string_json_value */);
500   test_max_message_length_on_response(config, false /* send_limit */,
501                                       true /* use_service_config */,
502                                       true /* use_string_json_value */);
503 }
504 
max_message_length_pre_init(void)505 void max_message_length_pre_init(void) {}
506