Add more docs about NGHTTP2_ERR_DATA_EXIST and its condition

This commit documents NGHTTP2_ERR_DATA_EXIST also occurs if HEADERS
has been already attached to stream too.  This commit also fixes
possible assertion error, and now nghttp2_submit_headers() and
nghttp2_submit_response() may return NGHTTP2_ERR_DATA_EXIST.  But we
recommend to use nghttp2_submit_request() and
nghttp2_submit_response(), and using them will avoid this error.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-07-08 00:25:07 +09:00
parent 8fcf5f60e4
commit 693fba3b64
3 changed files with 35 additions and 13 deletions

View File

@ -350,8 +350,10 @@ typedef enum {
*/ */
NGHTTP2_ERR_PUSH_DISABLED = -528, NGHTTP2_ERR_PUSH_DISABLED = -528,
/** /**
* DATA frame for a given stream has been already submitted and has * DATA or HEADERS frame for a given stream has been already
* not been fully processed yet. * submitted and has not been fully processed yet. Application
* should wait for the transmission of the previously submitted
* frame before submitting another.
*/ */
NGHTTP2_ERR_DATA_EXIST = -529, NGHTTP2_ERR_DATA_EXIST = -529,
/** /**
@ -3000,6 +3002,11 @@ NGHTTP2_EXTERN int32_t
* Out of memory. * Out of memory.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0. * The |stream_id| is 0.
* :enum:`NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. Normally, this does not happen, but when
* application wrongly calls `nghttp2_submit_response()` twice,
* this may happen.
* *
* .. warning:: * .. warning::
* *
@ -3109,7 +3116,8 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* *
* This function is low-level in a sense that the application code can * This function is low-level in a sense that the application code can
* specify flags directly. For usual HTTP request, * specify flags directly. For usual HTTP request,
* `nghttp2_submit_request()` is useful. * `nghttp2_submit_request()` is useful. Likewise, for HTTP response,
* prefer `nghttp2_submit_response()`.
* *
* This function returns newly assigned stream ID if it succeeds and * This function returns newly assigned stream ID if it succeeds and
* |stream_id| is -1. Otherwise, this function returns 0 if it * |stream_id| is -1. Otherwise, this function returns 0 if it
@ -3122,6 +3130,10 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* reached. * reached.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0. * The |stream_id| is 0.
* :enum:`NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. This happens if stream denoted by |stream_id|
* is in reserved state.
* *
* .. warning:: * .. warning::
* *
@ -3156,7 +3168,8 @@ NGHTTP2_EXTERN int32_t
* :enum:`NGHTTP2_ERR_NOMEM` * :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory. * Out of memory.
* :enum:`NGHTTP2_ERR_DATA_EXIST` * :enum:`NGHTTP2_ERR_DATA_EXIST`
* DATA has been already submitted and not fully processed yet. * DATA or HEADERS has been already submitted and not fully
* processed yet.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0. * The |stream_id| is 0.
* :enum:`NGHTTP2_ERR_STREAM_CLOSED` * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
@ -3164,14 +3177,19 @@ NGHTTP2_EXTERN int32_t
* *
* .. note:: * .. note::
* *
* Currently, only one data is allowed for a stream at a time. * Currently, only one DATA or HEADERS is allowed for a stream at a
* Submitting data more than once before first data is finished * time. Submitting these frames more than once before first DATA
* results in :enum:`NGHTTP2_ERR_DATA_EXIST` error code. The * or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST`
* earliest callback which tells that previous data is done is * error code. The earliest callback which tells that previous
* :type:`nghttp2_on_frame_send_callback`. In side that callback, * frame is done is :type:`nghttp2_on_frame_send_callback`. In side
* new data can be submitted using `nghttp2_submit_data()`. Of * that callback, new data can be submitted using
* course, all data except for last one must not have * `nghttp2_submit_data()`. Of course, all data except for last one
* :enum:`NGHTTP2_FLAG_END_STREAM` flag set in |flags|. * must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in
* |flags|. This sounds a bit complicated, and we recommend to use
* `nghttp2_submit_request()` and `nghttp2_submit_response()` to
* avoid this cascading issue. The experience shows that for HTTP
* use, these two functions are enough to implement both client and
* server.
*/ */
NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
int32_t stream_id, int32_t stream_id,

View File

@ -292,7 +292,7 @@ const char *nghttp2_strerror(int error_code) {
case NGHTTP2_ERR_PUSH_DISABLED: case NGHTTP2_ERR_PUSH_DISABLED:
return "Server push is disabled by peer"; return "Server push is disabled by peer";
case NGHTTP2_ERR_DATA_EXIST: case NGHTTP2_ERR_DATA_EXIST:
return "DATA frame already exists"; return "DATA or HEADERS frame has already been submitted for the stream";
case NGHTTP2_ERR_SESSION_CLOSING: case NGHTTP2_ERR_SESSION_CLOSING:
return "The current session is closing"; return "The current session is closing";
case NGHTTP2_ERR_HTTP_HEADER: case NGHTTP2_ERR_HTTP_HEADER:

View File

@ -713,6 +713,10 @@ int nghttp2_session_add_item(nghttp2_session *session,
if (stream && (stream->state == NGHTTP2_STREAM_RESERVED || if (stream && (stream->state == NGHTTP2_STREAM_RESERVED ||
item->aux_data.headers.attach_stream)) { item->aux_data.headers.attach_stream)) {
if (stream->item) {
return NGHTTP2_ERR_DATA_EXIST;
}
rv = nghttp2_stream_attach_item(stream, item, session); rv = nghttp2_stream_attach_item(stream, item, session);
if (rv != 0) { if (rv != 0) {