void nghttp2_outbound_item_free(nghttp2_outbound_item *item) { if(item == NULL) { return; } if(item->frame_cat == NGHTTP2_CAT_CTRL) { nghttp2_frame *frame; frame = nghttp2_outbound_item_get_ctrl_frame(item); switch(frame->hd.type) { case NGHTTP2_HEADERS: nghttp2_frame_headers_free(&frame->headers); if(item->aux_data) { free(((nghttp2_headers_aux_data*)item->aux_data)->data_prd); } break; case NGHTTP2_PRIORITY: nghttp2_frame_priority_free(&frame->priority); break; case NGHTTP2_RST_STREAM: nghttp2_frame_rst_stream_free(&frame->rst_stream); break; case NGHTTP2_SETTINGS: nghttp2_frame_settings_free(&frame->settings); break; case NGHTTP2_PUSH_PROMISE: nghttp2_frame_push_promise_free(&frame->push_promise); break; case NGHTTP2_PING: nghttp2_frame_ping_free(&frame->ping); break; case NGHTTP2_GOAWAY: nghttp2_frame_goaway_free(&frame->goaway); break; case NGHTTP2_WINDOW_UPDATE: nghttp2_frame_window_update_free(&frame->window_update); break; case NGHTTP2_EXT_ALTSVC: nghttp2_frame_altsvc_free(&frame->ext); free(frame->ext.payload); break; } } else if(item->frame_cat == NGHTTP2_CAT_DATA) { nghttp2_private_data *data_frame; data_frame = nghttp2_outbound_item_get_data_frame(item); nghttp2_frame_private_data_free(data_frame); } else { /* Unreachable */ assert(0); } free(item->frame); free(item->aux_data); }
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_, int32_t stream_id, const uint8_t *origin, size_t origin_len, const uint8_t *field_value, size_t field_value_len) { nghttp2_mem *mem; uint8_t *buf, *p; uint8_t *origin_copy; uint8_t *field_value_copy; nghttp2_outbound_item *item; nghttp2_frame *frame; nghttp2_ext_altsvc *altsvc; int rv; mem = &session->mem; if (!session->server) { return NGHTTP2_ERR_INVALID_STATE; } if (2 + origin_len + field_value_len > NGHTTP2_MAX_PAYLOADLEN) { return NGHTTP2_ERR_INVALID_ARGUMENT; } if (stream_id == 0) { if (origin_len == 0) { return NGHTTP2_ERR_INVALID_ARGUMENT; } } else if (origin_len != 0) { return NGHTTP2_ERR_INVALID_ARGUMENT; } buf = nghttp2_mem_malloc(mem, origin_len + field_value_len + 2); if (buf == NULL) { return NGHTTP2_ERR_NOMEM; } p = buf; origin_copy = p; if (origin_len) { p = nghttp2_cpymem(p, origin, origin_len); } *p++ = '\0'; field_value_copy = p; if (field_value_len) { p = nghttp2_cpymem(p, field_value, field_value_len); } *p++ = '\0'; item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); if (item == NULL) { rv = NGHTTP2_ERR_NOMEM; goto fail_item_malloc; } nghttp2_outbound_item_init(item); item->aux_data.ext.builtin = 1; altsvc = &item->ext_frame_payload.altsvc; frame = &item->frame; frame->ext.payload = altsvc; nghttp2_frame_altsvc_init(&frame->ext, stream_id, origin_copy, origin_len, field_value_copy, field_value_len); rv = nghttp2_session_add_item(session, item); if (rv != 0) { nghttp2_frame_altsvc_free(&frame->ext, mem); nghttp2_mem_free(mem, item); return rv; } return 0; fail_item_malloc: free(buf); return rv; }
void test_nghttp2_frame_pack_altsvc(void) { nghttp2_extension frame, oframe; nghttp2_ext_altsvc altsvc, oaltsvc; nghttp2_bufs bufs; nghttp2_buf *buf; size_t protocol_id_len, host_len, origin_len; uint8_t *protocol_id, *host, *origin; uint8_t *data; size_t datalen; int rv; size_t payloadlen; protocol_id_len = strlen("h2"); host_len = strlen("h2.example.org"); origin_len = strlen("www.example.org"); datalen = protocol_id_len + host_len + origin_len; data = malloc(datalen); memcpy(data, "h2", protocol_id_len); protocol_id = data; memcpy(data + protocol_id_len, "h2.example.org", host_len); host = data + protocol_id_len; memcpy(data + protocol_id_len + host_len, "http://www.example.org", origin_len); origin = data + protocol_id_len + host_len; frame_pack_bufs_init(&bufs); frame.payload = &altsvc; nghttp2_frame_altsvc_init(&frame, 1000000007, 1u << 31, 4000, protocol_id, protocol_id_len, host, host_len, origin, origin_len); rv = nghttp2_frame_pack_altsvc(&bufs, &frame); CU_ASSERT(0 == rv); CU_ASSERT((ssize_t)(NGHTTP2_FRAME_HDLEN + NGHTTP2_ALTSVC_MINLEN + datalen) == nghttp2_bufs_len(&bufs)); oframe.payload = &oaltsvc; CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs)); check_frame_header(NGHTTP2_ALTSVC_MINLEN + datalen, NGHTTP2_EXT_ALTSVC, NGHTTP2_FLAG_NONE, 1000000007, &oframe.hd); CU_ASSERT(1u << 31 == oaltsvc.max_age); CU_ASSERT(4000 == oaltsvc.port); CU_ASSERT(protocol_id_len == oaltsvc.protocol_id_len); CU_ASSERT(memcmp(protocol_id, oaltsvc.protocol_id, protocol_id_len) == 0); CU_ASSERT(host_len == oaltsvc.host_len); CU_ASSERT(memcmp(host, oaltsvc.host, host_len) == 0); CU_ASSERT(origin_len == oaltsvc.origin_len); CU_ASSERT(memcmp(origin, oaltsvc.origin, origin_len) == 0); nghttp2_frame_altsvc_free(&oframe); nghttp2_frame_altsvc_free(&frame); memset(&oframe, 0, sizeof(oframe)); memset(&oaltsvc, 0, sizeof(oaltsvc)); buf = &bufs.head->buf; CU_ASSERT(buf->pos - buf->begin == 1); /* Check no origin case */ payloadlen = NGHTTP2_ALTSVC_MINLEN + protocol_id_len + host_len; nghttp2_put_uint32be(buf->pos, (uint32_t)((payloadlen << 8) + buf->pos[3])); oframe.payload = &oaltsvc; CU_ASSERT(0 == nghttp2_frame_unpack_altsvc_payload (&oframe, buf->pos + NGHTTP2_FRAME_HDLEN, NGHTTP2_ALTSVC_FIXED_PARTLEN, buf->pos + NGHTTP2_FRAME_HDLEN + NGHTTP2_ALTSVC_FIXED_PARTLEN, payloadlen - NGHTTP2_ALTSVC_FIXED_PARTLEN)); CU_ASSERT(protocol_id_len == oaltsvc.protocol_id_len); CU_ASSERT(host_len == oaltsvc.host_len); CU_ASSERT(0 == oaltsvc.origin_len); memset(&oframe, 0, sizeof(oframe)); memset(&oaltsvc, 0, sizeof(oaltsvc)); /* Check insufficient payload length for host */ payloadlen = NGHTTP2_ALTSVC_MINLEN + protocol_id_len + host_len - 1; nghttp2_put_uint32be(buf->pos, (uint32_t)((payloadlen << 8) + buf->pos[3])); oframe.payload = &oaltsvc; CU_ASSERT(NGHTTP2_ERR_FRAME_SIZE_ERROR == nghttp2_frame_unpack_altsvc_payload (&oframe, buf->pos + NGHTTP2_FRAME_HDLEN, NGHTTP2_ALTSVC_FIXED_PARTLEN, buf->pos + NGHTTP2_FRAME_HDLEN + NGHTTP2_ALTSVC_FIXED_PARTLEN, payloadlen - NGHTTP2_ALTSVC_FIXED_PARTLEN)); memset(&oframe, 0, sizeof(oframe)); memset(&oaltsvc, 0, sizeof(oaltsvc)); /* Check no host case */ payloadlen = NGHTTP2_ALTSVC_MINLEN + protocol_id_len; nghttp2_put_uint32be(buf->pos, (uint32_t)((payloadlen << 8) + buf->pos[3])); buf->pos[NGHTTP2_FRAME_HDLEN + NGHTTP2_ALTSVC_FIXED_PARTLEN + protocol_id_len] = 0; oframe.payload = &oaltsvc; CU_ASSERT(0 == nghttp2_frame_unpack_altsvc_payload (&oframe, buf->pos + NGHTTP2_FRAME_HDLEN, NGHTTP2_ALTSVC_FIXED_PARTLEN, buf->pos + NGHTTP2_FRAME_HDLEN + NGHTTP2_ALTSVC_FIXED_PARTLEN, payloadlen - NGHTTP2_ALTSVC_FIXED_PARTLEN)); CU_ASSERT(protocol_id_len == oaltsvc.protocol_id_len); CU_ASSERT(0 == oaltsvc.host_len); CU_ASSERT(0 == oaltsvc.origin_len); memset(&oframe, 0, sizeof(oframe)); memset(&oaltsvc, 0, sizeof(oaltsvc)); /* Check missing Host-Len */ payloadlen = NGHTTP2_ALTSVC_FIXED_PARTLEN + protocol_id_len; nghttp2_put_uint32be(buf->pos, (uint32_t)((payloadlen << 8) + buf->pos[3])); oframe.payload = &oaltsvc; CU_ASSERT(NGHTTP2_ERR_FRAME_SIZE_ERROR == nghttp2_frame_unpack_altsvc_payload (&oframe, buf->pos + NGHTTP2_FRAME_HDLEN, NGHTTP2_ALTSVC_FIXED_PARTLEN, buf->pos + NGHTTP2_FRAME_HDLEN + NGHTTP2_ALTSVC_FIXED_PARTLEN, payloadlen - NGHTTP2_ALTSVC_FIXED_PARTLEN)); memset(&oframe, 0, sizeof(oframe)); memset(&oaltsvc, 0, sizeof(oaltsvc)); nghttp2_bufs_free(&bufs); }