diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 41e9429f..d8b1cc4e 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -350,8 +350,10 @@ typedef enum { */ NGHTTP2_ERR_PUSH_DISABLED = -528, /** - * DATA frame for a given stream has been already submitted and has - * not been fully processed yet. + * DATA or HEADERS frame for a given stream has been already + * 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, /** @@ -3000,6 +3002,11 @@ NGHTTP2_EXTERN int32_t * Out of memory. * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` * 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:: * @@ -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 * 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 * |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. * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` * 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:: * @@ -3156,7 +3168,8 @@ NGHTTP2_EXTERN int32_t * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. * :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` * The |stream_id| is 0. * :enum:`NGHTTP2_ERR_STREAM_CLOSED` @@ -3164,14 +3177,19 @@ NGHTTP2_EXTERN int32_t * * .. note:: * - * Currently, only one data is allowed for a stream at a time. - * Submitting data more than once before first data is finished - * results in :enum:`NGHTTP2_ERR_DATA_EXIST` error code. The - * earliest callback which tells that previous data is done is - * :type:`nghttp2_on_frame_send_callback`. In side that callback, - * new data can be submitted using `nghttp2_submit_data()`. Of - * course, all data except for last one must not have - * :enum:`NGHTTP2_FLAG_END_STREAM` flag set in |flags|. + * Currently, only one DATA or HEADERS is allowed for a stream at a + * time. Submitting these frames more than once before first DATA + * or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST` + * error code. The earliest callback which tells that previous + * frame is done is :type:`nghttp2_on_frame_send_callback`. In side + * that callback, new data can be submitted using + * `nghttp2_submit_data()`. Of course, all data except for last one + * 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, int32_t stream_id, diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c index d91d28a9..3ad1fb15 100644 --- a/lib/nghttp2_helper.c +++ b/lib/nghttp2_helper.c @@ -292,7 +292,7 @@ const char *nghttp2_strerror(int error_code) { case NGHTTP2_ERR_PUSH_DISABLED: return "Server push is disabled by peer"; 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: return "The current session is closing"; case NGHTTP2_ERR_HTTP_HEADER: diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 819b32a7..a044a54d 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -713,6 +713,10 @@ int nghttp2_session_add_item(nghttp2_session *session, if (stream && (stream->state == NGHTTP2_STREAM_RESERVED || item->aux_data.headers.attach_stream)) { + if (stream->item) { + return NGHTTP2_ERR_DATA_EXIST; + } + rv = nghttp2_stream_attach_item(stream, item, session); if (rv != 0) {