diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index b4c1d443..4f42605a 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -741,6 +741,30 @@ void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, altsvc->field_value_len = (size_t)(payload + payloadlen - p); } +int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame, + const uint8_t *payload, + size_t payloadlen, nghttp2_mem *mem) { + uint8_t *buf; + size_t origin_len; + + if (payloadlen < 2) { + return NGHTTP2_FRAME_SIZE_ERROR; + } + + origin_len = nghttp2_get_uint16(payload); + + buf = nghttp2_mem_malloc(mem, payloadlen - 2); + if (!buf) { + return NGHTTP2_ERR_NOMEM; + } + + nghttp2_cpymem(buf, payload + 2, payloadlen - 2); + + nghttp2_frame_unpack_altsvc_payload(frame, origin_len, buf, payloadlen - 2); + + return 0; +} + nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, size_t niv, nghttp2_mem *mem) { nghttp2_settings_entry *iv_copy; diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index c6111728..c6ebcb06 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -388,6 +388,24 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext); void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, size_t origin_len, uint8_t *payload, size_t payloadlen); + +/* + * Unpacks ALTSVC wire format into |frame|. This function only exists + * for unit test. After allocating buffer for fields, this function + * internally calls nghttp2_frame_unpack_altsvc_payload(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + * NGHTTP2_ERR_FRAME_SIZE_ERROR + * The payload is too small. + */ +int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame, + const uint8_t *payload, + size_t payloadlen, nghttp2_mem *mem); + /* * Initializes HEADERS frame |frame| with given values. |frame| takes * ownership of |nva|, so caller must not free it. If |stream_id| is diff --git a/tests/main.c b/tests/main.c index 3aae0376..0b17dcd7 100644 --- a/tests/main.c +++ b/tests/main.c @@ -339,6 +339,8 @@ int main(int argc _U_, char *argv[] _U_) { test_nghttp2_frame_pack_goaway) || !CU_add_test(pSuite, "frame_pack_window_update", test_nghttp2_frame_pack_window_update) || + !CU_add_test(pSuite, "frame_pack_altsvc", + test_nghttp2_frame_pack_altsvc) || !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) || diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 06d83448..17b7ae58 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -454,6 +454,60 @@ void test_nghttp2_frame_pack_window_update(void) { nghttp2_frame_window_update_free(&frame); } +void test_nghttp2_frame_pack_altsvc(void) { + nghttp2_extension frame, oframe; + nghttp2_ext_altsvc altsvc, oaltsvc; + nghttp2_bufs bufs; + int rv; + size_t payloadlen; + static const uint8_t origin[] = "nghttp2.org"; + static const uint8_t field_value[] = "h2=\":443\""; + nghttp2_buf buf; + uint8_t *rawbuf; + nghttp2_mem *mem; + + mem = nghttp2_mem_default(); + + frame_pack_bufs_init(&bufs); + + frame.payload = &altsvc; + oframe.payload = &oaltsvc; + + rawbuf = nghttp2_mem_malloc(mem, 32); + nghttp2_buf_wrap_init(&buf, rawbuf, 32); + + buf.last = nghttp2_cpymem(buf.last, origin, sizeof(origin) - 1); + buf.last = nghttp2_cpymem(buf.last, field_value, sizeof(field_value) - 1); + + nghttp2_frame_altsvc_init(&frame, 1000000007, buf.pos, sizeof(origin) - 1, + buf.pos + sizeof(origin) - 1, + sizeof(field_value) - 1); + + payloadlen = 2 + sizeof(origin) - 1 + sizeof(field_value) - 1; + + rv = nghttp2_frame_pack_altsvc(&bufs, &frame); + + CU_ASSERT(0 == rv); + CU_ASSERT(NGHTTP2_FRAME_HDLEN + payloadlen == nghttp2_bufs_len(&bufs)); + + rv = unpack_framebuf((nghttp2_frame*)&oframe, &bufs); + + CU_ASSERT(0 == rv); + + check_frame_header(payloadlen, NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, 1000000007, + &oframe.hd); + + CU_ASSERT(sizeof(origin) - 1 == oaltsvc.origin_len); + CU_ASSERT(0 == memcmp(origin, oaltsvc.origin, sizeof(origin) - 1)); + CU_ASSERT(sizeof(field_value) - 1 == oaltsvc.field_value_len); + CU_ASSERT(0 == + memcmp(field_value, oaltsvc.field_value, sizeof(field_value) - 1)); + + nghttp2_frame_altsvc_free(&oframe, mem); + nghttp2_frame_altsvc_free(&frame, mem); + nghttp2_bufs_free(&bufs); +} + void test_nghttp2_nv_array_copy(void) { nghttp2_nv *nva; ssize_t rv; diff --git a/tests/nghttp2_frame_test.h b/tests/nghttp2_frame_test.h index f3f4530e..059b20ba 100644 --- a/tests/nghttp2_frame_test.h +++ b/tests/nghttp2_frame_test.h @@ -38,6 +38,7 @@ 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_frame_pack_altsvc(void); void test_nghttp2_nv_array_copy(void); void test_nghttp2_iv_check(void); diff --git a/tests/nghttp2_test_helper.c b/tests/nghttp2_test_helper.c index ed92f132..dcd4ddb8 100644 --- a/tests/nghttp2_test_helper.c +++ b/tests/nghttp2_test_helper.c @@ -83,6 +83,10 @@ int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len) { nghttp2_frame_unpack_window_update_payload(&frame->window_update, payload, payloadlen); break; + case NGHTTP2_ALTSVC: + assert(payloadlen > 2); + nghttp2_frame_unpack_altsvc_payload2(&frame->ext, payload, payloadlen, mem); + break; default: /* Must not be reachable */ assert(0);