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 <CUnit/CUnit.h>
28 
29 #include <stdio.h>
30 #include <assert.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 typedef struct {
40   uint8_t data[8192];
41   uint8_t *datamark, *datalimit;
42 } data_feed;
43 
44 typedef struct {
45   data_feed *df;
46   size_t data_source_length;
47 } my_user_data;
48 
data_feed_init(data_feed * df,nghttp2_bufs * bufs)49 static void data_feed_init(data_feed *df, nghttp2_bufs *bufs) {
50   nghttp2_buf *buf;
51   size_t data_length;
52 
53   buf = &bufs->head->buf;
54   data_length = nghttp2_buf_len(buf);
55 
56   assert(data_length <= sizeof(df->data));
57   memcpy(df->data, buf->pos, data_length);
58   df->datamark = df->data;
59   df->datalimit = df->data + data_length;
60 }
61 
null_send_callback(nghttp2_session * session,const uint8_t * data,size_t len,int flags,void * user_data)62 static ssize_t null_send_callback(nghttp2_session *session, const uint8_t *data,
63                                   size_t len, int flags, void *user_data) {
64   (void)session;
65   (void)data;
66   (void)flags;
67   (void)user_data;
68 
69   return (ssize_t)len;
70 }
71 
data_feed_recv_callback(nghttp2_session * session,uint8_t * data,size_t len,int flags,void * user_data)72 static ssize_t data_feed_recv_callback(nghttp2_session *session, uint8_t *data,
73                                        size_t len, int flags, void *user_data) {
74   data_feed *df = ((my_user_data *)user_data)->df;
75   size_t avail = (size_t)(df->datalimit - df->datamark);
76   size_t wlen = nghttp2_min(avail, len);
77   (void)session;
78   (void)flags;
79 
80   memcpy(data, df->datamark, wlen);
81   df->datamark += wlen;
82   return (ssize_t)wlen;
83 }
84 
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)85 static ssize_t fixed_length_data_source_read_callback(
86     nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t len,
87     uint32_t *data_flags, nghttp2_data_source *source, void *user_data) {
88   my_user_data *ud = (my_user_data *)user_data;
89   size_t wlen;
90   (void)session;
91   (void)stream_id;
92   (void)buf;
93   (void)source;
94 
95   if (len < ud->data_source_length) {
96     wlen = len;
97   } else {
98     wlen = ud->data_source_length;
99   }
100   ud->data_source_length -= wlen;
101   if (ud->data_source_length == 0) {
102     *data_flags = NGHTTP2_DATA_FLAG_EOF;
103   }
104   return (ssize_t)wlen;
105 }
106 
107 #define TEST_FAILMALLOC_RUN(FUN)                                               \
108   do {                                                                         \
109     int nmalloc, i;                                                            \
110                                                                                \
111     nghttp2_failmalloc = 0;                                                    \
112     nghttp2_nmalloc = 0;                                                       \
113     FUN();                                                                     \
114     nmalloc = nghttp2_nmalloc;                                                 \
115                                                                                \
116     nghttp2_failmalloc = 1;                                                    \
117     for (i = 0; i < nmalloc; ++i) {                                            \
118       nghttp2_nmalloc = 0;                                                     \
119       nghttp2_failstart = i;                                                   \
120       /* printf("i=%zu\n", i); */                                              \
121       FUN();                                                                   \
122       /* printf("nmalloc=%d\n", nghttp2_nmalloc); */                           \
123     }                                                                          \
124     nghttp2_failmalloc = 0;                                                    \
125   } while (0)
126 
run_nghttp2_session_send(void)127 static void run_nghttp2_session_send(void) {
128   nghttp2_session *session;
129   nghttp2_session_callbacks callbacks;
130   nghttp2_nv nv[] = {MAKE_NV(":host", "example.org"),
131                      MAKE_NV(":scheme", "https")};
132   nghttp2_data_provider data_prd;
133   nghttp2_settings_entry iv[2];
134   my_user_data ud;
135   int rv;
136   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
137   callbacks.send_callback = null_send_callback;
138 
139   data_prd.read_callback = fixed_length_data_source_read_callback;
140   ud.data_source_length = 64 * 1024;
141 
142   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
143   iv[0].value = 4096;
144   iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
145   iv[1].value = 100;
146 
147   rv = nghttp2_session_client_new3(&session, &callbacks, &ud, NULL,
148                                    nghttp2_mem_fm());
149   if (rv != 0) {
150     goto client_new_fail;
151   }
152   rv = nghttp2_submit_request(session, NULL, nv, ARRLEN(nv), &data_prd, NULL);
153   if (rv < 0) {
154     goto fail;
155   }
156   rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, -1, NULL, nv,
157                               ARRLEN(nv), NULL);
158   if (rv < 0) {
159     goto fail;
160   }
161   rv = nghttp2_session_send(session);
162   if (rv != 0) {
163     goto fail;
164   }
165   /* The HEADERS submitted by the previous nghttp2_submit_headers will
166      have stream ID 3. Send HEADERS to that stream. */
167   rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, 3, NULL, nv,
168                               ARRLEN(nv), NULL);
169   if (rv != 0) {
170     goto fail;
171   }
172   rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 3, &data_prd);
173   if (rv != 0) {
174     goto fail;
175   }
176   rv = nghttp2_session_send(session);
177   if (rv != 0) {
178     goto fail;
179   }
180   rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 3, NGHTTP2_CANCEL);
181   if (rv != 0) {
182     goto fail;
183   }
184   rv = nghttp2_session_send(session);
185   if (rv != 0) {
186     goto fail;
187   }
188   rv = nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
189   if (rv != 0) {
190     goto fail;
191   }
192   rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2);
193   if (rv != 0) {
194     goto fail;
195   }
196   rv = nghttp2_session_send(session);
197   if (rv != 0) {
198     goto fail;
199   }
200   rv = nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, 100, NGHTTP2_NO_ERROR,
201                              NULL, 0);
202   if (rv != 0) {
203     goto fail;
204   }
205   rv = nghttp2_session_send(session);
206   if (rv != 0) {
207     goto fail;
208   }
209 
210 fail:
211   nghttp2_session_del(session);
212 client_new_fail:;
213 }
214 
test_nghttp2_session_send(void)215 void test_nghttp2_session_send(void) {
216   TEST_FAILMALLOC_RUN(run_nghttp2_session_send);
217 }
218 
run_nghttp2_session_send_server(void)219 static void run_nghttp2_session_send_server(void) {
220   nghttp2_session *session;
221   nghttp2_session_callbacks *callbacks;
222   int rv;
223   const uint8_t *txdata;
224   ssize_t txdatalen;
225   const uint8_t origin[] = "nghttp2.org";
226   const uint8_t altsvc_field_value[] = "h2=\":443\"";
227   static const uint8_t nghttp2[] = "https://nghttp2.org";
228   static const nghttp2_origin_entry ov = {
229       (uint8_t *)nghttp2,
230       sizeof(nghttp2) - 1,
231   };
232 
233   rv = nghttp2_session_callbacks_new(&callbacks);
234   if (rv != 0) {
235     return;
236   }
237 
238   rv = nghttp2_session_server_new3(&session, callbacks, NULL, NULL,
239                                    nghttp2_mem_fm());
240 
241   nghttp2_session_callbacks_del(callbacks);
242 
243   if (rv != 0) {
244     return;
245   }
246 
247   rv = nghttp2_submit_altsvc(session, NGHTTP2_FLAG_NONE, 0, origin,
248                              sizeof(origin) - 1, altsvc_field_value,
249                              sizeof(altsvc_field_value) - 1);
250   if (rv != 0) {
251     goto fail;
252   }
253 
254   rv = nghttp2_submit_origin(session, NGHTTP2_FLAG_NONE, &ov, 1);
255   if (rv != 0) {
256     goto fail;
257   }
258 
259   txdatalen = nghttp2_session_mem_send(session, &txdata);
260 
261   if (txdatalen < 0) {
262     goto fail;
263   }
264 
265 fail:
266   nghttp2_session_del(session);
267 }
268 
test_nghttp2_session_send_server(void)269 void test_nghttp2_session_send_server(void) {
270   TEST_FAILMALLOC_RUN(run_nghttp2_session_send_server);
271 }
272 
run_nghttp2_session_recv(void)273 static void run_nghttp2_session_recv(void) {
274   nghttp2_session *session;
275   nghttp2_session_callbacks callbacks;
276   nghttp2_hd_deflater deflater;
277   nghttp2_frame frame;
278   nghttp2_bufs bufs;
279   nghttp2_nv nv[] = {
280       MAKE_NV(":method", "GET"),
281       MAKE_NV(":scheme", "https"),
282       MAKE_NV(":authority", "example.org"),
283       MAKE_NV(":path", "/"),
284   };
285   nghttp2_settings_entry iv[2];
286   my_user_data ud;
287   data_feed df;
288   int rv;
289   nghttp2_nv *nva;
290   size_t nvlen;
291 
292   rv = frame_pack_bufs_init(&bufs);
293 
294   if (rv != 0) {
295     return;
296   }
297 
298   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
299   callbacks.recv_callback = data_feed_recv_callback;
300   ud.df = &df;
301 
302   nghttp2_failmalloc_pause();
303   nghttp2_hd_deflate_init(&deflater, nghttp2_mem_fm());
304   nghttp2_session_server_new3(&session, &callbacks, &ud, NULL,
305                               nghttp2_mem_fm());
306 
307   /* Client preface */
308   nghttp2_bufs_add(&bufs, NGHTTP2_CLIENT_MAGIC, NGHTTP2_CLIENT_MAGIC_LEN);
309   data_feed_init(&df, &bufs);
310   nghttp2_bufs_reset(&bufs);
311   nghttp2_failmalloc_unpause();
312 
313   rv = nghttp2_session_recv(session);
314   if (rv != 0) {
315     goto fail;
316   }
317 
318   nghttp2_failmalloc_pause();
319   /* SETTINGS */
320   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
321   iv[0].value = 4096;
322   iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
323   iv[1].value = 100;
324   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE,
325                               nghttp2_frame_iv_copy(iv, 2, nghttp2_mem_fm()),
326                               2);
327   nghttp2_frame_pack_settings(&bufs, &frame.settings);
328   nghttp2_frame_settings_free(&frame.settings, nghttp2_mem_fm());
329   data_feed_init(&df, &bufs);
330   nghttp2_bufs_reset(&bufs);
331   nghttp2_failmalloc_unpause();
332 
333   rv = nghttp2_session_recv(session);
334   if (rv != 0) {
335     goto fail;
336   }
337 
338   nghttp2_failmalloc_pause();
339   /* HEADERS */
340   nvlen = ARRLEN(nv);
341   nghttp2_nv_array_copy(&nva, nv, nvlen, nghttp2_mem_fm());
342   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_STREAM, 1,
343                              NGHTTP2_HCAT_REQUEST, NULL, nva, nvlen);
344   nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
345   nghttp2_frame_headers_free(&frame.headers, nghttp2_mem_fm());
346   data_feed_init(&df, &bufs);
347   nghttp2_bufs_reset(&bufs);
348   nghttp2_failmalloc_unpause();
349 
350   rv = nghttp2_session_recv(session);
351   if (rv != 0) {
352     goto fail;
353   }
354 
355   /* PING */
356   nghttp2_failmalloc_pause();
357   nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
358   nghttp2_frame_pack_ping(&bufs, &frame.ping);
359   nghttp2_frame_ping_free(&frame.ping);
360   data_feed_init(&df, &bufs);
361   nghttp2_bufs_reset(&bufs);
362 
363   nghttp2_failmalloc_unpause();
364 
365   rv = nghttp2_session_recv(session);
366   if (rv != 0) {
367     goto fail;
368   }
369 
370   /* RST_STREAM */
371   nghttp2_failmalloc_pause();
372   nghttp2_frame_rst_stream_init(&frame.rst_stream, 1, NGHTTP2_PROTOCOL_ERROR);
373   nghttp2_frame_pack_rst_stream(&bufs, &frame.rst_stream);
374   nghttp2_frame_rst_stream_free(&frame.rst_stream);
375   nghttp2_bufs_reset(&bufs);
376 
377   nghttp2_failmalloc_unpause();
378 
379   rv = nghttp2_session_recv(session);
380   if (rv != 0) {
381     goto fail;
382   }
383 
384 fail:
385   nghttp2_bufs_free(&bufs);
386   nghttp2_session_del(session);
387   nghttp2_hd_deflate_free(&deflater);
388 }
389 
test_nghttp2_session_recv(void)390 void test_nghttp2_session_recv(void) {
391   TEST_FAILMALLOC_RUN(run_nghttp2_session_recv);
392 }
393 
run_nghttp2_frame_pack_headers(void)394 static void run_nghttp2_frame_pack_headers(void) {
395   nghttp2_hd_deflater deflater;
396   nghttp2_hd_inflater inflater;
397   nghttp2_frame frame, oframe;
398   nghttp2_bufs bufs;
399   nghttp2_nv nv[] = {MAKE_NV(":host", "example.org"),
400                      MAKE_NV(":scheme", "https")};
401   int rv;
402   nghttp2_nv *nva;
403   size_t nvlen;
404 
405   rv = frame_pack_bufs_init(&bufs);
406 
407   if (rv != 0) {
408     return;
409   }
410 
411   rv = nghttp2_hd_deflate_init(&deflater, nghttp2_mem_fm());
412   if (rv != 0) {
413     goto deflate_init_fail;
414   }
415   rv = nghttp2_hd_inflate_init(&inflater, nghttp2_mem_fm());
416   if (rv != 0) {
417     goto inflate_init_fail;
418   }
419   nvlen = ARRLEN(nv);
420   rv = nghttp2_nv_array_copy(&nva, nv, nvlen, nghttp2_mem_fm());
421   if (rv < 0) {
422     goto nv_copy_fail;
423   }
424   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_STREAM, 1,
425                              NGHTTP2_HCAT_REQUEST, NULL, nva, nvlen);
426   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
427   if (rv != 0) {
428     goto fail;
429   }
430   rv = unpack_framebuf(&oframe, &bufs);
431   if (rv != 0) {
432     goto fail;
433   }
434   nghttp2_frame_headers_free(&oframe.headers, nghttp2_mem_fm());
435 
436 fail:
437   nghttp2_frame_headers_free(&frame.headers, nghttp2_mem_fm());
438 nv_copy_fail:
439   nghttp2_hd_inflate_free(&inflater);
440 inflate_init_fail:
441   nghttp2_hd_deflate_free(&deflater);
442 deflate_init_fail:
443   nghttp2_bufs_free(&bufs);
444 }
445 
run_nghttp2_frame_pack_settings(void)446 static void run_nghttp2_frame_pack_settings(void) {
447   nghttp2_frame frame, oframe;
448   nghttp2_bufs bufs;
449   nghttp2_buf *buf;
450   nghttp2_settings_entry iv[2], *iv_copy;
451   int rv;
452 
453   rv = frame_pack_bufs_init(&bufs);
454 
455   if (rv != 0) {
456     return;
457   }
458 
459   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
460   iv[0].value = 4096;
461   iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
462   iv[1].value = 100;
463 
464   iv_copy = nghttp2_frame_iv_copy(iv, 2, nghttp2_mem_fm());
465 
466   if (iv_copy == NULL) {
467     goto iv_copy_fail;
468   }
469 
470   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, iv_copy, 2);
471 
472   rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
473 
474   if (rv != 0) {
475     goto fail;
476   }
477 
478   buf = &bufs.head->buf;
479 
480   rv = nghttp2_frame_unpack_settings_payload2(
481       &oframe.settings.iv, &oframe.settings.niv, buf->pos + NGHTTP2_FRAME_HDLEN,
482       nghttp2_buf_len(buf) - NGHTTP2_FRAME_HDLEN, nghttp2_mem_fm());
483 
484   if (rv != 0) {
485     goto fail;
486   }
487   nghttp2_frame_settings_free(&oframe.settings, nghttp2_mem_fm());
488 
489 fail:
490   nghttp2_frame_settings_free(&frame.settings, nghttp2_mem_fm());
491 iv_copy_fail:
492   nghttp2_bufs_free(&bufs);
493 }
494 
test_nghttp2_frame(void)495 void test_nghttp2_frame(void) {
496   TEST_FAILMALLOC_RUN(run_nghttp2_frame_pack_headers);
497   TEST_FAILMALLOC_RUN(run_nghttp2_frame_pack_settings);
498 }
499 
deflate_inflate(nghttp2_hd_deflater * deflater,nghttp2_hd_inflater * inflater,nghttp2_bufs * bufs,nghttp2_nv * nva,size_t nvlen,nghttp2_mem * mem)500 static int deflate_inflate(nghttp2_hd_deflater *deflater,
501                            nghttp2_hd_inflater *inflater, nghttp2_bufs *bufs,
502                            nghttp2_nv *nva, size_t nvlen, nghttp2_mem *mem) {
503   int rv;
504 
505   rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, nva, nvlen);
506 
507   if (rv != 0) {
508     return rv;
509   }
510 
511   rv = (int)inflate_hd(inflater, NULL, bufs, 0, mem);
512 
513   if (rv < 0) {
514     return rv;
515   }
516 
517   nghttp2_bufs_reset(bufs);
518 
519   return 0;
520 }
521 
run_nghttp2_hd(void)522 static void run_nghttp2_hd(void) {
523   nghttp2_hd_deflater deflater;
524   nghttp2_hd_inflater inflater;
525   nghttp2_bufs bufs;
526   int rv;
527   nghttp2_nv nva1[] = {
528       MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
529       MAKE_NV(":path", "/slashdot"),
530       MAKE_NV("accept-encoding", "gzip, deflate"), MAKE_NV("foo", "bar")};
531   nghttp2_nv nva2[] = {
532       MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
533       MAKE_NV(":path", "/style.css"), MAKE_NV("cookie", "nghttp2=FTW"),
534       MAKE_NV("foo", "bar2")};
535 
536   rv = frame_pack_bufs_init(&bufs);
537 
538   if (rv != 0) {
539     return;
540   }
541 
542   rv = nghttp2_hd_deflate_init(&deflater, nghttp2_mem_fm());
543 
544   if (rv != 0) {
545     goto deflate_init_fail;
546   }
547 
548   rv = nghttp2_hd_inflate_init(&inflater, nghttp2_mem_fm());
549 
550   if (rv != 0) {
551     goto inflate_init_fail;
552   }
553 
554   rv = deflate_inflate(&deflater, &inflater, &bufs, nva1, ARRLEN(nva1),
555                        nghttp2_mem_fm());
556 
557   if (rv != 0) {
558     goto deflate_hd_fail;
559   }
560 
561   rv = deflate_inflate(&deflater, &inflater, &bufs, nva2, ARRLEN(nva2),
562                        nghttp2_mem_fm());
563 
564   if (rv != 0) {
565     goto deflate_hd_fail;
566   }
567 
568 deflate_hd_fail:
569   nghttp2_hd_inflate_free(&inflater);
570 inflate_init_fail:
571   nghttp2_hd_deflate_free(&deflater);
572 deflate_init_fail:
573   nghttp2_bufs_free(&bufs);
574 }
575 
test_nghttp2_hd(void)576 void test_nghttp2_hd(void) { TEST_FAILMALLOC_RUN(run_nghttp2_hd); }
577