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 <CUnit/CUnit.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 39typedef struct { 40 uint8_t data[8192]; 41 uint8_t *datamark, *datalimit; 42} data_feed; 43 44typedef struct { 45 data_feed *df; 46 size_t data_source_length; 47} my_user_data; 48 49static 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 62static 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 72static 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 85static 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 127static 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 210fail: 211 nghttp2_session_del(session); 212client_new_fail:; 213} 214 215void test_nghttp2_session_send(void) { 216 TEST_FAILMALLOC_RUN(run_nghttp2_session_send); 217} 218 219static 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 265fail: 266 nghttp2_session_del(session); 267} 268 269void test_nghttp2_session_send_server(void) { 270 TEST_FAILMALLOC_RUN(run_nghttp2_session_send_server); 271} 272 273static 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 384fail: 385 nghttp2_bufs_free(&bufs); 386 nghttp2_session_del(session); 387 nghttp2_hd_deflate_free(&deflater); 388} 389 390void test_nghttp2_session_recv(void) { 391 TEST_FAILMALLOC_RUN(run_nghttp2_session_recv); 392} 393 394static 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 436fail: 437 nghttp2_frame_headers_free(&frame.headers, nghttp2_mem_fm()); 438nv_copy_fail: 439 nghttp2_hd_inflate_free(&inflater); 440inflate_init_fail: 441 nghttp2_hd_deflate_free(&deflater); 442deflate_init_fail: 443 nghttp2_bufs_free(&bufs); 444} 445 446static 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 489fail: 490 nghttp2_frame_settings_free(&frame.settings, nghttp2_mem_fm()); 491iv_copy_fail: 492 nghttp2_bufs_free(&bufs); 493} 494 495void test_nghttp2_frame(void) { 496 TEST_FAILMALLOC_RUN(run_nghttp2_frame_pack_headers); 497 TEST_FAILMALLOC_RUN(run_nghttp2_frame_pack_settings); 498} 499 500static 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 522static 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 568deflate_hd_fail: 569 nghttp2_hd_inflate_free(&inflater); 570inflate_init_fail: 571 nghttp2_hd_deflate_free(&deflater); 572deflate_init_fail: 573 nghttp2_bufs_free(&bufs); 574} 575 576void test_nghttp2_hd(void) { TEST_FAILMALLOC_RUN(run_nghttp2_hd); } 577