• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2012, 2014 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "failmalloc_test.h"
26 
27 #include <stdio.h>
28 #include <assert.h>
29 
30 #include "munit.h"
31 
32 #include "nghttp2_session.h"
33 #include "nghttp2_stream.h"
34 #include "nghttp2_frame.h"
35 #include "nghttp2_helper.h"
36 #include "malloc_wrapper.h"
37 #include "nghttp2_test_helper.h"
38 
39 static const MunitTest tests[] = {
40     munit_void_test(test_nghttp2_session_send),
41     munit_void_test(test_nghttp2_session_send_server),
42     munit_void_test(test_nghttp2_session_recv),
43     munit_void_test(test_nghttp2_frame),
44     munit_void_test(test_nghttp2_hd),
45     munit_test_end(),
46 };
47 
48 const MunitSuite failmalloc_suite = {
49     "/failmalloc", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE,
50 };
51 
52 typedef struct {
53   uint8_t data[8192];
54   uint8_t *datamark, *datalimit;
55 } data_feed;
56 
57 typedef struct {
58   data_feed *df;
59   size_t data_source_length;
60 } my_user_data;
61 
data_feed_init(data_feed * df,nghttp2_bufs * bufs)62 static void data_feed_init(data_feed *df, nghttp2_bufs *bufs) {
63   nghttp2_buf *buf;
64   size_t data_length;
65 
66   buf = &bufs->head->buf;
67   data_length = nghttp2_buf_len(buf);
68 
69   assert(data_length <= sizeof(df->data));
70   memcpy(df->data, buf->pos, data_length);
71   df->datamark = df->data;
72   df->datalimit = df->data + data_length;
73 }
74 
null_send_callback(nghttp2_session * session,const uint8_t * data,size_t len,int flags,void * user_data)75 static nghttp2_ssize null_send_callback(nghttp2_session *session,
76                                         const uint8_t *data, size_t len,
77                                         int flags, void *user_data) {
78   (void)session;
79   (void)data;
80   (void)flags;
81   (void)user_data;
82 
83   return (nghttp2_ssize)len;
84 }
85 
data_feed_recv_callback(nghttp2_session * session,uint8_t * data,size_t len,int flags,void * user_data)86 static nghttp2_ssize data_feed_recv_callback(nghttp2_session *session,
87                                              uint8_t *data, size_t len,
88                                              int flags, void *user_data) {
89   data_feed *df = ((my_user_data *)user_data)->df;
90   size_t avail = (size_t)(df->datalimit - df->datamark);
91   size_t wlen = nghttp2_min_size(avail, len);
92   (void)session;
93   (void)flags;
94 
95   memcpy(data, df->datamark, wlen);
96   df->datamark += wlen;
97   return (nghttp2_ssize)wlen;
98 }
99 
fixed_length_data_source_read_callback(nghttp2_session * session,int32_t stream_id,uint8_t * buf,size_t len,uint32_t * data_flags,nghttp2_data_source * source,void * user_data)100 static nghttp2_ssize fixed_length_data_source_read_callback(
101     nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t len,
102     uint32_t *data_flags, nghttp2_data_source *source, void *user_data) {
103   my_user_data *ud = (my_user_data *)user_data;
104   size_t wlen;
105   (void)session;
106   (void)stream_id;
107   (void)buf;
108   (void)source;
109 
110   if (len < ud->data_source_length) {
111     wlen = len;
112   } else {
113     wlen = ud->data_source_length;
114   }
115   ud->data_source_length -= wlen;
116   if (ud->data_source_length == 0) {
117     *data_flags = NGHTTP2_DATA_FLAG_EOF;
118   }
119   return (nghttp2_ssize)wlen;
120 }
121 
122 #define TEST_FAILMALLOC_RUN(FUN)                                               \
123   do {                                                                         \
124     int nmalloc, i;                                                            \
125                                                                                \
126     nghttp2_failmalloc = 0;                                                    \
127     nghttp2_nmalloc = 0;                                                       \
128     FUN();                                                                     \
129     nmalloc = nghttp2_nmalloc;                                                 \
130                                                                                \
131     nghttp2_failmalloc = 1;                                                    \
132     for (i = 0; i < nmalloc; ++i) {                                            \
133       nghttp2_nmalloc = 0;                                                     \
134       nghttp2_failstart = i;                                                   \
135       /* printf("i=%zu\n", i); */                                              \
136       FUN();                                                                   \
137       /* printf("nmalloc=%d\n", nghttp2_nmalloc); */                           \
138     }                                                                          \
139     nghttp2_failmalloc = 0;                                                    \
140   } while (0)
141 
run_nghttp2_session_send(void)142 static void run_nghttp2_session_send(void) {
143   nghttp2_session *session;
144   nghttp2_session_callbacks callbacks;
145   nghttp2_nv nv[] = {MAKE_NV(":host", "example.org"),
146                      MAKE_NV(":scheme", "https")};
147   nghttp2_data_provider2 data_prd;
148   nghttp2_settings_entry iv[2];
149   my_user_data ud;
150   int rv;
151   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
152   callbacks.send_callback2 = null_send_callback;
153 
154   data_prd.read_callback = fixed_length_data_source_read_callback;
155   ud.data_source_length = 64 * 1024;
156 
157   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
158   iv[0].value = 4096;
159   iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
160   iv[1].value = 100;
161 
162   rv = nghttp2_session_client_new3(&session, &callbacks, &ud, NULL,
163                                    nghttp2_mem_fm());
164   if (rv != 0) {
165     goto client_new_fail;
166   }
167   rv = nghttp2_submit_request2(session, NULL, nv, ARRLEN(nv), &data_prd, NULL);
168   if (rv < 0) {
169     goto fail;
170   }
171   rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, -1, NULL, nv,
172                               ARRLEN(nv), NULL);
173   if (rv < 0) {
174     goto fail;
175   }
176   rv = nghttp2_session_send(session);
177   if (rv != 0) {
178     goto fail;
179   }
180   /* The HEADERS submitted by the previous nghttp2_submit_headers will
181      have stream ID 3. Send HEADERS to that stream. */
182   rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, 3, NULL, nv,
183                               ARRLEN(nv), NULL);
184   if (rv != 0) {
185     goto fail;
186   }
187   rv = nghttp2_submit_data2(session, NGHTTP2_FLAG_END_STREAM, 3, &data_prd);
188   if (rv != 0) {
189     goto fail;
190   }
191   rv = nghttp2_session_send(session);
192   if (rv != 0) {
193     goto fail;
194   }
195   rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 3, NGHTTP2_CANCEL);
196   if (rv != 0) {
197     goto fail;
198   }
199   rv = nghttp2_session_send(session);
200   if (rv != 0) {
201     goto fail;
202   }
203   rv = nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
204   if (rv != 0) {
205     goto fail;
206   }
207   rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2);
208   if (rv != 0) {
209     goto fail;
210   }
211   rv = nghttp2_session_send(session);
212   if (rv != 0) {
213     goto fail;
214   }
215   rv = nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, 100, NGHTTP2_NO_ERROR,
216                              NULL, 0);
217   if (rv != 0) {
218     goto fail;
219   }
220   rv = nghttp2_session_send(session);
221   if (rv != 0) {
222     goto fail;
223   }
224 
225 fail:
226   nghttp2_session_del(session);
227 client_new_fail:;
228 }
229 
test_nghttp2_session_send(void)230 void test_nghttp2_session_send(void) {
231   TEST_FAILMALLOC_RUN(run_nghttp2_session_send);
232 }
233 
run_nghttp2_session_send_server(void)234 static void run_nghttp2_session_send_server(void) {
235   nghttp2_session *session;
236   nghttp2_session_callbacks *callbacks;
237   int rv;
238   const uint8_t *txdata;
239   nghttp2_ssize txdatalen;
240   const uint8_t origin[] = "nghttp2.org";
241   const uint8_t altsvc_field_value[] = "h2=\":443\"";
242   static const uint8_t nghttp2[] = "https://nghttp2.org";
243   static const nghttp2_origin_entry ov = {
244       (uint8_t *)nghttp2,
245       sizeof(nghttp2) - 1,
246   };
247 
248   rv = nghttp2_session_callbacks_new(&callbacks);
249   if (rv != 0) {
250     return;
251   }
252 
253   rv = nghttp2_session_server_new3(&session, callbacks, NULL, NULL,
254                                    nghttp2_mem_fm());
255 
256   nghttp2_session_callbacks_del(callbacks);
257 
258   if (rv != 0) {
259     return;
260   }
261 
262   rv = nghttp2_submit_altsvc(session, NGHTTP2_FLAG_NONE, 0, origin,
263                              sizeof(origin) - 1, altsvc_field_value,
264                              sizeof(altsvc_field_value) - 1);
265   if (rv != 0) {
266     goto fail;
267   }
268 
269   rv = nghttp2_submit_origin(session, NGHTTP2_FLAG_NONE, &ov, 1);
270   if (rv != 0) {
271     goto fail;
272   }
273 
274   txdatalen = nghttp2_session_mem_send2(session, &txdata);
275 
276   if (txdatalen < 0) {
277     goto fail;
278   }
279 
280 fail:
281   nghttp2_session_del(session);
282 }
283 
test_nghttp2_session_send_server(void)284 void test_nghttp2_session_send_server(void) {
285   TEST_FAILMALLOC_RUN(run_nghttp2_session_send_server);
286 }
287 
run_nghttp2_session_recv(void)288 static void run_nghttp2_session_recv(void) {
289   nghttp2_session *session;
290   nghttp2_session_callbacks callbacks;
291   nghttp2_hd_deflater deflater;
292   nghttp2_frame frame;
293   nghttp2_bufs bufs;
294   nghttp2_nv nv[] = {
295       MAKE_NV(":method", "GET"),
296       MAKE_NV(":scheme", "https"),
297       MAKE_NV(":authority", "example.org"),
298       MAKE_NV(":path", "/"),
299   };
300   nghttp2_settings_entry iv[2];
301   my_user_data ud;
302   data_feed df;
303   int rv;
304   nghttp2_nv *nva;
305   size_t nvlen;
306 
307   rv = frame_pack_bufs_init(&bufs);
308 
309   if (rv != 0) {
310     return;
311   }
312 
313   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
314   callbacks.recv_callback2 = data_feed_recv_callback;
315   ud.df = &df;
316 
317   nghttp2_failmalloc_pause();
318   nghttp2_hd_deflate_init(&deflater, nghttp2_mem_fm());
319   nghttp2_session_server_new3(&session, &callbacks, &ud, NULL,
320                               nghttp2_mem_fm());
321 
322   /* Client preface */
323   nghttp2_bufs_add(&bufs, NGHTTP2_CLIENT_MAGIC, NGHTTP2_CLIENT_MAGIC_LEN);
324   data_feed_init(&df, &bufs);
325   nghttp2_bufs_reset(&bufs);
326   nghttp2_failmalloc_unpause();
327 
328   rv = nghttp2_session_recv(session);
329   if (rv != 0) {
330     goto fail;
331   }
332 
333   nghttp2_failmalloc_pause();
334   /* SETTINGS */
335   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
336   iv[0].value = 4096;
337   iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
338   iv[1].value = 100;
339   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE,
340                               nghttp2_frame_iv_copy(iv, 2, nghttp2_mem_fm()),
341                               2);
342   nghttp2_frame_pack_settings(&bufs, &frame.settings);
343   nghttp2_frame_settings_free(&frame.settings, nghttp2_mem_fm());
344   data_feed_init(&df, &bufs);
345   nghttp2_bufs_reset(&bufs);
346   nghttp2_failmalloc_unpause();
347 
348   rv = nghttp2_session_recv(session);
349   if (rv != 0) {
350     goto fail;
351   }
352 
353   nghttp2_failmalloc_pause();
354   /* HEADERS */
355   nvlen = ARRLEN(nv);
356   nghttp2_nv_array_copy(&nva, nv, nvlen, nghttp2_mem_fm());
357   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_STREAM, 1,
358                              NGHTTP2_HCAT_REQUEST, NULL, nva, nvlen);
359   nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
360   nghttp2_frame_headers_free(&frame.headers, nghttp2_mem_fm());
361   data_feed_init(&df, &bufs);
362   nghttp2_bufs_reset(&bufs);
363   nghttp2_failmalloc_unpause();
364 
365   rv = nghttp2_session_recv(session);
366   if (rv != 0) {
367     goto fail;
368   }
369 
370   /* PING */
371   nghttp2_failmalloc_pause();
372   nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
373   nghttp2_frame_pack_ping(&bufs, &frame.ping);
374   nghttp2_frame_ping_free(&frame.ping);
375   data_feed_init(&df, &bufs);
376   nghttp2_bufs_reset(&bufs);
377 
378   nghttp2_failmalloc_unpause();
379 
380   rv = nghttp2_session_recv(session);
381   if (rv != 0) {
382     goto fail;
383   }
384 
385   /* RST_STREAM */
386   nghttp2_failmalloc_pause();
387   nghttp2_frame_rst_stream_init(&frame.rst_stream, 1, NGHTTP2_PROTOCOL_ERROR);
388   nghttp2_frame_pack_rst_stream(&bufs, &frame.rst_stream);
389   nghttp2_frame_rst_stream_free(&frame.rst_stream);
390   nghttp2_bufs_reset(&bufs);
391 
392   nghttp2_failmalloc_unpause();
393 
394   rv = nghttp2_session_recv(session);
395   if (rv != 0) {
396     goto fail;
397   }
398 
399 fail:
400   nghttp2_bufs_free(&bufs);
401   nghttp2_session_del(session);
402   nghttp2_hd_deflate_free(&deflater);
403 }
404 
test_nghttp2_session_recv(void)405 void test_nghttp2_session_recv(void) {
406   TEST_FAILMALLOC_RUN(run_nghttp2_session_recv);
407 }
408 
run_nghttp2_frame_pack_headers(void)409 static void run_nghttp2_frame_pack_headers(void) {
410   nghttp2_hd_deflater deflater;
411   nghttp2_hd_inflater inflater;
412   nghttp2_frame frame, oframe;
413   nghttp2_bufs bufs;
414   nghttp2_nv nv[] = {MAKE_NV(":host", "example.org"),
415                      MAKE_NV(":scheme", "https")};
416   int rv;
417   nghttp2_nv *nva;
418   size_t nvlen;
419 
420   rv = frame_pack_bufs_init(&bufs);
421 
422   if (rv != 0) {
423     return;
424   }
425 
426   rv = nghttp2_hd_deflate_init(&deflater, nghttp2_mem_fm());
427   if (rv != 0) {
428     goto deflate_init_fail;
429   }
430   rv = nghttp2_hd_inflate_init(&inflater, nghttp2_mem_fm());
431   if (rv != 0) {
432     goto inflate_init_fail;
433   }
434   nvlen = ARRLEN(nv);
435   rv = nghttp2_nv_array_copy(&nva, nv, nvlen, nghttp2_mem_fm());
436   if (rv < 0) {
437     goto nv_copy_fail;
438   }
439   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_STREAM, 1,
440                              NGHTTP2_HCAT_REQUEST, NULL, nva, nvlen);
441   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
442   if (rv != 0) {
443     goto fail;
444   }
445   rv = unpack_framebuf(&oframe, &bufs);
446   if (rv != 0) {
447     goto fail;
448   }
449   nghttp2_frame_headers_free(&oframe.headers, nghttp2_mem_fm());
450 
451 fail:
452   nghttp2_frame_headers_free(&frame.headers, nghttp2_mem_fm());
453 nv_copy_fail:
454   nghttp2_hd_inflate_free(&inflater);
455 inflate_init_fail:
456   nghttp2_hd_deflate_free(&deflater);
457 deflate_init_fail:
458   nghttp2_bufs_free(&bufs);
459 }
460 
run_nghttp2_frame_pack_settings(void)461 static void run_nghttp2_frame_pack_settings(void) {
462   nghttp2_frame frame, oframe;
463   nghttp2_bufs bufs;
464   nghttp2_buf *buf;
465   nghttp2_settings_entry iv[2], *iv_copy;
466   int rv;
467 
468   rv = frame_pack_bufs_init(&bufs);
469 
470   if (rv != 0) {
471     return;
472   }
473 
474   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
475   iv[0].value = 4096;
476   iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
477   iv[1].value = 100;
478 
479   iv_copy = nghttp2_frame_iv_copy(iv, 2, nghttp2_mem_fm());
480 
481   if (iv_copy == NULL) {
482     goto iv_copy_fail;
483   }
484 
485   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, iv_copy, 2);
486 
487   rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
488 
489   if (rv != 0) {
490     goto fail;
491   }
492 
493   buf = &bufs.head->buf;
494 
495   rv = nghttp2_frame_unpack_settings_payload2(
496       &oframe.settings.iv, &oframe.settings.niv, buf->pos + NGHTTP2_FRAME_HDLEN,
497       nghttp2_buf_len(buf) - NGHTTP2_FRAME_HDLEN, nghttp2_mem_fm());
498 
499   if (rv != 0) {
500     goto fail;
501   }
502   nghttp2_frame_settings_free(&oframe.settings, nghttp2_mem_fm());
503 
504 fail:
505   nghttp2_frame_settings_free(&frame.settings, nghttp2_mem_fm());
506 iv_copy_fail:
507   nghttp2_bufs_free(&bufs);
508 }
509 
test_nghttp2_frame(void)510 void test_nghttp2_frame(void) {
511   TEST_FAILMALLOC_RUN(run_nghttp2_frame_pack_headers);
512   TEST_FAILMALLOC_RUN(run_nghttp2_frame_pack_settings);
513 }
514 
deflate_inflate(nghttp2_hd_deflater * deflater,nghttp2_hd_inflater * inflater,nghttp2_bufs * bufs,nghttp2_nv * nva,size_t nvlen,nghttp2_mem * mem)515 static int deflate_inflate(nghttp2_hd_deflater *deflater,
516                            nghttp2_hd_inflater *inflater, nghttp2_bufs *bufs,
517                            nghttp2_nv *nva, size_t nvlen, nghttp2_mem *mem) {
518   int rv;
519 
520   rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, nva, nvlen);
521 
522   if (rv != 0) {
523     return rv;
524   }
525 
526   rv = (int)inflate_hd(inflater, NULL, bufs, 0, mem);
527 
528   if (rv < 0) {
529     return rv;
530   }
531 
532   nghttp2_bufs_reset(bufs);
533 
534   return 0;
535 }
536 
run_nghttp2_hd(void)537 static void run_nghttp2_hd(void) {
538   nghttp2_hd_deflater deflater;
539   nghttp2_hd_inflater inflater;
540   nghttp2_bufs bufs;
541   int rv;
542   nghttp2_nv nva1[] = {
543       MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
544       MAKE_NV(":path", "/slashdot"),
545       MAKE_NV("accept-encoding", "gzip, deflate"), MAKE_NV("foo", "bar")};
546   nghttp2_nv nva2[] = {
547       MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
548       MAKE_NV(":path", "/style.css"), MAKE_NV("cookie", "nghttp2=FTW"),
549       MAKE_NV("foo", "bar2")};
550 
551   rv = frame_pack_bufs_init(&bufs);
552 
553   if (rv != 0) {
554     return;
555   }
556 
557   rv = nghttp2_hd_deflate_init(&deflater, nghttp2_mem_fm());
558 
559   if (rv != 0) {
560     goto deflate_init_fail;
561   }
562 
563   rv = nghttp2_hd_inflate_init(&inflater, nghttp2_mem_fm());
564 
565   if (rv != 0) {
566     goto inflate_init_fail;
567   }
568 
569   rv = deflate_inflate(&deflater, &inflater, &bufs, nva1, ARRLEN(nva1),
570                        nghttp2_mem_fm());
571 
572   if (rv != 0) {
573     goto deflate_hd_fail;
574   }
575 
576   rv = deflate_inflate(&deflater, &inflater, &bufs, nva2, ARRLEN(nva2),
577                        nghttp2_mem_fm());
578 
579   if (rv != 0) {
580     goto deflate_hd_fail;
581   }
582 
583 deflate_hd_fail:
584   nghttp2_hd_inflate_free(&inflater);
585 inflate_init_fail:
586   nghttp2_hd_deflate_free(&deflater);
587 deflate_init_fail:
588   nghttp2_bufs_free(&bufs);
589 }
590 
test_nghttp2_hd(void)591 void test_nghttp2_hd(void) { TEST_FAILMALLOC_RUN(run_nghttp2_hd); }
592