Make nghttp2_session_get_stream_user_data work inside nghttp2_on_frame_not_send_callback

This commit is contained in:
Tatsuhiro Tsujikawa 2015-02-12 22:41:57 +09:00
parent 7d4a6aa179
commit eb94603c51
2 changed files with 52 additions and 35 deletions

View File

@ -1322,6 +1322,9 @@ typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session,
* `nghttp2_session_recv()` and `nghttp2_session_send()` functions * `nghttp2_session_recv()` and `nghttp2_session_send()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
* *
* `nghttp2_session_get_stream_user_data()` can be used to get
* associated data.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use * To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_frame_not_send_callback()`. * `nghttp2_session_callbacks_set_on_frame_not_send_callback()`.
*/ */

View File

@ -1672,13 +1672,8 @@ static int session_prep_frame(nghttp2_session *session,
} }
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
nghttp2_stream *stream;
/* initial HEADERS, which opens stream */ /* initial HEADERS, which opens stream */
rv = session_predicate_request_headers_send(session); nghttp2_stream *stream;
if (rv != 0) {
return rv;
}
stream = nghttp2_session_open_stream( stream = nghttp2_session_open_stream(
session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE,
@ -1689,6 +1684,10 @@ static int session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_NOMEM; return NGHTTP2_ERR_NOMEM;
} }
rv = session_predicate_request_headers_send(session);
if (rv != 0) {
return rv;
}
} else { } else {
nghttp2_stream *stream; nghttp2_stream *stream;
@ -1729,7 +1728,7 @@ static int session_prep_frame(nghttp2_session *session,
&session->aob.framebufs, &frame->headers, &session->hd_deflater); &session->aob.framebufs, &frame->headers, &session->hd_deflater);
if (framerv < 0) { if (framerv < 0) {
goto close_stream_return; return framerv;
} }
DEBUGF(fprintf(stderr, DEBUGF(fprintf(stderr,
@ -1739,27 +1738,13 @@ static int session_prep_frame(nghttp2_session *session,
framerv = session_headers_add_pad(session, frame); framerv = session_headers_add_pad(session, frame);
if (framerv < 0) { if (framerv < 0) {
goto close_stream_return; return framerv;
} }
DEBUGF(fprintf(stderr, "send: HEADERS finally serialized in %zd bytes\n", DEBUGF(fprintf(stderr, "send: HEADERS finally serialized in %zd bytes\n",
nghttp2_bufs_len(&session->aob.framebufs))); nghttp2_bufs_len(&session->aob.framebufs)));
break; break;
close_stream_return:
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST &&
!nghttp2_is_fatal(framerv)) {
rv = nghttp2_session_close_stream(session, frame->hd.stream_id,
NGHTTP2_NO_ERROR);
if (nghttp2_is_fatal(rv)) {
return rv;
}
}
return framerv;
} }
case NGHTTP2_PRIORITY: { case NGHTTP2_PRIORITY: {
if (session_is_closing(session)) { if (session_is_closing(session)) {
@ -1805,6 +1790,24 @@ static int session_prep_frame(nghttp2_session *session,
aux_data = &item->aux_data.headers; aux_data = &item->aux_data.headers;
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
/* stream could be NULL if associated stream was already
closed. */
if (stream) {
nghttp2_priority_spec_init(&pri_spec, stream->stream_id,
NGHTTP2_DEFAULT_WEIGHT, 0);
} else {
nghttp2_priority_spec_default_init(&pri_spec);
}
if (!nghttp2_session_open_stream(
session, frame->push_promise.promised_stream_id,
NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED,
aux_data->stream_user_data)) {
return NGHTTP2_ERR_NOMEM;
}
estimated_payloadlen = session_estimate_headers_payload( estimated_payloadlen = session_estimate_headers_payload(
session, frame->push_promise.nva, frame->push_promise.nvlen, 0); session, frame->push_promise.nva, frame->push_promise.nvlen, 0);
@ -1812,8 +1815,7 @@ static int session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_FRAME_SIZE_ERROR; return NGHTTP2_ERR_FRAME_SIZE_ERROR;
} }
stream = nghttp2_session_get_stream(session, frame->hd.stream_id); /* predicte should fail if stream is NULL. */
rv = session_predicate_push_promise_send(session, stream); rv = session_predicate_push_promise_send(session, stream);
if (rv != 0) { if (rv != 0) {
return rv; return rv;
@ -1831,17 +1833,6 @@ static int session_prep_frame(nghttp2_session *session,
return framerv; return framerv;
} }
/* TODO It is unclear reserved stream dpeneds on associated
stream with or without exclusive flag set */
nghttp2_priority_spec_init(&pri_spec, stream->stream_id,
NGHTTP2_DEFAULT_WEIGHT, 0);
if (!nghttp2_session_open_stream(
session, frame->push_promise.promised_stream_id,
NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED,
aux_data->stream_user_data)) {
return NGHTTP2_ERR_NOMEM;
}
break; break;
} }
case NGHTTP2_PING: case NGHTTP2_PING:
@ -2683,6 +2674,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
if (item->frame.hd.type != NGHTTP2_DATA && if (item->frame.hd.type != NGHTTP2_DATA &&
session->callbacks.on_frame_not_send_callback && is_non_fatal(rv)) { session->callbacks.on_frame_not_send_callback && is_non_fatal(rv)) {
nghttp2_frame *frame = &item->frame; nghttp2_frame *frame = &item->frame;
int32_t opened_stream_id = 0;
/* The library is responsible for the transmission of /* The library is responsible for the transmission of
WINDOW_UPDATE frame, so we don't call error callback for WINDOW_UPDATE frame, so we don't call error callback for
it. */ it. */
@ -2696,6 +2688,28 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
} }
} }
/* We have to close stream opened by failed request HEADERS
or PUSH_PROMISE. */
switch (item->frame.hd.type) {
case NGHTTP2_HEADERS:
if (item->frame.headers.cat == NGHTTP2_HCAT_REQUEST) {
opened_stream_id = item->frame.hd.stream_id;
}
break;
case NGHTTP2_PUSH_PROMISE:
opened_stream_id = item->frame.push_promise.promised_stream_id;
break;
}
if (opened_stream_id) {
/* careful not to override rv */
int rv2;
rv2 = nghttp2_session_close_stream(session, opened_stream_id,
NGHTTP2_NO_ERROR);
if (nghttp2_is_fatal(rv2)) {
return rv2;
}
}
} }
nghttp2_outbound_item_free(item, mem); nghttp2_outbound_item_free(item, mem);
nghttp2_mem_free(mem, item); nghttp2_mem_free(mem, item);