Commit d1c1deaf authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Add promised_stream_user_data parameter to nghttp2_submit_push_promise

This is very useful to associate application specific data to promised
stream.

nghttp2_nv_array_copy now does not complain the header field is large.
parent 86aa905c
......@@ -2140,6 +2140,13 @@ int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
* This function creates copies of all name/value pairs in |nva|. It
* also lower-cases all names in |nva|.
*
* The |promised_stream_user_data| is a pointer to an arbitrary data
* which is associated to the promised stream this frame will open and
* make it in reserved state. It is available using
* `nghttp2_session_get_stream_user_data()`. The application can
* access it in :type:`nghttp2_before_frame_send_callback` and
* :type:`nghttp2_on_frame_send_callback` of this frame.
*
* Since the library reorders the frames and tries to send the highest
* prioritized one first and the HTTP/2.0 specification requires the
* stream ID must be strictly increasing, the promised stream ID
......@@ -2160,7 +2167,8 @@ int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
*/
int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const nghttp2_nv *nva, size_t nvlen);
const nghttp2_nv *nva, size_t nvlen,
void *promised_stream_user_data);
/**
* @function
......
......@@ -598,10 +598,6 @@ ssize_t nghttp2_nv_array_copy(nghttp2_nv **nva_ptr,
size_t buflen = 0;
nghttp2_nv *p;
for(i = 0; i < nvlen; ++i) {
if(nva[i].namelen > NGHTTP2_HD_MAX_NAME ||
nva[i].valuelen > NGHTTP2_HD_MAX_VALUE) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
buflen += nva[i].namelen + nva[i].valuelen;
}
/* If all name/value pair is 0-length, remove them */
......
......@@ -481,9 +481,6 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
*
* 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);
......
......@@ -1303,6 +1303,9 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
}
case NGHTTP2_PUSH_PROMISE: {
nghttp2_stream *stream;
nghttp2_headers_aux_data *aux_data;
aux_data = (nghttp2_headers_aux_data*)item->aux_data;
rv = nghttp2_session_predicate_push_promise_send(session,
frame->hd.stream_id);
if(rv != 0) {
......@@ -1325,12 +1328,13 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session,
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
assert(stream);
if(nghttp2_session_open_stream
if(!nghttp2_session_open_stream
(session, frame->push_promise.promised_stream_id,
NGHTTP2_STREAM_FLAG_PUSH,
nghttp2_pushed_stream_pri(stream),
NGHTTP2_STREAM_RESERVED,
NULL) == NULL) {
aux_data ?
aux_data->stream_user_data : NULL)) {
return NGHTTP2_ERR_NOMEM;
}
break;
......
......@@ -181,28 +181,41 @@ int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const nghttp2_nv *nva, size_t nvlen)
const nghttp2_nv *nva, size_t nvlen,
void *promised_stream_user_data)
{
nghttp2_frame *frame;
nghttp2_nv *nva_copy;
uint8_t flags_copy;
nghttp2_headers_aux_data *aux_data = NULL;
int rv;
frame = malloc(sizeof(nghttp2_frame));
if(frame == NULL) {
return NGHTTP2_ERR_NOMEM;
}
if(promised_stream_user_data) {
aux_data = malloc(sizeof(nghttp2_headers_aux_data));
if(aux_data == NULL) {
free(frame);
return NGHTTP2_ERR_NOMEM;
}
aux_data->data_prd = NULL;
aux_data->stream_user_data = promised_stream_user_data;
}
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen);
if(rv < 0) {
free(aux_data);
free(frame);
return rv;
}
flags_copy = NGHTTP2_FLAG_END_HEADERS;
nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy,
stream_id, -1, nva_copy, nvlen);
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, aux_data);
if(rv != 0) {
nghttp2_frame_push_promise_free(&frame->push_promise);
free(aux_data);
free(frame);
}
return 0;
......
......@@ -515,7 +515,8 @@ int Http2Handler::submit_push_promise(Request *req,
http2::make_nv_ls(":authority", (*itr).second)
};
return nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_END_HEADERS,
req->stream_id, nva.data(), nva.size());
req->stream_id, nva.data(), nva.size(),
nullptr);
}
void Http2Handler::add_stream(int32_t stream_id, std::unique_ptr<Request> req)
......
......@@ -406,8 +406,9 @@ void test_nghttp2_nv_array_copy(void)
nghttp2_nv_array_del(nva);
/* Large header field is acceptable */
rv = nghttp2_nv_array_copy(&nva, &bignv, 1);
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
CU_ASSERT(1 == rv);
free(bignv.value);
}
......
......@@ -2201,7 +2201,7 @@ void test_nghttp2_session_reprioritize_stream(void)
CU_ASSERT(0 == nghttp2_submit_push_promise(session,
NGHTTP2_FLAG_END_HEADERS,
3, NULL, 0));
3, NULL, 0, NULL));
ud.block_count = 0;
CU_ASSERT(0 == nghttp2_session_send(session));
/* Now PUSH_PROMISE is in aob */
......@@ -2846,7 +2846,7 @@ void test_nghttp2_submit_push_promise(void)
NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL);
CU_ASSERT(0 == nghttp2_submit_push_promise(session, NGHTTP2_FLAG_NONE, 1,
nv, ARRLEN(nv)));
nv, ARRLEN(nv), &ud));
ud.frame_send_cb_called = 0;
ud.sent_frame_type = 0;
......@@ -2855,6 +2855,7 @@ void test_nghttp2_submit_push_promise(void)
CU_ASSERT(NGHTTP2_PUSH_PROMISE == ud.sent_frame_type);
stream = nghttp2_session_get_stream(session, 2);
CU_ASSERT(NGHTTP2_STREAM_RESERVED == stream->state);
CU_ASSERT(&ud == nghttp2_session_get_stream_user_data(session, 2));
nghttp2_session_del(session);
}
......@@ -3039,7 +3040,8 @@ void test_nghttp2_submit_invalid_nv(void)
/* nghttp2_submit_push_promise */
CU_ASSERT(0 ==
nghttp2_submit_push_promise(session, NGHTTP2_FLAG_NONE, 2,
empty_name_nv, ARRLEN(empty_name_nv)));
empty_name_nv, ARRLEN(empty_name_nv),
NULL));
nghttp2_session_del(session);
}
......@@ -4128,7 +4130,7 @@ void test_nghttp2_session_pack_headers_with_padding(void)
/* Check PUSH_PROMISE */
CU_ASSERT(0 ==
nghttp2_submit_push_promise(sv_session, NGHTTP2_FLAG_NONE, 1,
nva, ARRLEN(nva)));
nva, ARRLEN(nva), NULL));
acc.length = 0;
CU_ASSERT(0 == nghttp2_session_send(sv_session));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment