@@ -497,6 +497,7 @@ static int session_new(nghttp2_session **session_ptr,
497497 (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
498498 (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
499499 (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
500+ (*session_ptr)->max_continuations = NGHTTP2_DEFAULT_MAX_CONTINUATIONS;
500501
501502 if (option) {
502503 if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -585,6 +586,10 @@ static int session_new(nghttp2_session **session_ptr,
585586 option->stream_reset_burst,
586587 option->stream_reset_rate);
587588 }
589+
590+ if (option->opt_set_mask & NGHTTP2_OPT_MAX_CONTINUATIONS) {
591+ (*session_ptr)->max_continuations = option->max_continuations;
592+ }
588593 }
589594
590595 rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -979,7 +984,14 @@ static int session_attach_stream_item(nghttp2_session *session,
979984 return 0;
980985 }
981986
982- return session_ob_data_push(session, stream);
987+ rv = session_ob_data_push(session, stream);
988+ if (rv != 0) {
989+ nghttp2_stream_detach_item(stream);
990+
991+ return rv;
992+ }
993+
994+ return 0;
983995}
984996
985997static void session_detach_stream_item(nghttp2_session *session,
@@ -1309,9 +1321,11 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
13091321 assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
13101322 nghttp2_stream_in_dep_tree(stream));
13111323
1324+ nghttp2_session_detach_idle_stream(session, stream);
1325+
13121326 if (nghttp2_stream_in_dep_tree(stream)) {
13131327 assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES));
1314- nghttp2_session_detach_idle_stream(session, stream);
1328+
13151329 rv = nghttp2_stream_dep_remove(stream);
13161330 if (rv != 0) {
13171331 return NULL;
@@ -1471,6 +1485,21 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
14711485
14721486 DEBUGF("stream: stream(%p)=%d close\n", stream, stream->stream_id);
14731487
1488+ /* We call on_stream_close_callback even if stream->state is
1489+ NGHTTP2_STREAM_INITIAL. This will happen while sending request
1490+ HEADERS, a local endpoint receives RST_STREAM for that stream. It
1491+ may be PROTOCOL_ERROR, but without notifying stream closure will
1492+ hang the stream in a local endpoint.
1493+ */
1494+
1495+ if (session->callbacks.on_stream_close_callback) {
1496+ if (session->callbacks.on_stream_close_callback(
1497+ session, stream_id, error_code, session->user_data) != 0) {
1498+
1499+ return NGHTTP2_ERR_CALLBACK_FAILURE;
1500+ }
1501+ }
1502+
14741503 if (stream->item) {
14751504 nghttp2_outbound_item *item;
14761505
@@ -1488,21 +1517,6 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
14881517 }
14891518 }
14901519
1491- /* We call on_stream_close_callback even if stream->state is
1492- NGHTTP2_STREAM_INITIAL. This will happen while sending request
1493- HEADERS, a local endpoint receives RST_STREAM for that stream. It
1494- may be PROTOCOL_ERROR, but without notifying stream closure will
1495- hang the stream in a local endpoint.
1496- */
1497-
1498- if (session->callbacks.on_stream_close_callback) {
1499- if (session->callbacks.on_stream_close_callback(
1500- session, stream_id, error_code, session->user_data) != 0) {
1501-
1502- return NGHTTP2_ERR_CALLBACK_FAILURE;
1503- }
1504- }
1505-
15061520 is_my_stream_id = nghttp2_session_is_my_stream_id(session, stream_id);
15071521
15081522 /* pushed streams which is not opened yet is not counted toward max
@@ -1559,6 +1573,11 @@ int nghttp2_session_destroy_stream(nghttp2_session *session,
15591573 }
15601574 }
15611575
1576+ if (stream->queued &&
1577+ (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
1578+ session_ob_data_remove(session, stream);
1579+ }
1580+
15621581 nghttp2_map_remove(&session->streams, stream->stream_id);
15631582 nghttp2_stream_free(stream);
15641583 nghttp2_mem_free(mem, stream);
@@ -6812,6 +6831,8 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
68126831 }
68136832 }
68146833 session_inbound_frame_reset(session);
6834+
6835+ session->num_continuations = 0;
68156836 }
68166837 break;
68176838 }
@@ -6933,6 +6954,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
69336954 }
69346955#endif /* DEBUGBUILD */
69356956
6957+ if (++session->num_continuations > session->max_continuations) {
6958+ return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS;
6959+ }
6960+
69366961 readlen = inbound_frame_buf_read(iframe, in, last);
69376962 in += readlen;
69386963
0 commit comments