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