parent
aacac613af
commit
12b2e0a2b3
|
@ -86,6 +86,7 @@ APIDOCS= \
|
||||||
nghttp2_session_consume.rst \
|
nghttp2_session_consume.rst \
|
||||||
nghttp2_session_consume_connection.rst \
|
nghttp2_session_consume_connection.rst \
|
||||||
nghttp2_session_consume_stream.rst \
|
nghttp2_session_consume_stream.rst \
|
||||||
|
nghttp2_session_create_idle_stream.rst \
|
||||||
nghttp2_session_del.rst \
|
nghttp2_session_del.rst \
|
||||||
nghttp2_session_find_stream.rst \
|
nghttp2_session_find_stream.rst \
|
||||||
nghttp2_session_get_effective_local_window_size.rst \
|
nghttp2_session_get_effective_local_window_size.rst \
|
||||||
|
|
|
@ -2887,6 +2887,51 @@ nghttp2_session_change_stream_priority(nghttp2_session *session,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
const nghttp2_priority_spec *pri_spec);
|
const nghttp2_priority_spec *pri_spec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Creates idle stream with the given |stream_id|, and priority
|
||||||
|
* |pri_spec|.
|
||||||
|
*
|
||||||
|
* The stream creation is done without sending PRIORITY frame, which
|
||||||
|
* means that peer does not know about the existence of this idle
|
||||||
|
* stream in the local endpoint.
|
||||||
|
*
|
||||||
|
* RFC 7540 does not disallow the use of creation of idle stream with
|
||||||
|
* odd or even stream ID regardless of client or server. So this
|
||||||
|
* function can create odd or even stream ID regardless of client or
|
||||||
|
* server. But probably it is a bit safer to use the stream ID the
|
||||||
|
* local endpoint can initiate (in other words, use odd stream ID for
|
||||||
|
* client, and even stream ID for server), to avoid potential
|
||||||
|
* collision from peer's instruction. Also we can use
|
||||||
|
* `nghttp2_session_set_next_stream_id()` to avoid to open created
|
||||||
|
* idle streams accidentally if we follow this recommendation.
|
||||||
|
*
|
||||||
|
* If |session| is initialized as server, and ``pri_spec->stream_id``
|
||||||
|
* points to the idle stream, the idle stream is created if it does
|
||||||
|
* not exist. The created idle stream will depend on root stream
|
||||||
|
* (stream 0) with weight 16.
|
||||||
|
*
|
||||||
|
* Otherwise, if stream denoted by ``pri_spec->stream_id`` is not
|
||||||
|
* found, we use default priority instead of given |pri_spec|. That
|
||||||
|
* is make stream depend on root stream with weight 16.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||||
|
* Out of memory.
|
||||||
|
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||||
|
* Attempted to depend on itself; or stream denoted by |stream_id|
|
||||||
|
* already exists; or |stream_id| cannot be used to create idle
|
||||||
|
* stream (in other words, local endpoint has already opened
|
||||||
|
* stream ID greater than or equal to the given stream ID; or
|
||||||
|
* |stream_id| is 0
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN int
|
||||||
|
nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id,
|
||||||
|
const nghttp2_priority_spec *pri_spec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
|
|
|
@ -6731,3 +6731,32 @@ int nghttp2_session_change_stream_priority(
|
||||||
|
|
||||||
return nghttp2_session_reprioritize_stream(session, stream, &pri_spec_copy);
|
return nghttp2_session_reprioritize_stream(session, stream, &pri_spec_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_session_create_idle_stream(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
const nghttp2_priority_spec *pri_spec) {
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
nghttp2_priority_spec pri_spec_copy;
|
||||||
|
|
||||||
|
if (stream_id == 0 || stream_id == pri_spec->stream_id ||
|
||||||
|
!session_detect_idle_stream(session, stream_id)) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = nghttp2_session_get_stream_raw(session, stream_id);
|
||||||
|
if (stream) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pri_spec_copy = *pri_spec;
|
||||||
|
nghttp2_priority_spec_normalize_weight(&pri_spec_copy);
|
||||||
|
|
||||||
|
stream =
|
||||||
|
nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
|
&pri_spec_copy, NGHTTP2_STREAM_IDLE, NULL);
|
||||||
|
if (!stream) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -8464,6 +8464,77 @@ void test_nghttp2_session_change_stream_priority(void) {
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_session_create_idle_stream(void) {
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
nghttp2_stream *stream2, *stream4, *stream8, *stream10;
|
||||||
|
nghttp2_priority_spec pri_spec;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
memset(&callbacks, 0, sizeof(callbacks));
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
stream2 = open_stream(session, 2);
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 2, 111, 1);
|
||||||
|
|
||||||
|
rv = nghttp2_session_create_idle_stream(session, 4, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
stream4 = nghttp2_session_get_stream_raw(session, 4);
|
||||||
|
|
||||||
|
CU_ASSERT(4 == stream4->stream_id);
|
||||||
|
CU_ASSERT(111 == stream4->weight);
|
||||||
|
CU_ASSERT(stream2 == stream4->dep_prev);
|
||||||
|
CU_ASSERT(stream4 == stream2->dep_next);
|
||||||
|
|
||||||
|
/* If pri_spec->stream_id does not exist, and it is idle stream, it
|
||||||
|
is created too */
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 8, 109, 0);
|
||||||
|
|
||||||
|
rv = nghttp2_session_create_idle_stream(session, 8, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
stream8 = nghttp2_session_get_stream_raw(session, 8);
|
||||||
|
stream10 = nghttp2_session_get_stream_raw(session, 10);
|
||||||
|
|
||||||
|
CU_ASSERT(8 == stream8->stream_id);
|
||||||
|
CU_ASSERT(109 == stream8->weight);
|
||||||
|
CU_ASSERT(10 == stream10->stream_id);
|
||||||
|
CU_ASSERT(16 == stream10->weight);
|
||||||
|
CU_ASSERT(stream10 == stream8->dep_prev);
|
||||||
|
CU_ASSERT(&session->root == stream10->dep_prev);
|
||||||
|
|
||||||
|
/* It is an error to attempt to create already existing idle
|
||||||
|
stream */
|
||||||
|
rv = nghttp2_session_create_idle_stream(session, 4, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
|
||||||
|
/* It is an error to depend on itself */
|
||||||
|
pri_spec.stream_id = 6;
|
||||||
|
|
||||||
|
rv = nghttp2_session_create_idle_stream(session, 6, &pri_spec);
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
|
||||||
|
/* It is an error to create root stream (0) as idle stream */
|
||||||
|
rv = nghttp2_session_create_idle_stream(session, 0, &pri_spec);
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
|
||||||
|
/* It is an error to create non-idle stream */
|
||||||
|
session->next_stream_id = 20;
|
||||||
|
pri_spec.stream_id = 2;
|
||||||
|
|
||||||
|
rv = nghttp2_session_create_idle_stream(session, 18, &pri_spec);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
static void check_nghttp2_http_recv_headers_fail(
|
static void check_nghttp2_http_recv_headers_fail(
|
||||||
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
||||||
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
||||||
|
|
|
@ -136,6 +136,7 @@ void test_nghttp2_session_defer_then_close(void);
|
||||||
void test_nghttp2_session_detach_item_from_closed_stream(void);
|
void test_nghttp2_session_detach_item_from_closed_stream(void);
|
||||||
void test_nghttp2_session_flooding(void);
|
void test_nghttp2_session_flooding(void);
|
||||||
void test_nghttp2_session_change_stream_priority(void);
|
void test_nghttp2_session_change_stream_priority(void);
|
||||||
|
void test_nghttp2_session_create_idle_stream(void);
|
||||||
void test_nghttp2_http_mandatory_headers(void);
|
void test_nghttp2_http_mandatory_headers(void);
|
||||||
void test_nghttp2_http_content_length(void);
|
void test_nghttp2_http_content_length(void);
|
||||||
void test_nghttp2_http_content_length_mismatch(void);
|
void test_nghttp2_http_content_length_mismatch(void);
|
||||||
|
|
Loading…
Reference in New Issue