From 94263216fb432c2c1f331843fa289f7629d47a4b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 11 Sep 2013 00:55:35 +0900 Subject: [PATCH] Add nghttp2_submit_request2 This function is similar to nghttp2_submit_request and the difference is it takes an array of nghttp2_nv as name/value pairs. It is useful if name/value pairs is not NULL-terminated in the application code. --- lib/includes/nghttp2/nghttp2.h | 26 +++++ lib/nghttp2_frame.c | 54 ++++++++++ lib/nghttp2_frame.h | 30 +++++- lib/nghttp2_submit.c | 179 ++++++++++++++++++++++----------- tests/main.c | 7 ++ tests/nghttp2_frame_test.c | 59 +++++++++++ tests/nghttp2_frame_test.h | 2 + tests/nghttp2_hd_test.c | 5 +- tests/nghttp2_session_test.c | 56 +++++++++++ tests/nghttp2_session_test.h | 2 + tests/nghttp2_test_helper.h | 4 + 11 files changed, 357 insertions(+), 67 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index a5ce70cb..fccf5ce8 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -1568,6 +1568,10 @@ const char* nghttp2_strerror(int lib_error_code); * This function creates copies of all name/value pairs in |nv|. It * also lower-cases all names in |nv|. * + * The string in |nv| must be NULL-terminated. Use + * `nghttp2_submit_request2()` if name/value pairs are not + * NULL-terminated strings. + * * If |data_prd| is not ``NULL``, it provides data which will be sent * in subsequent DATA frames. In this case, a method that allows * request message bodies @@ -1606,6 +1610,28 @@ int nghttp2_submit_request(nghttp2_session *session, int32_t pri, const nghttp2_data_provider *data_prd, void *stream_user_data); +/** + * @function + * + * Just like `nghttp2_submit_request()`, but this function takes the + * |nva|, which is an array of ``nghttp2_nv`` with |nvlen| elements, + * as name/value pairs. This function is useful if name/value pairs + * are not NULL-terminated strings. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The |pri| is invalid; or the |nva| includes empty name or + * name which contains invalid characters. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +int nghttp2_submit_request2(nghttp2_session *session, int32_t pri, + const nghttp2_nv *nva, size_t nvlen, + const nghttp2_data_provider *data_prd, + void *stream_user_data); + /** * @function * diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index 305174cf..0809fb42 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -597,6 +597,17 @@ int nghttp2_frame_nv_check_null(const char **nv) return 1; } +int nghttp2_nv_array_check_null(const nghttp2_nv *nva, size_t nvlen) +{ + size_t i; + for(i = 0; i < nvlen; ++i) { + if(!nghttp2_check_header_name_nocase(nva[i].name, nva[i].namelen)) { + return 0; + } + } + return 1; +} + int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) { return a->namelen == b->namelen && a->valuelen == b->valuelen && @@ -686,6 +697,49 @@ ssize_t nghttp2_nv_array_from_cstr(nghttp2_nv **nva_ptr, const char **nv) return nvlen; } +ssize_t nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, + const nghttp2_nv *nva, size_t nvlen) +{ + size_t i; + uint8_t *data; + size_t buflen = 0; + nghttp2_nv *p; + for(i = 0; i < nvlen; ++i) { + if(nva[i].namelen > NGHTTP2_MAX_HD_VALUE_LENGTH || + nva[i].valuelen > NGHTTP2_MAX_HD_VALUE_LENGTH) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + buflen += nva[i].namelen + nva[i].valuelen; + } + /* If all name/value pair is 0-length, remove them */ + if(nvlen == 0 || buflen == 0) { + *nva_ptr = NULL; + return 0; + } + buflen += sizeof(nghttp2_nv)*nvlen; + *nva_ptr = malloc(buflen); + if(*nva_ptr == NULL) { + return NGHTTP2_ERR_NOMEM; + } + p = *nva_ptr; + data = (uint8_t*)(*nva_ptr) + sizeof(nghttp2_nv)*nvlen; + + for(i = 0; i < nvlen; ++i) { + memcpy(data, nva[i].name, nva[i].namelen); + p->name = data; + p->namelen = nva[i].namelen; + nghttp2_downcase(p->name, p->namelen); + data += nva[i].namelen; + memcpy(data, nva[i].value, nva[i].valuelen); + p->value = data; + p->valuelen = nva[i].valuelen; + data += nva[i].valuelen; + ++p; + } + nghttp2_nv_array_sort(*nva_ptr, nvlen); + return nvlen; +} + int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv, int32_t flow_control_opt) { diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 22ca55d7..d8517f4d 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -536,17 +536,38 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen); * Copies name/value pairs from |nv| to |*nva_ptr|, which is * dynamically allocated so that all items can be stored. * + * The |*nva_ptr| must be freed using nghttp2_nv_array_del(). + * * This function returns the number of name/value pairs in |*nva_ptr|, * or one of the following negative error codes: * * NGHTTP2_ERR_NOMEM * Out of memory. * NGHTTP2_ERR_INVALID_ARGUMENT - * The length of name or value in |nv| is strictly larger than (1 - * << 16) - 1. + * The length of name or value in |nv| is strictly larger than + * NGHTTP2_MAX_HD_VALUE_LENGTH. */ ssize_t nghttp2_nv_array_from_cstr(nghttp2_nv **nva_ptr, const char **nv); +/* + * Copies name/value pairs from |nva|, which contains |nvlen| pairs, + * to |*nva_ptr|, which is dynamically allocated so that all items can + * be stored. + * + * The |*nva_ptr| must be freed using nghttp2_nv_array_del(). + * + * This function returns the number of name/value pairs in |*nva_ptr|, + * or one of the following negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_INVALID_ARGUMENT + * The length of name or value in |nva| is strictly larger than + * NGHTTP2_MAX_HD_VALUE_LENGTH. + */ +ssize_t nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, + const nghttp2_nv *nva, size_t nvlen); + /* * Returns nonzero if the name/value pair |a| equals to |b|. The name * is compared in case-sensitive, because we ensure that this function @@ -561,12 +582,11 @@ void nghttp2_nv_array_del(nghttp2_nv *nva); /* * Checks names are not empty string and do not contain control - * characters and values are not NULL. This function allows captital - * alphabet letters in name. + * characters. This function allows captital alphabet letters in name. * * This function returns nonzero if it succeeds, or 0. */ -int nghttp2_nv_array_check_null(nghttp2_nv *nva, size_t nvlen); +int nghttp2_nv_array_check_null(const nghttp2_nv *nva, size_t nvlen); /* diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 56efcd33..9745802e 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -31,7 +31,74 @@ #include "nghttp2_frame.h" #include "nghttp2_helper.h" +/* This function takes ownership of |nva_copy|. Regardless of the + return value, the caller must not free |nva_copy| after this + function returns. */ static int nghttp2_submit_headers_shared +(nghttp2_session *session, + uint8_t flags, + int32_t stream_id, + int32_t pri, + nghttp2_nv *nva_copy, + size_t nvlen, + const nghttp2_data_provider *data_prd, + void *stream_user_data) +{ + int rv; + uint8_t flags_copy; + nghttp2_frame *frame = NULL; + nghttp2_data_provider *data_prd_copy = NULL; + nghttp2_headers_aux_data *aux_data = NULL; + if(pri < 0) { + rv = NGHTTP2_ERR_INVALID_ARGUMENT; + goto fail; + } + if(data_prd != NULL && data_prd->read_callback != NULL) { + data_prd_copy = malloc(sizeof(nghttp2_data_provider)); + if(data_prd_copy == NULL) { + rv = NGHTTP2_ERR_NOMEM; + goto fail; + } + *data_prd_copy = *data_prd; + } + if(data_prd || stream_user_data) { + aux_data = malloc(sizeof(nghttp2_headers_aux_data)); + if(aux_data == NULL) { + rv = NGHTTP2_ERR_NOMEM; + goto fail; + } + aux_data->data_prd = data_prd_copy; + aux_data->stream_user_data = stream_user_data; + } + frame = malloc(sizeof(nghttp2_frame)); + if(frame == NULL) { + rv = NGHTTP2_ERR_NOMEM; + goto fail; + } + /* TODO Implement header continuation */ + flags_copy = (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) | + NGHTTP2_FLAG_END_HEADERS; + + nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri, + nva_copy, nvlen); + rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, + aux_data); + if(rv != 0) { + nghttp2_frame_headers_free(&frame->headers); + goto fail2; + } + return 0; + fail: + /* nghttp2_frame_headers_init() takes ownership of nva_copy. */ + nghttp2_nv_array_del(nva_copy); + fail2: + free(frame); + free(aux_data); + free(data_prd_copy); + return rv; +} + +static int nghttp2_submit_headers_shared_nv (nghttp2_session *session, uint8_t flags, int32_t stream_id, @@ -40,71 +107,50 @@ static int nghttp2_submit_headers_shared const nghttp2_data_provider *data_prd, void *stream_user_data) { - int r; - nghttp2_frame *frame; - nghttp2_nv *nva_copy; ssize_t nvlen; - uint8_t flags_copy; - nghttp2_data_provider *data_prd_copy = NULL; - nghttp2_headers_aux_data *aux_data = NULL; - if(pri < 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } + nghttp2_nv *nva_copy; if(!nghttp2_frame_nv_check_null(nv)) { return NGHTTP2_ERR_INVALID_ARGUMENT; } - if(data_prd != NULL && data_prd->read_callback != NULL) { - data_prd_copy = malloc(sizeof(nghttp2_data_provider)); - if(data_prd_copy == NULL) { - return NGHTTP2_ERR_NOMEM; - } - *data_prd_copy = *data_prd; - } - if(data_prd || stream_user_data) { - aux_data = malloc(sizeof(nghttp2_headers_aux_data)); - if(aux_data == NULL) { - free(data_prd_copy); - return NGHTTP2_ERR_NOMEM; - } - aux_data->data_prd = data_prd_copy; - aux_data->stream_user_data = stream_user_data; - } - frame = malloc(sizeof(nghttp2_frame)); - if(frame == NULL) { - free(aux_data); - free(data_prd_copy); - return NGHTTP2_ERR_NOMEM; - } nvlen = nghttp2_nv_array_from_cstr(&nva_copy, nv); if(nvlen < 0) { - free(frame); - free(aux_data); - free(data_prd_copy); return nvlen; } - /* TODO Implement header continuation */ - flags_copy = (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) | - NGHTTP2_FLAG_END_HEADERS; + return nghttp2_submit_headers_shared(session, flags, stream_id, + pri, nva_copy, nvlen, data_prd, + stream_user_data); +} - nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri, - nva_copy, nvlen); - r = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, - aux_data); - if(r != 0) { - nghttp2_frame_headers_free(&frame->headers); - free(frame); - free(aux_data); - free(data_prd_copy); +static int nghttp2_submit_headers_shared_nva +(nghttp2_session *session, + uint8_t flags, + int32_t stream_id, + int32_t pri, + const nghttp2_nv *nva, + size_t nvlen, + const nghttp2_data_provider *data_prd, + void *stream_user_data) +{ + ssize_t rv; + nghttp2_nv *nva_copy; + if(!nghttp2_nv_array_check_null(nva, nvlen)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; } - return r; + rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen); + if(rv < 0) { + return rv; + } + return nghttp2_submit_headers_shared(session, flags, stream_id, + pri, nva_copy, rv, data_prd, + stream_user_data); } int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, int32_t stream_id, int32_t pri, const char **nv, void *stream_user_data) { - return nghttp2_submit_headers_shared(session, flags, stream_id, - pri, nv, NULL, stream_user_data); + return nghttp2_submit_headers_shared_nv(session, flags, stream_id, + pri, nv, NULL, stream_user_data); } @@ -291,10 +337,8 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, return 0; } -int nghttp2_submit_request(nghttp2_session *session, int32_t pri, - const char **nv, - const nghttp2_data_provider *data_prd, - void *stream_user_data) +static uint8_t set_request_flags(int32_t pri, + const nghttp2_data_provider *data_prd) { uint8_t flags = NGHTTP2_FLAG_NONE; if(data_prd == NULL || data_prd->read_callback == NULL) { @@ -303,8 +347,27 @@ int nghttp2_submit_request(nghttp2_session *session, int32_t pri, if(pri != NGHTTP2_PRI_DEFAULT) { flags |= NGHTTP2_FLAG_PRIORITY; } - return nghttp2_submit_headers_shared(session, flags, -1, pri, nv, - data_prd, stream_user_data); + return flags; +} + +int nghttp2_submit_request(nghttp2_session *session, int32_t pri, + const char **nv, + const nghttp2_data_provider *data_prd, + void *stream_user_data) +{ + uint8_t flags = set_request_flags(pri, data_prd); + return nghttp2_submit_headers_shared_nv(session, flags, -1, pri, nv, + data_prd, stream_user_data); +} + +int nghttp2_submit_request2(nghttp2_session *session, int32_t pri, + const nghttp2_nv *nva, size_t nvlen, + const nghttp2_data_provider *data_prd, + void *stream_user_data) +{ + uint8_t flags = set_request_flags(pri, data_prd); + return nghttp2_submit_headers_shared_nva(session, flags, -1, pri, nva, nvlen, + data_prd, stream_user_data); } int nghttp2_submit_response(nghttp2_session *session, @@ -315,9 +378,9 @@ int nghttp2_submit_response(nghttp2_session *session, if(data_prd == NULL || data_prd->read_callback == NULL) { flags |= NGHTTP2_FLAG_END_STREAM; } - return nghttp2_submit_headers_shared(session, flags, stream_id, - NGHTTP2_PRI_DEFAULT, nv, data_prd, - NULL); + return nghttp2_submit_headers_shared_nv(session, flags, stream_id, + NGHTTP2_PRI_DEFAULT, nv, data_prd, + NULL); } int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, diff --git a/tests/main.c b/tests/main.c index c3668b6f..516345ed 100644 --- a/tests/main.c +++ b/tests/main.c @@ -136,6 +136,10 @@ int main(int argc, char* argv[]) test_nghttp2_submit_request_with_data) || !CU_add_test(pSuite, "submit_request_without_data", test_nghttp2_submit_request_without_data) || + !CU_add_test(pSuite, "submit_request2_with_data", + test_nghttp2_submit_request2_with_data) || + !CU_add_test(pSuite, "submit_request2_without_data", + test_nghttp2_submit_request2_without_data) || !CU_add_test(pSuite, "submit_headers_start_stream", test_nghttp2_submit_headers_start_stream) || !CU_add_test(pSuite, "submit_headers_reply", @@ -215,8 +219,11 @@ int main(int argc, char* argv[]) test_nghttp2_frame_pack_goaway) || !CU_add_test(pSuite, "frame_pack_window_update", test_nghttp2_frame_pack_window_update) || + !CU_add_test(pSuite, "nv_array_check_null", + test_nghttp2_nv_array_check_null) || !CU_add_test(pSuite, "nv_array_from_cstr", test_nghttp2_nv_array_from_cstr) || + !CU_add_test(pSuite, "nv_array_copy", test_nghttp2_nv_array_copy) || !CU_add_test(pSuite, "iv_check", test_nghttp2_iv_check) || !CU_add_test(pSuite, "hd_deflate", test_nghttp2_hd_deflate) || !CU_add_test(pSuite, "hd_deflate_same_indexed_repr", diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 7a712fc6..a8d1491e 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -355,6 +355,22 @@ void test_nghttp2_frame_pack_window_update(void) nghttp2_frame_window_update_free(&frame); } +void test_nghttp2_nv_array_check_null(void) +{ + nghttp2_nv nva1[] = {MAKE_NV("path", "/"), + MAKE_NV("host", "a")}; + nghttp2_nv nva2[] = {MAKE_NV("", "/"), + MAKE_NV("host", "a")}; + nghttp2_nv nva3[] = {MAKE_NV("path", "/"), + MAKE_NV("host\x01", "a")}; + nghttp2_nv nva4[] = {MAKE_NV("PATH", "/")}; + + CU_ASSERT(nghttp2_nv_array_check_null(nva1, ARRLEN(nva1))); + CU_ASSERT(0 == nghttp2_nv_array_check_null(nva2, ARRLEN(nva2))); + CU_ASSERT(0 == nghttp2_nv_array_check_null(nva3, ARRLEN(nva3))); + CU_ASSERT(nghttp2_nv_array_check_null(nva4, ARRLEN(nva4))); +} + void test_nghttp2_nv_array_from_cstr(void) { const char *empty[] = {NULL}; @@ -397,6 +413,49 @@ void test_nghttp2_nv_array_from_cstr(void) free(bigval); } +void test_nghttp2_nv_array_copy(void) +{ + nghttp2_nv *nva; + ssize_t rv; + nghttp2_nv emptynv[] = {MAKE_NV("", ""), + MAKE_NV("", "")}; + nghttp2_nv nv[] = {MAKE_NV("alpha", "bravo"), + MAKE_NV("charlie", "delta")}; + nghttp2_nv bignv; + + bignv.name = (uint8_t*)"echo"; + bignv.namelen = (uint16_t)strlen("echo"); + bignv.valuelen = (1 << 14) - 1; + bignv.value = malloc(bignv.valuelen); + memset(bignv.value, '0', bignv.valuelen); + + rv = nghttp2_nv_array_copy(&nva, NULL, 0); + CU_ASSERT(0 == rv); + CU_ASSERT(NULL == nva); + + rv = nghttp2_nv_array_copy(&nva, emptynv, ARRLEN(emptynv)); + CU_ASSERT(0 == rv); + CU_ASSERT(NULL == nva); + + rv = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); + CU_ASSERT(2 == rv); + CU_ASSERT(nva[0].namelen == 5); + CU_ASSERT(0 == memcmp("alpha", nva[0].name, 5)); + CU_ASSERT(nva[0].valuelen = 5); + CU_ASSERT(0 == memcmp("bravo", nva[0].value, 5)); + CU_ASSERT(nva[1].namelen == 7); + CU_ASSERT(0 == memcmp("charlie", nva[1].name, 7)); + CU_ASSERT(nva[1].valuelen == 5); + CU_ASSERT(0 == memcmp("delta", nva[1].value, 5)); + + nghttp2_nv_array_del(nva); + + rv = nghttp2_nv_array_copy(&nva, &bignv, 1); + CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv); + + free(bignv.value); +} + void test_nghttp2_iv_check(void) { nghttp2_settings_entry iv[5]; diff --git a/tests/nghttp2_frame_test.h b/tests/nghttp2_frame_test.h index 742038e2..36ed15db 100644 --- a/tests/nghttp2_frame_test.h +++ b/tests/nghttp2_frame_test.h @@ -35,7 +35,9 @@ void test_nghttp2_frame_pack_push_promise(void); void test_nghttp2_frame_pack_ping(void); void test_nghttp2_frame_pack_goaway(void); void test_nghttp2_frame_pack_window_update(void); +void test_nghttp2_nv_array_check_null(void); void test_nghttp2_nv_array_from_cstr(void); +void test_nghttp2_nv_array_copy(void); void test_nghttp2_iv_check(void); #endif /* NGHTTP2_FRAME_TEST_H */ diff --git a/tests/nghttp2_hd_test.c b/tests/nghttp2_hd_test.c index 42c80f12..7deb2234 100644 --- a/tests/nghttp2_hd_test.c +++ b/tests/nghttp2_hd_test.c @@ -31,10 +31,7 @@ #include "nghttp2_hd.h" #include "nghttp2_frame.h" - -#define MAKE_NV(NAME, VALUE) \ - { (uint8_t*)NAME, (uint8_t*)VALUE, strlen(NAME), strlen(VALUE) } -#define ARRLEN(ARR) (sizeof(ARR)/sizeof(ARR[0])) +#include "nghttp2_test_helper.h" static void assert_nv_equal(nghttp2_nv *a, nghttp2_nv *b, size_t len) { diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 269e3154..2dee3883 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -1787,6 +1787,62 @@ void test_nghttp2_submit_request_without_data(void) nghttp2_session_del(session); } +void test_nghttp2_submit_request2_with_data(void) +{ + nghttp2_session *session; + nghttp2_session_callbacks callbacks; + nghttp2_nv nva[] = {MAKE_NV(":version", "HTTP/1.1")}; + nghttp2_data_provider data_prd; + my_user_data ud; + nghttp2_outbound_item *item; + + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); + callbacks.send_callback = null_send_callback; + + data_prd.read_callback = fixed_length_data_source_read_callback; + ud.data_source_length = 64*1024 - 1; + CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); + CU_ASSERT(0 == nghttp2_submit_request2(session, NGHTTP2_PRI_DEFAULT, + nva, ARRLEN(nva), &data_prd, NULL)); + item = nghttp2_session_get_next_ob_item(session); + CU_ASSERT(nvnameeq(":version", &OB_CTRL(item)->headers.nva[0])); + CU_ASSERT(0 == nghttp2_session_send(session)); + CU_ASSERT(0 == ud.data_source_length); + + nghttp2_session_del(session); +} + +void test_nghttp2_submit_request2_without_data(void) +{ + nghttp2_session *session; + nghttp2_session_callbacks callbacks; + accumulator acc; + nghttp2_nv nva[] = {MAKE_NV(":version", "HTTP/1.1")}; + nghttp2_data_provider data_prd = {{-1}, NULL}; + nghttp2_outbound_item *item; + my_user_data ud; + nghttp2_frame frame; + + acc.length = 0; + ud.acc = &acc; + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); + callbacks.send_callback = accumulator_send_callback; + CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); + CU_ASSERT(0 == nghttp2_submit_request2(session, NGHTTP2_PRI_DEFAULT, + nva, ARRLEN(nva), &data_prd, NULL)); + item = nghttp2_session_get_next_ob_item(session); + CU_ASSERT(nvnameeq(":version", &OB_CTRL(item)->headers.nva[0])); + CU_ASSERT(OB_CTRL(item)->hd.flags & NGHTTP2_FLAG_END_STREAM); + + CU_ASSERT(0 == nghttp2_session_send(session)); + CU_ASSERT(0 == unpack_frame_with_nv_block(&frame, NGHTTP2_HEADERS, + &session->hd_inflater, + acc.buf, acc.length)); + CU_ASSERT(nvnameeq(":version", &frame.headers.nva[0])); + nghttp2_frame_headers_free(&frame.headers); + + nghttp2_session_del(session); +} void test_nghttp2_submit_headers_start_stream(void) { diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index e9ff58c8..fcbff56b 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -57,6 +57,8 @@ void test_nghttp2_submit_response(void); void test_nghttp2_submit_response_without_data(void); void test_nghttp2_submit_request_with_data(void); void test_nghttp2_submit_request_without_data(void); +void test_nghttp2_submit_request2_with_data(void); +void test_nghttp2_submit_request2_without_data(void); void test_nghttp2_submit_headers_start_stream(void); void test_nghttp2_submit_headers_reply(void); void test_nghttp2_submit_headers_push_reply(void); diff --git a/tests/nghttp2_test_helper.h b/tests/nghttp2_test_helper.h index cf3234fd..30bc60bc 100644 --- a/tests/nghttp2_test_helper.h +++ b/tests/nghttp2_test_helper.h @@ -32,6 +32,10 @@ #include "nghttp2_frame.h" #include "nghttp2_hd.h" +#define MAKE_NV(NAME, VALUE) \ + { (uint8_t*)NAME, (uint8_t*)VALUE, strlen(NAME), strlen(VALUE) } +#define ARRLEN(ARR) (sizeof(ARR)/sizeof(ARR[0])) + ssize_t unpack_frame_with_nv_block(nghttp2_frame *frame, nghttp2_frame_type type, nghttp2_hd_context *inflater,