Merge branch 'priority'

This commit is contained in:
Tatsuhiro Tsujikawa 2014-04-24 23:48:37 +09:00
commit 2d4b92fc2b
17 changed files with 1229 additions and 1289 deletions

View File

@ -114,21 +114,21 @@ typedef struct {
/** /**
* @macro * @macro
* *
* The default weight of priority group. * The default weight of stream dependency.
*/ */
#define NGHTTP2_DEFAULT_WEIGHT 16 #define NGHTTP2_DEFAULT_WEIGHT 16
/** /**
* @macro * @macro
* *
* The maximum weight of priority group. * The maximum weight of stream dependency.
*/ */
#define NGHTTP2_MAX_WEIGHT 256 #define NGHTTP2_MAX_WEIGHT 256
/** /**
* @macro * @macro
* *
* The minimum weight of priority group. * The minimum weight of stream dependency.
*/ */
#define NGHTTP2_MIN_WEIGHT 1 #define NGHTTP2_MIN_WEIGHT 1
@ -482,13 +482,9 @@ typedef enum {
*/ */
NGHTTP2_FLAG_PAD_HIGH = 0x10, NGHTTP2_FLAG_PAD_HIGH = 0x10,
/** /**
* The PRIORITY_GROUP flag. * The PRIORITY flag.
*/ */
NGHTTP2_FLAG_PRIORITY_GROUP = 0x20, NGHTTP2_FLAG_PRIORITY = 0x20
/**
* The PRIORITY_DEPENDENCY flag.
*/
NGHTTP2_FLAG_PRIORITY_DEPENDENCY = 0x40
} nghttp2_flag; } nghttp2_flag;
/** /**
@ -731,93 +727,25 @@ typedef enum {
NGHTTP2_HCAT_HEADERS = 3 NGHTTP2_HCAT_HEADERS = 3
} nghttp2_headers_category; } nghttp2_headers_category;
/**
* @enum
*
* The type of priority specified in :type:`nghttp2_priority_spec`.
*/
typedef enum {
/**
* No priority is given. The default priority will be used.
*/
NGHTTP2_PRIORITY_TYPE_NONE = 0,
/**
* Priority group ID and its weight are specified.
*/
NGHTTP2_PRIORITY_TYPE_GROUP = 1,
/**
* The stream ID of a stream to depend on and its exclusive flag is
* specified.
*/
NGHTTP2_PRIORITY_TYPE_DEP = 2
} nghttp2_priority_type;
/** /**
* @struct * @struct
* *
* This structure stores priority group ID and its weight. * The structure to specify stream dependency.
*/ */
typedef struct { typedef struct {
/** /**
* The priority group ID * The stream ID of the stream to depend on. Specifying 0 makes
*/ * stream not depend any other stream.
int32_t pri_group_id;
/**
* The weight of the priority group
*/
int32_t weight;
} nghttp2_priority_group;
/**
* @struct
*
* This structure stores stream ID of the stream to depend on and its
* dependency is exclusive or not.
*/
typedef struct {
/**
* The stream ID of the stream to depend on.
*/ */
int32_t stream_id; int32_t stream_id;
/**
* The weight of this dependency.
*/
int32_t weight;
/** /**
* nonzero means exclusive dependency * nonzero means exclusive dependency
*/ */
uint8_t exclusive; uint8_t exclusive;
} nghttp2_priority_dep;
/**
* @struct
*
* The structure to specify stream dependency. To specify stream
* dependency, specify |pri_type| and fill the |group| or |dep| member
* according to |pri_type|.
*/
typedef struct {
/**
* Type of priority specification. If |pri_type| is
* :enum:`NGHTTP2_PRIORITY_TYPE_GROUP`, fill |group|. If |pri_type|
* is :enum:`NGHTTP2_PRIORITY_TYPE_DEP`, fill |dep|. If |pri_type|
* is :enum:`NGHTTP2_PRIORITY_TYPE_NONE`, the other data members are
* ignored and it means that default priority group ID (which is
* same as the stream ID) and default weight
* :macro:`NGHTTP2_DEFAULT_WEIGHT` are specified.
*/
nghttp2_priority_type pri_type;
union {
/**
* Specify priority group ID and its weight. This field is
* interpreted only when |pri_type| member is
* :enum:`NGHTTP2_PRIORITY_TYPE_GROUP`.
*/
nghttp2_priority_group group;
/**
* Specify stream ID of a stream to depend on and exclusive flag.
* This field is interpreted only when |pri_type| member is
* :enum:`NGHTTP2_PRIORITY_TYPE_DEP`.
*/
nghttp2_priority_dep dep;
} spec;
} nghttp2_priority_spec; } nghttp2_priority_spec;
/** /**
@ -2153,32 +2081,32 @@ const char* nghttp2_strerror(int lib_error_code);
/** /**
* @function * @function
* *
* Initializes |pri_spec| with priority group ID |pri_group_id| and * Initializes |pri_spec| with the |stream_id| of the stream to depend
* its weight |weight|. * on with |weight| and its exclusive flag. If |exclusive| is
* nonzero, exclusive flag is set.
* *
* The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`, * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
* :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If |weight| is strictly * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.
* less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
* :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
*
* To specify weight for the default priority group (which is the same
* as the stream ID of the stream) in `nghttp2_submit_request()` and
* `nghttp2_submit_headers()` and its stream ID is not known in
* advance, specify -1 to |pri_group_id|.
*/ */
void nghttp2_priority_spec_group_init(nghttp2_priority_spec *pri_spec, void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
int32_t pri_group_id, int32_t weight); int32_t stream_id, int32_t weight,
int exclusive);
/** /**
* @function * @function
* *
* Initializes |pri_spec| with the |stream_id| of the stream to depend * Initializes |pri_spec| with the default values. The default values
* on and its exclusive flag. If |exclusive| is nonzero, exclusive * are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and
* flag is set. * exclusive = 0.
*/ */
void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec, void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec);
int32_t stream_id, int exclusive);
/**
* @function
*
* Returns nonzero if the |pri_spec| is filled with default values.
*/
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
/** /**
* @function * @function
@ -2186,12 +2114,17 @@ void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec,
* Submits HEADERS frame and optionally one or more DATA frames. * Submits HEADERS frame and optionally one or more DATA frames.
* *
* The |pri_spec| is priority specification of this request. ``NULL`` * The |pri_spec| is priority specification of this request. ``NULL``
* means the default priority (priority group ID becomes its stream ID * means the default priority (see
* and weight is :macro:`NGHTTP2_DEFAULT_WEIGHT`). To specify the * `nghttp2_priority_spec_default_init()`). To specify the priority,
* priority, use either `nghttp2_priority_spec_group_init()` or * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``,
* `nghttp2_priority_spec_dep_init()`. If |pri_spec| is not ``NULL``,
* this function will copy its data members. * this function will copy its data members.
* *
* The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
* :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is
* strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
* :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
*
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The value is opaque sequence of bytes and * |nvlen| elements. The value is opaque sequence of bytes and
* therefore can contain NULL byte (0x0). If the application requires * therefore can contain NULL byte (0x0). If the application requires
@ -2234,8 +2167,6 @@ void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec,
* *
* :enum:`NGHTTP2_ERR_NOMEM` * :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory. * Out of memory.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |pri_spec->pri_type| is invalid.
*/ */
int nghttp2_submit_request(nghttp2_session *session, int nghttp2_submit_request(nghttp2_session *session,
const nghttp2_priority_spec *pri_spec, const nghttp2_priority_spec *pri_spec,
@ -2306,12 +2237,17 @@ int nghttp2_submit_response(nghttp2_session *session,
* response, specify stream ID in |stream_id|. * response, specify stream ID in |stream_id|.
* *
* The |pri_spec| is priority specification of this request. ``NULL`` * The |pri_spec| is priority specification of this request. ``NULL``
* means the default priority (priority group ID becomes its stream ID * means the default priority (see
* and weight is :macro:`NGHTTP2_DEFAULT_WEIGHT`). To specify the * `nghttp2_priority_spec_default_init()`). To specify the priority,
* priority, use either `nghttp2_priority_spec_group_init()` or * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``,
* `nghttp2_priority_spec_dep_init()`. If |pri_spec| is not ``NULL``,
* this function will copy its data members. * this function will copy its data members.
* *
* The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
* :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is
* strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
* :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
*
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The value is opaque sequence of bytes and * |nvlen| elements. The value is opaque sequence of bytes and
* therefore can contain NULL byte (0x0). If the application requires * therefore can contain NULL byte (0x0). If the application requires
@ -2336,8 +2272,6 @@ int nghttp2_submit_response(nghttp2_session *session,
* *
* :enum:`NGHTTP2_ERR_NOMEM` * :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory. * Out of memory.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |pri_spec->pri_type| is invalid.
*/ */
int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
int32_t stream_id, int32_t stream_id,
@ -2379,10 +2313,15 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
* :enum:`NGHTTP2_FLAG_NONE`. * :enum:`NGHTTP2_FLAG_NONE`.
* *
* The |pri_spec| is priority specification of this request. ``NULL`` * The |pri_spec| is priority specification of this request. ``NULL``
* is not allowed for this function. To specify the priority, use * is not allowed for this function. To specify the priority, use
* either `nghttp2_priority_spec_group_init()` or * `nghttp2_priority_spec_init()`. This function will copy its data
* `nghttp2_priority_spec_dep_init()`. This function will copy its * members.
* data members. *
* The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
* :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is
* strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
* :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -2390,8 +2329,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
* :enum:`NGHTTP2_ERR_NOMEM` * :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory. * Out of memory.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |pri_spec| is NULL; or the |pri_spec->pri_type| is invalid; * The |pri_spec| is NULL; or trying to depend on itself.
* or trying to depend on itself.
*/ */
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
int32_t stream_id, int32_t stream_id,

View File

@ -74,7 +74,12 @@ void nghttp2_frame_headers_init(nghttp2_headers *frame,
frame->nva = nva; frame->nva = nva;
frame->nvlen = nvlen; frame->nvlen = nvlen;
frame->cat = NGHTTP2_HCAT_REQUEST; frame->cat = NGHTTP2_HCAT_REQUEST;
frame->pri_spec = *pri_spec;
if(pri_spec) {
frame->pri_spec = *pri_spec;
} else {
nghttp2_priority_spec_default_init(&frame->pri_spec);
}
} }
void nghttp2_frame_headers_free(nghttp2_headers *frame) void nghttp2_frame_headers_free(nghttp2_headers *frame)
@ -85,22 +90,8 @@ void nghttp2_frame_headers_free(nghttp2_headers *frame)
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id, void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
const nghttp2_priority_spec *pri_spec) const nghttp2_priority_spec *pri_spec)
{ {
uint8_t flags; nghttp2_frame_set_hd(&frame->hd, 5, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE,
stream_id);
switch(pri_spec->pri_type) {
case NGHTTP2_PRIORITY_TYPE_GROUP:
flags = NGHTTP2_FLAG_PRIORITY_GROUP;
break;
case NGHTTP2_PRIORITY_TYPE_DEP:
flags = NGHTTP2_FLAG_PRIORITY_DEPENDENCY;
break;
default:
assert(0);
}
nghttp2_frame_set_hd(&frame->hd, 4, NGHTTP2_PRIORITY, flags, stream_id);
frame->pri_spec = *pri_spec; frame->pri_spec = *pri_spec;
} }
@ -261,14 +252,10 @@ void nghttp2_frame_private_data_free(nghttp2_private_data *frame)
size_t nghttp2_frame_priority_len(uint8_t flags) size_t nghttp2_frame_priority_len(uint8_t flags)
{ {
if(flags & NGHTTP2_FLAG_PRIORITY_GROUP) { if(flags & NGHTTP2_FLAG_PRIORITY) {
return 5; return 5;
} }
if(flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
return 4;
}
return 0; return 0;
} }
@ -375,7 +362,9 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
return rv; return rv;
} }
nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec); if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec);
}
frame->padlen = 0; frame->padlen = 0;
frame->hd.length = nghttp2_bufs_len(bufs); frame->hd.length = nghttp2_bufs_len(bufs);
@ -386,24 +375,11 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
void nghttp2_frame_pack_priority_spec(uint8_t *buf, void nghttp2_frame_pack_priority_spec(uint8_t *buf,
const nghttp2_priority_spec *pri_spec) const nghttp2_priority_spec *pri_spec)
{ {
switch(pri_spec->pri_type) { nghttp2_put_uint32be(buf, pri_spec->stream_id);
case NGHTTP2_PRIORITY_TYPE_GROUP: if(pri_spec->exclusive) {
buf[0] |= 0x80;
nghttp2_put_uint32be(buf, pri_spec->spec.group.pri_group_id);
buf[4] = pri_spec->spec.group.weight - 1;
return;
case NGHTTP2_PRIORITY_TYPE_DEP:
nghttp2_put_uint32be(buf, pri_spec->spec.dep.stream_id);
if(pri_spec->spec.dep.exclusive) {
buf[0] |= 0x80;
}
return;
default:
return;
} }
buf[4] = pri_spec->weight - 1;
} }
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
@ -411,33 +387,28 @@ void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
const uint8_t *payload, const uint8_t *payload,
size_t payloadlen) size_t payloadlen)
{ {
if(flags & NGHTTP2_FLAG_PRIORITY_GROUP) { int32_t dep_stream_id;
int32_t pri_group_id; uint8_t exclusive;
int32_t weight; int32_t weight;
pri_group_id = nghttp2_get_uint32(payload) & NGHTTP2_PRI_GROUP_ID_MASK; dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
weight = payload[4] + 1; exclusive = (payload[0] & 0x80) > 0;
weight = payload[4] + 1;
nghttp2_priority_spec_group_init(pri_spec, pri_group_id, weight); nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive);
} else if(flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
int32_t dep_stream_id;
uint8_t exclusive;
dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
exclusive = (payload[0] & 0x80) > 0;
nghttp2_priority_spec_dep_init(pri_spec, dep_stream_id, exclusive);
} else {
pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_NONE;
}
} }
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
const uint8_t *payload, const uint8_t *payload,
size_t payloadlen) size_t payloadlen)
{ {
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags, if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
payload, payloadlen); nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags,
payload, payloadlen);
} else {
nghttp2_priority_spec_default_init(&frame->pri_spec);
}
frame->nva = NULL; frame->nva = NULL;
frame->nvlen = 0; frame->nvlen = 0;
@ -457,7 +428,7 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame)
nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec); nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec);
buf->last += nghttp2_frame_priority_len(frame->hd.flags); buf->last += 5;
return 0; return 0;
} }

View File

@ -155,7 +155,8 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
/* /*
* Unpacks HEADERS frame byte sequence into |frame|. This function * Unpacks HEADERS frame byte sequence into |frame|. This function
* only unapcks bytes that come before name/value header block. * only unapcks bytes that come before name/value header block and
* after PAD_HIGH and PAD_LOW.
* *
* This function returns 0 if it succeeds or one of the following * This function returns 0 if it succeeds or one of the following
* negative error codes: * negative error codes:

View File

@ -24,18 +24,25 @@
*/ */
#include "nghttp2_priority_spec.h" #include "nghttp2_priority_spec.h"
void nghttp2_priority_spec_group_init(nghttp2_priority_spec *pri_spec, void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
int32_t pri_group_id, int32_t weight) int32_t stream_id, int32_t weight,
int exclusive)
{ {
pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_GROUP; pri_spec->stream_id = stream_id;
pri_spec->spec.group.pri_group_id = pri_group_id; pri_spec->weight = weight;
pri_spec->spec.group.weight = weight; pri_spec->exclusive = exclusive != 0;
} }
void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec, void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec)
int32_t stream_id, int exclusive)
{ {
pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_DEP; pri_spec->stream_id = 0;
pri_spec->spec.dep.stream_id = stream_id; pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT;
pri_spec->spec.dep.exclusive = exclusive != 0; pri_spec->exclusive = 0;
}
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec)
{
return pri_spec->stream_id == 0 &&
pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT &&
pri_spec->exclusive == 0;
} }

View File

@ -147,13 +147,6 @@ nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
return (nghttp2_stream*)nghttp2_map_find(&session->streams, stream_id); return (nghttp2_stream*)nghttp2_map_find(&session->streams, stream_id);
} }
nghttp2_stream_group* nghttp2_session_get_stream_group
(nghttp2_session *session, int32_t pri_group_id)
{
return (nghttp2_stream_group*)nghttp2_map_find(&session->stream_groups,
pri_group_id);
}
static int nghttp2_outbound_item_compar(const void *lhsx, const void *rhsx) static int nghttp2_outbound_item_compar(const void *lhsx, const void *rhsx)
{ {
const nghttp2_outbound_item *lhs, *rhs; const nghttp2_outbound_item *lhs, *rhs;
@ -287,10 +280,7 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
goto fail_map; goto fail_map;
} }
rv = nghttp2_map_init(&(*session_ptr)->stream_groups); nghttp2_stream_roots_init(&(*session_ptr)->roots);
if(rv != 0) {
goto fail_group_map;
}
(*session_ptr)->next_seq = 0; (*session_ptr)->next_seq = 0;
@ -359,8 +349,6 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
return 0; return 0;
fail_aob_framebuf: fail_aob_framebuf:
nghttp2_map_free(&(*session_ptr)->stream_groups);
fail_group_map:
nghttp2_map_free(&(*session_ptr)->streams); nghttp2_map_free(&(*session_ptr)->streams);
fail_map: fail_map:
nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater); nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater);
@ -432,14 +420,6 @@ static int nghttp2_free_streams(nghttp2_map_entry *entry, void *ptr)
return 0; return 0;
} }
static int nghttp2_free_stream_groups(nghttp2_map_entry *entry, void *ptr)
{
nghttp2_stream_group_free((nghttp2_stream_group*)entry);
free(entry);
return 0;
}
static void nghttp2_session_ob_pq_free(nghttp2_pq *pq) static void nghttp2_session_ob_pq_free(nghttp2_pq *pq)
{ {
while(!nghttp2_pq_empty(pq)) { while(!nghttp2_pq_empty(pq)) {
@ -458,15 +438,13 @@ void nghttp2_session_del(nghttp2_session *session)
} }
free(session->inflight_iv); free(session->inflight_iv);
nghttp2_stream_roots_free(&session->roots);
/* Have to free streams first, so that we can check /* Have to free streams first, so that we can check
stream->data_item->queued */ stream->data_item->queued */
nghttp2_map_each_free(&session->streams, nghttp2_free_streams, NULL); nghttp2_map_each_free(&session->streams, nghttp2_free_streams, NULL);
nghttp2_map_free(&session->streams); nghttp2_map_free(&session->streams);
nghttp2_map_each_free(&session->stream_groups, nghttp2_free_stream_groups,
NULL);
nghttp2_map_free(&session->stream_groups);
nghttp2_session_ob_pq_free(&session->ob_pq); nghttp2_session_ob_pq_free(&session->ob_pq);
nghttp2_session_ob_pq_free(&session->ob_ss_pq); nghttp2_session_ob_pq_free(&session->ob_ss_pq);
nghttp2_active_outbound_item_reset(&session->aob); nghttp2_active_outbound_item_reset(&session->aob);
@ -482,99 +460,71 @@ int nghttp2_session_reprioritize_stream
const nghttp2_priority_spec *pri_spec) const nghttp2_priority_spec *pri_spec)
{ {
int rv; int rv;
nghttp2_stream_group *stream_group;
nghttp2_stream_group *old_stream_group;
nghttp2_stream *dep_stream; nghttp2_stream *dep_stream;
nghttp2_stream *root_stream; nghttp2_stream *root_stream;
const nghttp2_priority_group *group;
const nghttp2_priority_dep *dep;
switch(pri_spec->pri_type) { if(pri_spec->stream_id == stream->stream_id) {
case NGHTTP2_PRIORITY_TYPE_GROUP: return nghttp2_session_terminate_session(session,
group = &pri_spec->spec.group; NGHTTP2_PROTOCOL_ERROR);
}
old_stream_group = stream->stream_group;
if(pri_spec->stream_id == 0) {
nghttp2_stream_dep_remove_subtree(stream); nghttp2_stream_dep_remove_subtree(stream);
stream_group = nghttp2_session_get_stream_group(session, /* We have to update weight after removing stream from tree */
group->pri_group_id); stream->weight = pri_spec->weight;
if(stream_group == NULL) { if(pri_spec->exclusive &&
stream_group = nghttp2_session_open_stream_group(session, session->roots.num_streams <= NGHTTP2_MAX_DEP_TREE_LENGTH) {
group->pri_group_id,
group->weight);
if(stream_group == NULL) { rv = nghttp2_stream_dep_all_your_stream_are_belong_to_us
return NGHTTP2_ERR_NOMEM; (stream, &session->ob_pq);
}
} else { } else {
stream_group->weight = group->weight; rv = nghttp2_stream_dep_make_root(stream, &session->ob_pq);
} }
rv = nghttp2_stream_dep_make_root(stream_group, stream, &session->ob_pq); return rv;
}
if(rv != 0) { dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
return rv;
}
nghttp2_session_close_stream_group_if_empty(session, old_stream_group);
if(!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) {
return 0; return 0;
}
case NGHTTP2_PRIORITY_TYPE_DEP: if(nghttp2_stream_dep_subtree_find(stream, dep_stream)) {
dep = &pri_spec->spec.dep; DEBUGF(fprintf(stderr,
"stream: cycle detected, dep_stream(%p)=%d "
"stream(%p)=%d\n",
dep_stream, dep_stream->stream_id,
stream, stream->stream_id));
if(dep->stream_id == stream->stream_id || dep->stream_id == 0) { nghttp2_stream_dep_remove_subtree(dep_stream);
return nghttp2_session_terminate_session(session, nghttp2_stream_dep_make_root(dep_stream, &session->ob_pq);
NGHTTP2_PROTOCOL_ERROR); }
}
old_stream_group = stream->stream_group; nghttp2_stream_dep_remove_subtree(stream);
dep_stream = nghttp2_session_get_stream_raw(session, dep->stream_id); /* We have to update weight after removing stream from tree */
stream->weight = pri_spec->weight;
if(dep_stream == NULL) { root_stream = nghttp2_stream_get_dep_root(dep_stream);
return 0;
}
/* Ignore priority request if resultant tree has cycle */ if(root_stream->num_substreams + stream->num_substreams >
if(nghttp2_stream_dep_subtree_find(stream, dep_stream)) { NGHTTP2_MAX_DEP_TREE_LENGTH) {
DEBUGF(fprintf(stderr, rv = nghttp2_stream_dep_make_root(stream, &session->ob_pq);
"stream: future cycle detected, dep_stream(%p)=%d " } else {
"stream(%p)=%d\n", if(pri_spec->exclusive) {
dep_stream, dep_stream->stream_id, rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream,
stream, stream->stream_id)); &session->ob_pq);
return 0;
}
nghttp2_stream_dep_remove_subtree(stream);
root_stream = nghttp2_stream_get_dep_root(dep_stream);
if(root_stream->num_substreams + stream->num_substreams >
NGHTTP2_MAX_DEP_TREE_LENGTH) {
rv = nghttp2_stream_dep_make_root(dep_stream->stream_group, stream,
&session->ob_pq);
} else { } else {
if(dep->exclusive) { rv = nghttp2_stream_dep_add_subtree(dep_stream, stream,
rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream, &session->ob_pq);
&session->ob_pq);
} else {
rv = nghttp2_stream_dep_add_subtree(dep_stream, stream,
&session->ob_pq);
}
} }
}
if(rv != 0) { if(rv != 0) {
return rv; return rv;
}
nghttp2_session_close_stream_group_if_empty(session, old_stream_group);
return 0;
default:
assert(0);
} }
return 0; return 0;
@ -615,24 +565,30 @@ int nghttp2_session_add_frame(nghttp2_session *session,
if(frame->hd.stream_id == -1) { if(frame->hd.stream_id == -1) {
/* Initial HEADERS, which will open stream */ /* Initial HEADERS, which will open stream */
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { /* TODO If we always frame.headers.pri_spec filled in, we
item->weight = frame->headers.pri_spec.spec.group.weight; don't have to check flags */
} else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
dep_stream = nghttp2_session_get_stream if(frame->headers.pri_spec.stream_id == 0) {
(session, frame->headers.pri_spec.spec.dep.stream_id); item->weight = frame->headers.pri_spec.weight;
if(dep_stream) {
item->weight = dep_stream->stream_group->weight;
} else { } else {
item->weight = NGHTTP2_DEFAULT_WEIGHT; dep_stream = nghttp2_session_get_stream
(session, frame->headers.pri_spec.stream_id);
if(dep_stream) {
item->weight = nghttp2_stream_dep_distributed_effective_weight
(dep_stream, frame->headers.pri_spec.weight);
} else {
item->weight = frame->headers.pri_spec.weight;
}
} }
} else { } else {
item->weight = NGHTTP2_DEFAULT_WEIGHT; item->weight = NGHTTP2_DEFAULT_WEIGHT;
} }
} else if(stream) { } else if(stream) {
/* Otherwise, the frame must have stream ID. We use its /* Otherwise, the frame must have stream ID. We use its
priority value. */ effective_weight. */
item->weight = stream->stream_group->weight; item->weight = stream->effective_weight;
} }
break; break;
case NGHTTP2_PRIORITY: case NGHTTP2_PRIORITY:
@ -656,7 +612,7 @@ int nghttp2_session_add_frame(nghttp2_session *session,
case NGHTTP2_PUSH_PROMISE: case NGHTTP2_PUSH_PROMISE:
/* Use priority of associated stream */ /* Use priority of associated stream */
if(stream) { if(stream) {
item->weight = stream->stream_group->weight; item->weight = stream->effective_weight;
} }
break; break;
@ -699,7 +655,7 @@ int nghttp2_session_add_frame(nghttp2_session *session,
if(stream->data_item) { if(stream->data_item) {
rv = NGHTTP2_ERR_DATA_EXIST; rv = NGHTTP2_ERR_DATA_EXIST;
} else { } else {
item->weight = nghttp2_stream_group_shared_wait(stream->stream_group); item->weight = stream->effective_weight;
rv = nghttp2_stream_attach_data(stream, item, &session->ob_pq); rv = nghttp2_stream_attach_data(stream, item, &session->ob_pq);
} }
@ -756,57 +712,18 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
nghttp2_stream *stream; nghttp2_stream *stream;
nghttp2_stream *dep_stream; nghttp2_stream *dep_stream;
nghttp2_stream *root_stream; nghttp2_stream *root_stream;
int32_t pri_group_id;
int32_t weight;
nghttp2_stream_group *stream_group;
dep_stream = NULL;
if(session->server && !nghttp2_session_is_my_stream_id(session, stream_id)) { if(session->server && !nghttp2_session_is_my_stream_id(session, stream_id)) {
nghttp2_session_adjust_closed_stream(session, 1); nghttp2_session_adjust_closed_stream(session, 1);
} }
switch(pri_spec->pri_type) {
case NGHTTP2_PRIORITY_TYPE_GROUP:
pri_group_id = pri_spec->spec.group.pri_group_id;
weight = pri_spec->spec.group.weight;
break;
case NGHTTP2_PRIORITY_TYPE_DEP:
dep_stream = nghttp2_session_get_stream_raw(session,
pri_spec->spec.dep.stream_id);
if(dep_stream) {
pri_group_id = dep_stream->stream_group->pri_group_id;
weight = dep_stream->stream_group->weight;
} else {
pri_group_id = stream_id;
weight = NGHTTP2_DEFAULT_WEIGHT;
}
break;
default:
pri_group_id = stream_id;
weight = NGHTTP2_DEFAULT_WEIGHT;
};
stream_group = nghttp2_session_get_stream_group(session, pri_group_id);
if(stream_group == NULL) {
stream_group = nghttp2_session_open_stream_group(session, pri_group_id,
weight);
if(stream_group == NULL) {
return NULL;
}
}
stream = malloc(sizeof(nghttp2_stream)); stream = malloc(sizeof(nghttp2_stream));
if(stream == NULL) { if(stream == NULL) {
return NULL; return NULL;
} }
nghttp2_stream_init(stream, stream_id, flags, initial_state, nghttp2_stream_init(stream, stream_id, flags, initial_state,
pri_spec->weight, &session->roots,
session->remote_settings session->remote_settings
[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], [NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
session->local_settings session->local_settings
@ -819,8 +736,6 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
return NULL; return NULL;
} }
nghttp2_stream_group_add_stream(stream_group, stream);
if(initial_state == NGHTTP2_STREAM_RESERVED) { if(initial_state == NGHTTP2_STREAM_RESERVED) {
if(nghttp2_session_is_my_stream_id(session, stream_id)) { if(nghttp2_session_is_my_stream_id(session, stream_id)) {
/* half closed (remote) */ /* half closed (remote) */
@ -839,15 +754,34 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
} }
} }
/* Possibly update weight of priority group */
stream_group->weight = weight;
/* We don't have to track dependency of received reserved stream */ /* We don't have to track dependency of received reserved stream */
if(stream->shut_flags & NGHTTP2_SHUT_WR) { if(stream->shut_flags & NGHTTP2_SHUT_WR) {
return stream; return stream;
} }
if(!dep_stream) { if(pri_spec->stream_id == 0) {
++session->roots.num_streams;
if(pri_spec->exclusive &&
session->roots.num_streams <= NGHTTP2_MAX_DEP_TREE_LENGTH) {
rv = nghttp2_stream_dep_all_your_stream_are_belong_to_us
(stream, &session->ob_pq);
/* Since no dpri is changed in dependency tree, the above
function call never fail. */
assert(rv == 0);
} else {
nghttp2_stream_roots_add(&session->roots, stream);
}
return stream;
}
dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
/* If dep_stream is not part of dependency tree, we don't use it. */
if(!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) {
return stream; return stream;
} }
@ -858,7 +792,7 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
root_stream = nghttp2_stream_get_dep_root(dep_stream); root_stream = nghttp2_stream_get_dep_root(dep_stream);
if(root_stream->num_substreams < NGHTTP2_MAX_DEP_TREE_LENGTH) { if(root_stream->num_substreams < NGHTTP2_MAX_DEP_TREE_LENGTH) {
if(pri_spec->spec.dep.exclusive) { if(pri_spec->exclusive) {
nghttp2_stream_dep_insert(dep_stream, stream); nghttp2_stream_dep_insert(dep_stream, stream);
} else { } else {
nghttp2_stream_dep_add(dep_stream, stream); nghttp2_stream_dep_add(dep_stream, stream);
@ -929,7 +863,9 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
/* Closes both directions just in case they are not closed yet */ /* Closes both directions just in case they are not closed yet */
stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED; stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED;
if(session->server && !nghttp2_session_is_my_stream_id(session, stream_id)) { if(session->server &&
nghttp2_stream_in_dep_tree(stream) &&
!nghttp2_session_is_my_stream_id(session, stream_id)) {
/* On server side, retain incoming stream object at most /* On server side, retain incoming stream object at most
MAX_CONCURRENT_STREAMS combined with the current active streams MAX_CONCURRENT_STREAMS combined with the current active streams
to make dependency tree work better. */ to make dependency tree work better. */
@ -944,18 +880,11 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
void nghttp2_session_destroy_stream(nghttp2_session *session, void nghttp2_session_destroy_stream(nghttp2_session *session,
nghttp2_stream *stream) nghttp2_stream *stream)
{ {
nghttp2_stream_group *stream_group;
DEBUGF(fprintf(stderr, "stream: destroy closed stream(%p)=%d\n", DEBUGF(fprintf(stderr, "stream: destroy closed stream(%p)=%d\n",
stream, stream->stream_id)); stream, stream->stream_id));
nghttp2_stream_dep_remove(stream); nghttp2_stream_dep_remove(stream);
stream_group = stream->stream_group;
nghttp2_stream_group_remove_stream(stream_group, stream);
nghttp2_session_close_stream_group_if_empty(session, stream_group);
nghttp2_map_remove(&session->streams, stream->stream_id); nghttp2_map_remove(&session->streams, stream->stream_id);
nghttp2_stream_free(stream); nghttp2_stream_free(stream);
free(stream); free(stream);
@ -1537,15 +1466,6 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
frame->hd.stream_id = session->next_stream_id; frame->hd.stream_id = session->next_stream_id;
session->next_stream_id += 2; session->next_stream_id += 2;
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) {
if(frame->headers.pri_spec.spec.group.pri_group_id == -1) {
/* We now know stream_id. Assign stream_id to
pri_group_id if it is -1. */
frame->headers.pri_spec.spec.group.pri_group_id =
frame->hd.stream_id;
}
}
} else if(nghttp2_session_predicate_push_response_headers_send } else if(nghttp2_session_predicate_push_response_headers_send
(session, frame->hd.stream_id) == 0) { (session, frame->hd.stream_id) == 0) {
frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE;
@ -1665,7 +1585,8 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
/* TODO It is unclear reserved stream dpeneds on associated /* TODO It is unclear reserved stream dpeneds on associated
stream with or without exclusive flag set */ stream with or without exclusive flag set */
nghttp2_priority_spec_dep_init(&pri_spec, stream->stream_id, 0); nghttp2_priority_spec_init(&pri_spec, stream->stream_id,
NGHTTP2_DEFAULT_WEIGHT, 0);
if(!nghttp2_session_open_stream if(!nghttp2_session_open_stream
(session, frame->push_promise.promised_stream_id, (session, frame->push_promise.promised_stream_id,
@ -2159,8 +2080,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
assert(stream); assert(stream);
next_item = nghttp2_session_get_next_ob_item(session); next_item = nghttp2_session_get_next_ob_item(session);
outbound_item_cycle_weight outbound_item_cycle_weight(aob->item, stream->effective_weight);
(aob->item, nghttp2_stream_group_shared_wait(stream->stream_group));
/* If priority of this stream is higher or equal to other stream /* If priority of this stream is higher or equal to other stream
waiting at the top of the queue, we continue to send this waiting at the top of the queue, we continue to send this
@ -2855,9 +2775,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
(session, frame, NGHTTP2_ENHANCE_YOUR_CALM); (session, frame, NGHTTP2_ENHANCE_YOUR_CALM);
} }
if(frame->headers.pri_spec.pri_type == NGHTTP2_PRIORITY_TYPE_DEP && if(frame->headers.pri_spec.stream_id == frame->hd.stream_id) {
(frame->headers.pri_spec.spec.dep.stream_id == frame->hd.stream_id ||
frame->headers.pri_spec.spec.dep.stream_id == 0)) {
return nghttp2_session_inflate_handle_invalid_connection return nghttp2_session_inflate_handle_invalid_connection
(session, frame, NGHTTP2_PROTOCOL_ERROR); (session, frame, NGHTTP2_PROTOCOL_ERROR);
} }
@ -3508,7 +3426,8 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
/* TODO It is unclear reserved stream dpeneds on associated /* TODO It is unclear reserved stream dpeneds on associated
stream with or without exclusive flag set */ stream with or without exclusive flag set */
nghttp2_priority_spec_dep_init(&pri_spec, stream->stream_id, 0); nghttp2_priority_spec_init(&pri_spec, stream->stream_id,
NGHTTP2_DEFAULT_WEIGHT, 0);
promised_stream = nghttp2_session_open_stream promised_stream = nghttp2_session_open_stream
(session, (session,
@ -4229,15 +4148,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PAD_LOW | NGHTTP2_FLAG_PAD_LOW |
NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_HIGH |
NGHTTP2_FLAG_PRIORITY_GROUP | NGHTTP2_FLAG_PRIORITY);
NGHTTP2_FLAG_PRIORITY_DEPENDENCY);
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if(rv < 0 || if(rv < 0) {
(iframe->frame.hd.flags & (NGHTTP2_FLAG_PRIORITY_GROUP |
NGHTTP2_FLAG_PRIORITY_DEPENDENCY)) ==
(NGHTTP2_FLAG_PRIORITY_GROUP | NGHTTP2_FLAG_PRIORITY_DEPENDENCY)) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD; iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
@ -4287,34 +4201,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
break; break;
case NGHTTP2_PRIORITY: case NGHTTP2_PRIORITY:
pri_fieldlen = 0;
DEBUGF(fprintf(stderr, "recv: PRIORITY\n")); DEBUGF(fprintf(stderr, "recv: PRIORITY\n"));
iframe->frame.hd.flags &= (NGHTTP2_FLAG_PRIORITY_GROUP | iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
NGHTTP2_FLAG_PRIORITY_DEPENDENCY);
pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); if(iframe->payloadleft != 5) {
if(iframe->frame.hd.flags == (NGHTTP2_FLAG_PRIORITY_GROUP |
NGHTTP2_FLAG_PRIORITY_DEPENDENCY) ||
pri_fieldlen == 0) {
busy = 1;
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
if(nghttp2_is_fatal(rv)) {
return rv;
}
break;
}
if(pri_fieldlen != iframe->payloadleft) {
busy = 1; busy = 1;
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
@ -4324,7 +4215,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_set_mark(iframe, pri_fieldlen); inbound_frame_set_mark(iframe, 5);
break; break;
case NGHTTP2_RST_STREAM: case NGHTTP2_RST_STREAM:
@ -4535,6 +4426,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->state = NGHTTP2_IB_READ_NBYTE;
inbound_frame_set_mark(iframe, pri_fieldlen); inbound_frame_set_mark(iframe, pri_fieldlen);
break; break;
} else {
/* Truncate buffers used for padding spec */
inbound_frame_set_mark(iframe, 0);
} }
} }
@ -5653,7 +5547,7 @@ int nghttp2_session_upgrade(nghttp2_session *session,
return rv; return rv;
} }
nghttp2_priority_spec_group_init(&pri_spec, 1, NGHTTP2_DEFAULT_WEIGHT); nghttp2_priority_spec_default_init(&pri_spec);
stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
&pri_spec, NGHTTP2_STREAM_OPENING, &pri_spec, NGHTTP2_STREAM_OPENING,
@ -5672,41 +5566,3 @@ int nghttp2_session_upgrade(nghttp2_session *session,
} }
return 0; return 0;
} }
nghttp2_stream_group* nghttp2_session_open_stream_group
(nghttp2_session *session, int32_t pri_group_id, int32_t weight)
{
int rv;
nghttp2_stream_group *stream_group;
stream_group = malloc(sizeof(nghttp2_stream_group));
if(stream_group == NULL) {
return NULL;
}
nghttp2_stream_group_init(stream_group, pri_group_id, weight);
rv = nghttp2_map_insert(&session->stream_groups, &stream_group->map_entry);
if(rv != 0) {
free(stream_group);
return NULL;
}
return stream_group;
}
void nghttp2_session_close_stream_group_if_empty
(nghttp2_session *session, nghttp2_stream_group *stream_group)
{
if(stream_group->num_streams == 0) {
DEBUGF(fprintf(stderr, "stream: stream_group(%p)=%d closed\n",
stream_group, stream_group->pri_group_id));
nghttp2_map_remove(&session->stream_groups, stream_group->pri_group_id);
nghttp2_stream_group_free(stream_group);
free(stream_group);
}
}

View File

@ -117,7 +117,7 @@ typedef enum {
struct nghttp2_session { struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams; nghttp2_map /* <nghttp2_stream*> */ streams;
nghttp2_map /* <nghttp2_stream_group*> */ stream_groups; nghttp2_stream_roots roots;
/* Queue for outbound frames other than stream-creating HEADERS */ /* Queue for outbound frames other than stream-creating HEADERS */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq; nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
/* Queue for outbound stream-creating HEADERS frame */ /* Queue for outbound stream-creating HEADERS frame */
@ -603,14 +603,6 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session, nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
int32_t stream_id); int32_t stream_id);
/*
* Returns nghttp2_stream_group* object whose priority group ID is
* |pri_group_id|. It could be NULL if such priority group does not
* exist.
*/
nghttp2_stream_group* nghttp2_session_get_stream_group
(nghttp2_session *session, int32_t pri_group_id);
/* /*
* Packs DATA frame |frame| in wire frame format and stores it in * Packs DATA frame |frame| in wire frame format and stores it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
@ -698,19 +690,4 @@ int nghttp2_session_reprioritize_stream
(nghttp2_session *session, nghttp2_stream *stream, (nghttp2_session *session, nghttp2_stream *stream,
const nghttp2_priority_spec *pri_spec); const nghttp2_priority_spec *pri_spec);
/*
* Creates new priority group using given values.
*
* This function returns created priority group if it succeeds, or
* NULL.
*/
nghttp2_stream_group* nghttp2_session_open_stream_group
(nghttp2_session *session, int32_t pri_group_id, int32_t weight);
/*
* Closes priority group if it does not include any streams.
*/
void nghttp2_session_close_stream_group_if_empty
(nghttp2_session *session, nghttp2_stream_group *stream_group);
#endif /* NGHTTP2_SESSION_H */ #endif /* NGHTTP2_SESSION_H */

View File

@ -32,6 +32,8 @@
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, uint8_t flags,
nghttp2_stream_state initial_state, nghttp2_stream_state initial_state,
int32_t weight,
nghttp2_stream_roots *roots,
int32_t remote_initial_window_size, int32_t remote_initial_window_size,
int32_t local_initial_window_size, int32_t local_initial_window_size,
void *stream_user_data) void *stream_user_data)
@ -55,10 +57,16 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->closed_next = NULL; stream->closed_next = NULL;
stream->stream_group = NULL;
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA; stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
stream->num_substreams = 1; stream->num_substreams = 1;
stream->num_subtop = 0; stream->weight = weight;
stream->effective_weight = stream->weight;
stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0;
stream->roots = roots;
stream->root_prev = NULL;
stream->root_next = NULL;
} }
void nghttp2_stream_free(nghttp2_stream *stream) void nghttp2_stream_free(nghttp2_stream *stream)
@ -79,15 +87,12 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
static int stream_push_data(nghttp2_stream *stream, nghttp2_pq *pq) static int stream_push_data(nghttp2_stream *stream, nghttp2_pq *pq)
{ {
int rv; int rv;
ssize_t weight;
assert(stream->data_item); assert(stream->data_item);
assert(stream->data_item->queued == 0); assert(stream->data_item->queued == 0);
weight = nghttp2_stream_group_shared_wait(stream->stream_group); if(stream->data_item->weight > stream->effective_weight) {
stream->data_item->weight = stream->effective_weight;
if(stream->data_item->weight > weight) {
stream->data_item->weight = weight;
} }
rv = nghttp2_pq_push(pq, stream->data_item); rv = nghttp2_pq_push(pq, stream->data_item);
@ -129,39 +134,49 @@ static nghttp2_stream* stream_update_dep_length(nghttp2_stream *stream,
return stream; return stream;
} }
static nghttp2_stream* stream_update_dep_both_length(nghttp2_stream *stream, int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
ssize_t delta_stream, int32_t weight)
ssize_t delta_top)
{ {
stream->num_substreams += delta_stream; weight = stream->weight * weight / stream->sum_dep_weight;
stream->num_subtop += delta_top;
stream = stream_first_sib(stream); return nghttp2_max(1, weight);
if(stream->dep_prev) {
return stream_update_dep_both_length(stream->dep_prev, delta_stream,
delta_top);
}
return stream;
} }
static void stream_update_dep_set_rest_stream_group int32_t nghttp2_stream_dep_distributed_effective_weight
(nghttp2_stream *stream, nghttp2_stream_group *stream_group) (nghttp2_stream *stream, int32_t weight)
{ {
if(stream == NULL) { weight = stream->effective_weight * weight / stream->sum_norest_weight;
return nghttp2_max(1, weight);
}
/* Updates effective_weight of descendant streams in subtree of
|stream|. We assume that stream->effective_weight is already set
right. */
static void stream_update_dep_effective_weight(nghttp2_stream *stream)
{
nghttp2_stream *si;
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
stream, stream->stream_id, stream->weight,
stream->sum_norest_weight));
/* stream->sum_norest_weight == 0 means there is no
NGHTTP2_STREAM_DPRI_TOP under stream */
if(stream->dpri != NGHTTP2_STREAM_DPRI_NO_DATA ||
stream->sum_norest_weight == 0) {
return; return;
} }
nghttp2_stream_group_remove_stream(stream->stream_group, stream); for(si = stream->dep_next; si; si = si->sib_next) {
nghttp2_stream_group_add_stream(stream_group, stream); if(si->dpri != NGHTTP2_STREAM_DPRI_REST) {
si->effective_weight = nghttp2_stream_dep_distributed_effective_weight
(stream, si->weight);
}
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { stream_update_dep_effective_weight(si);
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
} }
stream_update_dep_set_rest_stream_group(stream->sib_next, stream_group);
stream_update_dep_set_rest_stream_group(stream->dep_next, stream_group);
} }
static void stream_update_dep_set_rest(nghttp2_stream *stream) static void stream_update_dep_set_rest(nghttp2_stream *stream)
@ -174,8 +189,6 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
return; return;
} }
stream->num_subtop = 0;
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
stream->dpri = NGHTTP2_STREAM_DPRI_REST; stream->dpri = NGHTTP2_STREAM_DPRI_REST;
@ -192,37 +205,22 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
* Performs dfs starting |stream|, search stream which can become * Performs dfs starting |stream|, search stream which can become
* NGHTTP2_STREAM_DPRI_TOP and queues its data_item. * NGHTTP2_STREAM_DPRI_TOP and queues its data_item.
* *
* This function returns the number of stream marked as * This function returns 0 if it succeeds, or one of the following
* NGHTTP2_STREAM_DPRI_TOP (including already marked as such) if it * negative error codes:
* succeeds, or one of the following negative error codes:
* *
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory. * Out of memory.
*/ */
static ssize_t stream_update_dep_set_top(nghttp2_stream *stream, static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq)
nghttp2_pq *pq)
{ {
ssize_t rv; int rv;
ssize_t num_top; nghttp2_stream *si;
if(stream == NULL) { if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 0; return 0;
} }
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
rv = stream_update_dep_set_top(stream->sib_next, pq);
if(rv < 0) {
return rv;
}
stream->num_subtop = 1;
return stream->num_subtop + rv;
}
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) { if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n", DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n",
stream->stream_id)); stream->stream_id));
@ -236,44 +234,63 @@ static ssize_t stream_update_dep_set_top(nghttp2_stream *stream,
stream->dpri = NGHTTP2_STREAM_DPRI_TOP; stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
rv = stream_update_dep_set_top(stream->sib_next, pq); return 0;
}
if(rv < 0) { for(si = stream->dep_next; si; si = si->sib_next) {
rv = stream_update_dep_set_top(si, pq);
if(rv != 0) {
return rv; return rv;
} }
stream->num_subtop = 1;
return stream->num_subtop + rv;
} }
assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_DATA); return 0;
rv = stream_update_dep_set_top(stream->sib_next, pq);
if(rv < 0) {
return rv;
}
num_top = rv;
rv = stream_update_dep_set_top(stream->dep_next, pq);
if(rv < 0) {
return rv;
}
stream->num_subtop = rv;
return stream->num_subtop + num_top;
} }
static ssize_t stream_update_dep_on_attach_data(nghttp2_stream *stream, /*
nghttp2_pq *pq) * Updates stream->sum_norest_weight recursively. We have to gather
* effective sum of weight of descendants. If stream->dpri ==
* NGHTTP2_STREAM_DPRI_NO_DATA, we have to go deeper and check that
* any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP.
* If so, we have to add weight of its direct descendants to
* stream->sum_norest_weight. To make this work, this function
* returns 1 if any of its descendants has dpri value of
* NGHTTP2_STREAM_DPRI_TOP, otherwise 0.
*/
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
{ {
ssize_t rv; nghttp2_stream *si;
int rv;
stream->sum_norest_weight = 0;
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
}
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
return 0;
}
rv = 0;
for(si = stream->dep_next; si; si = si->sib_next) {
if(stream_update_dep_sum_norest_weight(si)) {
rv = 1;
stream->sum_norest_weight += si->weight;
}
}
return rv;
}
static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
nghttp2_pq *pq)
{
int rv;
nghttp2_stream *root_stream; nghttp2_stream *root_stream;
ssize_t old_num_subtop;
stream->dpri = NGHTTP2_STREAM_DPRI_REST; stream->dpri = NGHTTP2_STREAM_DPRI_REST;
@ -283,16 +300,14 @@ static ssize_t stream_update_dep_on_attach_data(nghttp2_stream *stream,
DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream)); DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream));
old_num_subtop = root_stream->num_subtop;
rv = stream_update_dep_set_top(root_stream, pq); rv = stream_update_dep_set_top(root_stream, pq);
if(rv < 0) { if(rv != 0) {
return rv; return rv;
} }
nghttp2_stream_group_update_num_top stream_update_dep_sum_norest_weight(root_stream);
(root_stream->stream_group, root_stream->num_subtop - old_num_subtop); stream_update_dep_effective_weight(root_stream);
return 0; return 0;
} }
@ -300,30 +315,21 @@ static ssize_t stream_update_dep_on_attach_data(nghttp2_stream *stream,
static int stream_update_dep_on_detach_data(nghttp2_stream *stream, static int stream_update_dep_on_detach_data(nghttp2_stream *stream,
nghttp2_pq *pq) nghttp2_pq *pq)
{ {
ssize_t rv; int rv;
nghttp2_stream *root_stream; nghttp2_stream *root_stream;
ssize_t old_num_subtop;
if(stream->dpri != NGHTTP2_STREAM_DPRI_TOP) {
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
return 0;
}
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA; stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
root_stream = nghttp2_stream_get_dep_root(stream); root_stream = nghttp2_stream_get_dep_root(stream);
old_num_subtop = root_stream->num_subtop;
rv = stream_update_dep_set_top(root_stream, pq); rv = stream_update_dep_set_top(root_stream, pq);
if(rv < 0) { if(rv != 0) {
return rv; return rv;
} }
nghttp2_stream_group_update_num_top stream_update_dep_sum_norest_weight(root_stream);
(root_stream->stream_group, root_stream->num_subtop - old_num_subtop); stream_update_dep_effective_weight(root_stream);
return 0; return 0;
} }
@ -475,6 +481,7 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
nghttp2_stream *stream) nghttp2_stream *stream)
{ {
nghttp2_stream *si; nghttp2_stream *si;
nghttp2_stream *root_stream;
assert(stream->data_item == NULL); assert(stream->data_item == NULL);
@ -483,6 +490,9 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
dep_stream, dep_stream->stream_id, dep_stream, dep_stream->stream_id,
stream, stream->stream_id)); stream, stream->stream_id));
stream->sum_dep_weight = dep_stream->sum_dep_weight;
dep_stream->sum_dep_weight = stream->weight;
if(dep_stream->dep_next) { if(dep_stream->dep_next) {
for(si = dep_stream->dep_next; si; si = si->sib_next) { for(si = dep_stream->dep_next; si; si = si->sib_next) {
stream->num_substreams += si->num_substreams; stream->num_substreams += si->num_substreams;
@ -495,13 +505,19 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
dep_stream->dep_next = stream; dep_stream->dep_next = stream;
stream->dep_prev = dep_stream; stream->dep_prev = dep_stream;
stream_update_dep_length(dep_stream, 1); root_stream = stream_update_dep_length(dep_stream, 1);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
++stream->roots->num_streams;
} }
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
nghttp2_stream *stream) nghttp2_stream *stream)
{ {
nghttp2_stream *last_sib; nghttp2_stream *last_sib;
nghttp2_stream *root_stream;
assert(stream->data_item == NULL); assert(stream->data_item == NULL);
@ -510,31 +526,52 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
dep_stream, dep_stream->stream_id, dep_stream, dep_stream->stream_id,
stream, stream->stream_id)); stream, stream->stream_id));
stream_update_dep_length(dep_stream, 1); root_stream = stream_update_dep_length(dep_stream, 1);
dep_stream->sum_dep_weight += stream->weight;
if(dep_stream->dep_next == NULL) { if(dep_stream->dep_next == NULL) {
dep_stream->dep_next = stream; dep_stream->dep_next = stream;
stream->dep_prev = dep_stream; stream->dep_prev = dep_stream;
} else {
return; last_sib = stream_last_sib(dep_stream->dep_next);
last_sib->sib_next = stream;
stream->sib_prev = last_sib;
} }
last_sib = stream_last_sib(dep_stream->dep_next); stream_update_dep_sum_norest_weight(root_stream);
last_sib->sib_next = stream; stream_update_dep_effective_weight(root_stream);
stream->sib_prev = last_sib;
++stream->roots->num_streams;
} }
void nghttp2_stream_dep_remove(nghttp2_stream *stream) void nghttp2_stream_dep_remove(nghttp2_stream *stream)
{ {
nghttp2_stream *prev, *next, *dep_next; nghttp2_stream *prev, *next, *dep_next, *dep_prev, *si, *root_stream;
int32_t sum_dep_weight_delta;
root_stream = NULL;
DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n",
stream, stream->stream_id)); stream, stream->stream_id));
/* Distribute weight of |stream| to direct descendants */
sum_dep_weight_delta = -stream->weight;
for(si = stream->dep_next; si; si = si->sib_next) {
si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
sum_dep_weight_delta += si->weight;
}
prev = stream_first_sib(stream); prev = stream_first_sib(stream);
if(prev->dep_prev) { dep_prev = prev->dep_prev;
stream_update_dep_length(prev->dep_prev, -1);
if(dep_prev) {
root_stream = stream_update_dep_length(dep_prev, -1);
dep_prev->sum_dep_weight += sum_dep_weight_delta;
} }
if(stream->sib_prev) { if(stream->sib_prev) {
@ -574,7 +611,7 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
dep_next = NULL; dep_next = NULL;
} }
} else { } else {
nghttp2_stream *si; nghttp2_stream_roots_remove(stream->roots, stream);
dep_next = NULL; dep_next = NULL;
@ -588,6 +625,11 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
si->sib_prev = NULL; si->sib_prev = NULL;
si->sib_next = NULL; si->sib_next = NULL;
/* We already distributed weight of |stream| to this. */
si->effective_weight = si->weight;
nghttp2_stream_roots_add(si->roots, si);
si = next; si = next;
} }
} }
@ -600,11 +642,20 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
next->sib_prev = prev; next->sib_prev = prev;
} }
if(root_stream) {
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
}
stream->num_substreams = 1; stream->num_substreams = 1;
stream->sum_dep_weight = 0;
stream->dep_prev = NULL; stream->dep_prev = NULL;
stream->dep_next = NULL; stream->dep_next = NULL;
stream->sib_prev = NULL; stream->sib_prev = NULL;
stream->sib_next = NULL; stream->sib_next = NULL;
--stream->roots->num_streams;
} }
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
@ -614,10 +665,8 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *last_sib; nghttp2_stream *last_sib;
nghttp2_stream *dep_next; nghttp2_stream *dep_next;
nghttp2_stream *root_stream; nghttp2_stream *root_stream;
nghttp2_stream *si;
size_t delta_substreams; size_t delta_substreams;
ssize_t old_num_subtop; int rv;
ssize_t rv;
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d " DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
"stream(%p)=%d\n", "stream(%p)=%d\n",
@ -626,17 +675,16 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
delta_substreams = stream->num_substreams; delta_substreams = stream->num_substreams;
nghttp2_stream_group_update_num_top stream_update_dep_set_rest(stream);
(stream->stream_group, -stream->num_subtop);
stream_update_dep_set_rest_stream_group(stream, dep_stream->stream_group);
if(dep_stream->dep_next) { if(dep_stream->dep_next) {
dep_next = dep_stream->dep_next; /* dep_stream->num_substreams includes dep_stream itself */
stream->num_substreams += dep_stream->num_substreams - 1;
for(si = dep_stream->dep_next; si; si = si->sib_next) { stream->sum_dep_weight += dep_stream->sum_dep_weight;
stream->num_substreams += si->num_substreams; dep_stream->sum_dep_weight = stream->weight;
}
dep_next = dep_stream->dep_next;
stream_update_dep_set_rest(dep_next); stream_update_dep_set_rest(dep_next);
@ -657,20 +705,21 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
} else { } else {
dep_stream->dep_next = stream; dep_stream->dep_next = stream;
stream->dep_prev = dep_stream; stream->dep_prev = dep_stream;
assert(dep_stream->sum_dep_weight == 0);
dep_stream->sum_dep_weight = stream->weight;
} }
root_stream = stream_update_dep_length(dep_stream, delta_substreams); root_stream = stream_update_dep_length(dep_stream, delta_substreams);
old_num_subtop = root_stream->num_subtop;
rv = stream_update_dep_set_top(root_stream, pq); rv = stream_update_dep_set_top(root_stream, pq);
if(rv < 0) { if(rv != 0) {
return rv; return rv;
} }
nghttp2_stream_group_update_num_top stream_update_dep_sum_norest_weight(root_stream);
(root_stream->stream_group, root_stream->num_subtop - old_num_subtop); stream_update_dep_effective_weight(root_stream);
return 0; return 0;
} }
@ -681,20 +730,18 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
{ {
nghttp2_stream *last_sib; nghttp2_stream *last_sib;
nghttp2_stream *root_stream; nghttp2_stream *root_stream;
ssize_t old_num_subtop; int rv;
ssize_t rv;
DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d " DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d "
"stream(%p)=%d\n", "stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, dep_stream, dep_stream->stream_id,
stream, stream->stream_id)); stream, stream->stream_id));
nghttp2_stream_group_update_num_top stream_update_dep_set_rest(stream);
(stream->stream_group, -stream->num_subtop);
stream_update_dep_set_rest_stream_group(stream, dep_stream->stream_group);
if(dep_stream->dep_next) { if(dep_stream->dep_next) {
dep_stream->sum_dep_weight += stream->weight;
last_sib = stream_last_sib(dep_stream->dep_next); last_sib = stream_last_sib(dep_stream->dep_next);
last_sib->sib_next = stream; last_sib->sib_next = stream;
@ -702,33 +749,32 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
} else { } else {
dep_stream->dep_next = stream; dep_stream->dep_next = stream;
stream->dep_prev = dep_stream; stream->dep_prev = dep_stream;
assert(dep_stream->sum_dep_weight == 0);
dep_stream->sum_dep_weight = stream->weight;
} }
root_stream = stream_update_dep_length(dep_stream, stream->num_substreams); root_stream = stream_update_dep_length(dep_stream, stream->num_substreams);
old_num_subtop = root_stream->num_subtop;
rv = stream_update_dep_set_top(root_stream, pq); rv = stream_update_dep_set_top(root_stream, pq);
if(rv < 0) { if(rv != 0) {
return rv; return rv;
} }
nghttp2_stream_group_update_num_top stream_update_dep_sum_norest_weight(root_stream);
(root_stream->stream_group, root_stream->num_subtop - old_num_subtop); stream_update_dep_effective_weight(root_stream);
return 0; return 0;
} }
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
{ {
nghttp2_stream *prev, *next; nghttp2_stream *prev, *next, *dep_prev, *root_stream;
DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n",
stream, stream->stream_id)); stream, stream->stream_id));
/* Removing subtree does not change stream_group->num_top */
if(stream->sib_prev) { if(stream->sib_prev) {
prev = stream->sib_prev; prev = stream->sib_prev;
@ -738,24 +784,34 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
} }
prev = stream_first_sib(prev); prev = stream_first_sib(prev);
if(prev->dep_prev) {
stream_update_dep_both_length(prev->dep_prev, -stream->num_substreams, dep_prev = prev->dep_prev;
-stream->num_subtop);
}
} else if(stream->dep_prev) { } else if(stream->dep_prev) {
prev = stream->dep_prev; dep_prev = stream->dep_prev;
next = stream->sib_next; next = stream->sib_next;
prev->dep_next = next; dep_prev->dep_next = next;
if(next) { if(next) {
next->dep_prev = prev; next->dep_prev = dep_prev;
next->sib_prev = NULL; next->sib_prev = NULL;
} }
stream_update_dep_both_length(prev, -stream->num_substreams, } else {
-stream->num_subtop); nghttp2_stream_roots_remove(stream->roots, stream);
dep_prev = NULL;
}
if(dep_prev) {
dep_prev->sum_dep_weight -= stream->weight;
root_stream = stream_update_dep_length(dep_prev, -stream->num_substreams);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
} }
stream->sib_prev = NULL; stream->sib_prev = NULL;
@ -763,94 +819,165 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
stream->dep_prev = NULL; stream->dep_prev = NULL;
} }
int nghttp2_stream_dep_make_root(nghttp2_stream_group *stream_group, int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq)
nghttp2_stream *stream,
nghttp2_pq *pq)
{ {
ssize_t rv; int rv;
DEBUGF(fprintf(stderr, "stream: dep_make_root new_stream_group(%p)=%d, " DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n",
"old_stream_group(%p)=%d, stream(%p)=%d\n",
stream_group, stream_group->pri_group_id,
stream->stream_group, stream->stream_group->pri_group_id,
stream, stream->stream_id)); stream, stream->stream_id));
/* First update num_top of old stream_group */ nghttp2_stream_roots_add(stream->roots, stream);
nghttp2_stream_group_update_num_top
(stream->stream_group, -stream->num_subtop);
stream_update_dep_set_rest_stream_group(stream, stream_group); stream_update_dep_set_rest(stream);
stream->effective_weight = stream->weight;
rv = stream_update_dep_set_top(stream, pq); rv = stream_update_dep_set_top(stream, pq);
if(rv < 0) { if(rv != 0) {
return rv; return rv;
} }
nghttp2_stream_group_update_num_top(stream_group, stream->num_subtop); stream_update_dep_sum_norest_weight(stream);
stream_update_dep_effective_weight(stream);
return 0; return 0;
} }
void nghttp2_stream_group_init(nghttp2_stream_group *stream_group, int nghttp2_stream_dep_all_your_stream_are_belong_to_us
int32_t pri_group_id, (nghttp2_stream *stream, nghttp2_pq *pq)
int32_t weight)
{ {
nghttp2_map_entry_init(&stream_group->map_entry, pri_group_id); nghttp2_stream *first, *si;
stream_group->num_streams = 0; DEBUGF(fprintf(stderr, "stream: ALL YOUR STREAM ARE BELONG TO US "
stream_group->num_top = 0; "stream(%p)=%d\n",
stream_group->pri_group_id = pri_group_id;
stream_group->weight = weight;
}
void nghttp2_stream_group_free(nghttp2_stream_group *stream_group)
{}
void nghttp2_stream_group_add_stream(nghttp2_stream_group *stream_group,
nghttp2_stream *stream)
{
DEBUGF(fprintf(stderr, "stream_group: stream_group(%p)=%d "
"add stream(%p)=%d\n",
stream_group, stream_group->pri_group_id,
stream, stream->stream_id)); stream, stream->stream_id));
stream->stream_group = stream_group; first = stream->roots->head;
++stream_group->num_streams; /* stream must not be include in stream->roots->head list */
} assert(first != stream);
void nghttp2_stream_group_remove_stream(nghttp2_stream_group *stream_group, if(first) {
nghttp2_stream *stream) nghttp2_stream *prev;
{
DEBUGF(fprintf(stderr, "stream_group: stream_group(%p)=%d "
"remove stream(%p)=%d\n",
stream_group, stream_group->pri_group_id,
stream, stream->stream_id));
stream->stream_group = NULL; prev = first;
--stream_group->num_streams; DEBUGF(fprintf(stderr, "stream: root stream(%p)=%d\n",
} first, first->stream_id));
void nghttp2_stream_group_update_num_top(nghttp2_stream_group *stream_group, stream->sum_dep_weight += first->weight;
ssize_t delta) stream->num_substreams += first->num_substreams;
{
DEBUGF(fprintf(stderr, "stream_group: stream_group(%p)=%d "
"update num_top current=%zd, delta=%zd, after=%zd\n",
stream_group, stream_group->pri_group_id,
stream_group->num_top, delta, stream_group->num_top + delta));
stream_group->num_top += delta; for(si = first->root_next; si; si = si->root_next) {
assert(stream_group->num_top >= 0); assert(si != stream);
}
size_t nghttp2_stream_group_shared_wait(nghttp2_stream_group *stream_group) DEBUGF(fprintf(stderr, "stream: root stream(%p)=%d\n",
{ si, si->stream_id));
if(stream_group->num_top == 0) {
return 1; fprintf(stderr, "w=%d, sum=%d\n",
si->weight, stream->sum_dep_weight);
stream->sum_dep_weight += si->weight;
stream->num_substreams += si->num_substreams;
si->sib_prev = prev;
prev->sib_next = si;
prev = si;
}
if(stream->dep_next) {
nghttp2_stream *last_sib;
last_sib = stream_last_sib(stream->dep_next);
last_sib->sib_next = first;
first->sib_prev = last_sib;
} else {
stream->dep_next = first;
first->dep_prev = stream;
}
} }
return nghttp2_max(1, stream_group->weight / stream_group->num_top); nghttp2_stream_roots_remove_all(stream->roots);
return nghttp2_stream_dep_make_root(stream, pq);
}
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream)
{
return stream->dep_prev || stream->dep_next ||
stream->sib_prev || stream->sib_next ||
stream->root_next || stream->root_prev ||
stream->roots->head == stream;
}
void nghttp2_stream_roots_init(nghttp2_stream_roots *roots)
{
roots->head = NULL;
roots->num_streams = 0;
}
void nghttp2_stream_roots_free(nghttp2_stream_roots *roots)
{}
void nghttp2_stream_roots_add(nghttp2_stream_roots *roots,
nghttp2_stream *stream)
{
if(roots->head) {
nghttp2_stream *si;
for(si = roots->head; si; si = si->root_next) {
if(si == stream) {
assert(0);
}
}
stream->root_next = roots->head;
roots->head->root_prev = stream;
}
roots->head = stream;
}
void nghttp2_stream_roots_remove(nghttp2_stream_roots *roots,
nghttp2_stream *stream)
{
nghttp2_stream *root_prev, *root_next;
root_prev = stream->root_prev;
root_next = stream->root_next;
if(root_prev) {
root_prev->root_next = root_next;
if(root_next) {
root_next->root_prev = root_prev;
}
} else {
if(root_next) {
root_next->root_prev = NULL;
}
roots->head = root_next;
}
stream->root_prev = NULL;
stream->root_next = NULL;
}
void nghttp2_stream_roots_remove_all(nghttp2_stream_roots *roots)
{
nghttp2_stream *si, *next;
for(si = roots->head; si;) {
next = si->root_next;
si->root_prev = NULL;
si->root_next = NULL;
si = next;
}
roots->head = NULL;
} }

View File

@ -102,9 +102,9 @@ typedef enum {
NGHTTP2_STREAM_DPRI_REST = 0x04 NGHTTP2_STREAM_DPRI_REST = 0x04
} nghttp2_stream_dpri; } nghttp2_stream_dpri;
struct nghttp2_stream_group; struct nghttp2_stream_roots;
typedef struct nghttp2_stream_group nghttp2_stream_group; typedef struct nghttp2_stream_roots nghttp2_stream_roots;
struct nghttp2_stream; struct nghttp2_stream;
@ -122,27 +122,28 @@ struct nghttp2_stream {
dep_prev and sib_prev are NULL. */ dep_prev and sib_prev are NULL. */
nghttp2_stream *dep_prev, *dep_next; nghttp2_stream *dep_prev, *dep_next;
nghttp2_stream *sib_prev, *sib_next; nghttp2_stream *sib_prev, *sib_next;
/* pointers to track dependency tree root streams. This is
doubly-linked list and first element is pointed by
roots->head. */
nghttp2_stream *root_prev, *root_next;
/* When stream is kept after closure, it may be kept in single /* When stream is kept after closure, it may be kept in single
linked list pointed by nghttp2_session closed_stream_head. linked list pointed by nghttp2_session closed_stream_head.
closed_next points to the next stream object if it is the element closed_next points to the next stream object if it is the element
of the list. */ of the list. */
nghttp2_stream *closed_next; nghttp2_stream *closed_next;
/* pointer to roots, which tracks dependency tree roots */
nghttp2_stream_roots *roots;
/* The arbitrary data provided by user for this stream. */ /* The arbitrary data provided by user for this stream. */
void *stream_user_data; void *stream_user_data;
/* DATA frame item */ /* DATA frame item */
nghttp2_outbound_item *data_item; nghttp2_outbound_item *data_item;
/* stream ID */ /* stream ID */
int32_t stream_id; int32_t stream_id;
/* priority group this stream belongs to */
nghttp2_stream_group *stream_group;
/* categorized priority of this stream. Only stream bearing /* categorized priority of this stream. Only stream bearing
NGHTTP2_STREAM_DPRI_TOP can send DATA frame. */ NGHTTP2_STREAM_DPRI_TOP can send DATA frame. */
nghttp2_stream_dpri dpri; nghttp2_stream_dpri dpri;
/* the number of streams in subtree */ /* the number of streams in subtree */
size_t num_substreams; size_t num_substreams;
/* the number of streams marked as NGHTTP2_STREAM_DPRI_TOP in
subtree */
ssize_t num_subtop;
/* Current remote window size. This value is computed against the /* Current remote window size. This value is computed against the
current initial window size of remote endpoint. */ current initial window size of remote endpoint. */
int32_t remote_window_size; int32_t remote_window_size;
@ -157,6 +158,16 @@ struct nghttp2_stream {
NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by
submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */
int32_t local_window_size; int32_t local_window_size;
/* weight of this stream */
int32_t weight;
/* effective weight of this stream in belonging dependency tree */
int32_t effective_weight;
/* sum of weight (not effective_weight) of direct descendants */
int32_t sum_dep_weight;
/* sum of weight of direct descendants which have at least one
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
value to calculate effective weight. */
int32_t sum_norest_weight;
nghttp2_stream_state state; nghttp2_stream_state state;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
uint8_t flags; uint8_t flags;
@ -167,6 +178,8 @@ struct nghttp2_stream {
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, uint8_t flags,
nghttp2_stream_state initial_state, nghttp2_stream_state initial_state,
int32_t weight,
nghttp2_stream_roots *roots,
int32_t remote_initial_window_size, int32_t remote_initial_window_size,
int32_t local_initial_window_size, int32_t local_initial_window_size,
void *stream_user_data); void *stream_user_data);
@ -259,12 +272,30 @@ nghttp2_stream* nghttp2_stream_get_dep_root(nghttp2_stream *stream);
int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream, int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
nghttp2_stream *target); nghttp2_stream *target);
/*
* Computes distributed weight of a stream of the |weight| under the
* |stream| if |stream| is removed from a dependency tree. The result
* is computed using stream->weight rather than
* stream->effective_weight.
*/
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
int32_t weight);
/*
* Computes effective weight of a stream of the |weight| under the
* |stream|. The result is computed using stream->effective_weight
* rather than stream->weight. This function is used to determine
* weight in dependency tree.
*/
int32_t nghttp2_stream_dep_distributed_effective_weight
(nghttp2_stream *stream, int32_t weight);
/* /*
* Makes the |stream| depend on the |dep_stream|. This dependency is * Makes the |stream| depend on the |dep_stream|. This dependency is
* exclusive. All existing direct descendants of |dep_stream| become * exclusive. All existing direct descendants of |dep_stream| become
* the descendants of the |stream|. This function assumes * the descendants of the |stream|. This function assumes
* |stream->data| is NULL and no dpri members are changed in this * |stream->data| is NULL and no dpri members are changed in this
* dependency tree. It also does not change stream->stream_group. * dependency tree.
*/ */
void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
nghttp2_stream *stream); nghttp2_stream *stream);
@ -272,8 +303,7 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
/* /*
* Makes the |stream| depend on the |dep_stream|. This dependency is * Makes the |stream| depend on the |dep_stream|. This dependency is
* not exclusive. This function assumes |stream->data| is NULL and no * not exclusive. This function assumes |stream->data| is NULL and no
* dpri members are changed in this dependency tree. It also does not * dpri members are changed in this dependency tree.
* change stream->stream_group.
*/ */
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
nghttp2_stream *stream); nghttp2_stream *stream);
@ -342,8 +372,8 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
/* /*
* Removes subtree whose root stream is |stream|. Removing subtree * Removes subtree whose root stream is |stream|. Removing subtree
* does not change dpri values and removed subtree is still in the * does not change dpri values. The effective_weight of streams in
* same stream_group. * removed subtree is not updated.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -354,8 +384,8 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
/* /*
* Makes the |stream| as root for |stream_group|. Updates dpri * Makes the |stream| as root. Updates dpri members in this
* members in this dependency tree. * dependency tree.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -363,53 +393,42 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
* NGHTTP2_ERR_NOMEM * NGHTTP2_ERR_NOMEM
* Out of memory * Out of memory
*/ */
int nghttp2_stream_dep_make_root(nghttp2_stream_group *stream_group, int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq);
nghttp2_stream *stream,
nghttp2_pq *pq);
/* /*
* Priority group of streams. * Makes the |stream| as root and all existing root streams become
* direct children of |stream|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/ */
struct nghttp2_stream_group { int nghttp2_stream_dep_all_your_stream_are_belong_to_us
/* Intrusive Map */ (nghttp2_stream *stream, nghttp2_pq *pq);
nghttp2_map_entry map_entry;
/* The number of streams this priority group contains */ /*
size_t num_streams; * Returns nonzero if |stream| is in any dependency tree.
/* The number of streams marked as NGHTTP2_STREAM_DPRI_TOP */ */
ssize_t num_top; int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
/* The priority group ID */
int32_t pri_group_id; struct nghttp2_stream_roots {
/* The weight of this group */ nghttp2_stream *head;
int32_t weight;
int32_t num_streams;
}; };
void nghttp2_stream_group_init(nghttp2_stream_group *stream_group, void nghttp2_stream_roots_init(nghttp2_stream_roots *roots);
int32_t pri_group_id,
int32_t weight);
void nghttp2_stream_group_free(nghttp2_stream_group *stream_group); void nghttp2_stream_roots_free(nghttp2_stream_roots *roots);
/* void nghttp2_stream_roots_add(nghttp2_stream_roots *roots,
* Adds |stream| to |stream_group|. nghttp2_stream *stream);
*/
void nghttp2_stream_group_add_stream(nghttp2_stream_group *stream_group,
nghttp2_stream *stream);
/* void nghttp2_stream_roots_remove(nghttp2_stream_roots *roots,
* Removes |stream| from |stream_group|. nghttp2_stream *stream);
*/
void nghttp2_stream_group_remove_stream(nghttp2_stream_group *stream_group,
nghttp2_stream *stream);
/* void nghttp2_stream_roots_remove_all(nghttp2_stream_roots *roots);
* Updates |stream_group->num_top| += |delta|
*/
void nghttp2_stream_group_update_num_top(nghttp2_stream_group *stream_group,
ssize_t delta);
/*
* Returns shared weight among the streams belongs to |stream_group|.
*/
size_t nghttp2_stream_group_shared_wait(nghttp2_stream_group *stream_group);
#endif /* NGHTTP2_STREAM */ #endif /* NGHTTP2_STREAM */

View File

@ -77,8 +77,7 @@ static int nghttp2_submit_headers_shared
flags_copy = flags_copy =
(flags & (NGHTTP2_FLAG_END_STREAM | (flags & (NGHTTP2_FLAG_END_STREAM |
NGHTTP2_FLAG_END_SEGMENT | NGHTTP2_FLAG_END_SEGMENT |
NGHTTP2_FLAG_PRIORITY_GROUP | NGHTTP2_FLAG_PRIORITY)) |
NGHTTP2_FLAG_PRIORITY_DEPENDENCY)) |
NGHTTP2_FLAG_END_HEADERS; NGHTTP2_FLAG_END_HEADERS;
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri_spec, nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri_spec,
@ -102,14 +101,12 @@ static int nghttp2_submit_headers_shared
return rv; return rv;
} }
static void adjust_priority_spec_group_weight(nghttp2_priority_spec *pri_spec) static void adjust_priority_spec_weight(nghttp2_priority_spec *pri_spec)
{ {
assert(pri_spec->pri_type == NGHTTP2_PRIORITY_TYPE_GROUP); if(pri_spec->weight < NGHTTP2_MIN_WEIGHT) {
pri_spec->weight = NGHTTP2_MIN_WEIGHT;
if(pri_spec->spec.group.weight < NGHTTP2_MIN_WEIGHT) { } else if(pri_spec->weight > NGHTTP2_MAX_WEIGHT) {
pri_spec->spec.group.weight = NGHTTP2_MIN_WEIGHT; pri_spec->weight = NGHTTP2_MAX_WEIGHT;
} else if(pri_spec->spec.group.weight > NGHTTP2_MAX_WEIGHT) {
pri_spec->spec.group.weight = NGHTTP2_MAX_WEIGHT;
} }
} }
@ -125,25 +122,13 @@ static int nghttp2_submit_headers_shared_nva
{ {
ssize_t rv; ssize_t rv;
nghttp2_nv *nva_copy; nghttp2_nv *nva_copy;
nghttp2_priority_spec copy_pri_spec = { nghttp2_priority_spec copy_pri_spec;
NGHTTP2_PRIORITY_TYPE_NONE
};
if(pri_spec) { if(pri_spec) {
switch(pri_spec->pri_type) {
case NGHTTP2_PRIORITY_TYPE_NONE:
case NGHTTP2_PRIORITY_TYPE_GROUP:
case NGHTTP2_PRIORITY_TYPE_DEP:
break;
default:
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
copy_pri_spec = *pri_spec; copy_pri_spec = *pri_spec;
adjust_priority_spec_weight(&copy_pri_spec);
if(copy_pri_spec.pri_type == NGHTTP2_PRIORITY_TYPE_GROUP) { } else {
adjust_priority_spec_group_weight(&copy_pri_spec); nghttp2_priority_spec_default_init(&copy_pri_spec);
}
} }
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen); rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen);
@ -164,20 +149,10 @@ int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
{ {
flags &= NGHTTP2_FLAG_END_STREAM; flags &= NGHTTP2_FLAG_END_STREAM;
if(pri_spec) { if(pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
switch(pri_spec->pri_type) { flags |= NGHTTP2_FLAG_PRIORITY;
case NGHTTP2_PRIORITY_TYPE_GROUP: } else {
flags |= NGHTTP2_FLAG_PRIORITY_GROUP; pri_spec = NULL;
break;
case NGHTTP2_PRIORITY_TYPE_DEP:
flags |= NGHTTP2_FLAG_PRIORITY_DEPENDENCY;
break;
default:
/* Default weight */
pri_spec = NULL;
break;
}
} }
return nghttp2_submit_headers_shared_nva(session, flags, stream_id, pri_spec, return nghttp2_submit_headers_shared_nva(session, flags, stream_id, pri_spec,
@ -203,23 +178,14 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
copy_pri_spec = *pri_spec; if(stream_id == pri_spec->stream_id) {
switch(copy_pri_spec.pri_type) {
case NGHTTP2_PRIORITY_TYPE_GROUP:
adjust_priority_spec_group_weight(&copy_pri_spec);
break;
case NGHTTP2_PRIORITY_TYPE_DEP:
if(stream_id == copy_pri_spec.spec.dep.stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
break;
default:
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
copy_pri_spec = *pri_spec;
adjust_priority_spec_weight(&copy_pri_spec);
frame = malloc(sizeof(nghttp2_frame)); frame = malloc(sizeof(nghttp2_frame));
if(frame == NULL) { if(frame == NULL) {
@ -433,17 +399,7 @@ static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
} }
if(pri_spec) { if(pri_spec) {
switch(pri_spec->pri_type) { flags |= NGHTTP2_FLAG_PRIORITY;
case NGHTTP2_PRIORITY_TYPE_GROUP:
flags |= NGHTTP2_FLAG_PRIORITY_GROUP;
break;
case NGHTTP2_PRIORITY_TYPE_DEP:
flags |= NGHTTP2_FLAG_PRIORITY_DEPENDENCY;
break;
default:
/* Default weight */
break;
}
} }
return flags; return flags;
@ -457,6 +413,10 @@ int nghttp2_submit_request(nghttp2_session *session,
{ {
uint8_t flags; uint8_t flags;
if(pri_spec && nghttp2_priority_spec_check_default(pri_spec)) {
pri_spec = NULL;
}
flags = set_request_flags(pri_spec, data_prd); flags = set_request_flags(pri_spec, data_prd);
return nghttp2_submit_headers_shared_nva(session, flags, -1, pri_spec, return nghttp2_submit_headers_shared_nva(session, flags, -1, pri_spec,

View File

@ -261,27 +261,15 @@ void print_flags(const nghttp2_frame_hd& hd)
} }
s += "PAD_HIGH"; s += "PAD_HIGH";
} }
if(hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { if(hd.flags & NGHTTP2_FLAG_PRIORITY) {
if(!s.empty()) { if(!s.empty()) {
s += " | "; s += " | ";
} }
s += "PRIORITY_GROUP"; s += "PRIORITY";
}
if(hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
if(!s.empty()) {
s += " | ";
}
s += "PRIORITY_DEPENDENCY";
} }
break; break;
case NGHTTP2_PRIORITY: case NGHTTP2_PRIORITY:
if(hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) {
s += "PRIORITY_GROUP";
} else if(hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
s += "PRIORITY_DEPENDENCY";
}
break; break;
case NGHTTP2_SETTINGS: case NGHTTP2_SETTINGS:
if(hd.flags & NGHTTP2_FLAG_ACK) { if(hd.flags & NGHTTP2_FLAG_ACK) {
@ -368,14 +356,11 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
case NGHTTP2_HEADERS: case NGHTTP2_HEADERS:
print_frame_attr_indent(); print_frame_attr_indent();
fprintf(outfile, "(padlen=%zu", frame->headers.padlen); fprintf(outfile, "(padlen=%zu", frame->headers.padlen);
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
fprintf(outfile, ", pri_group_id=%d, weight=%u", fprintf(outfile, ", stream_id=%d, weight=%u, exclusive=%d",
frame->headers.pri_spec.spec.group.pri_group_id, frame->headers.pri_spec.stream_id,
frame->headers.pri_spec.spec.group.weight); frame->headers.pri_spec.weight,
} else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { frame->headers.pri_spec.exclusive);
fprintf(outfile, ", stream_id=%d, exclusive=%d",
frame->headers.pri_spec.spec.dep.stream_id,
frame->headers.pri_spec.spec.dep.exclusive);
} }
fprintf(outfile, ")\n"); fprintf(outfile, ")\n");
switch(frame->headers.cat) { switch(frame->headers.cat) {
@ -399,19 +384,10 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
case NGHTTP2_PRIORITY: case NGHTTP2_PRIORITY:
print_frame_attr_indent(); print_frame_attr_indent();
fprintf(outfile, "("); fprintf(outfile, "(stream_id=%d, weight=%u, exclusive=%d)\n",
frame->priority.pri_spec.stream_id,
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { frame->priority.pri_spec.weight,
fprintf(outfile, "pri_group_id=%d, weight=%u", frame->priority.pri_spec.exclusive);
frame->priority.pri_spec.spec.group.pri_group_id,
frame->priority.pri_spec.spec.group.weight);
} else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
fprintf(outfile, "stream_id=%d, exclusive=%d",
frame->priority.pri_spec.spec.dep.stream_id,
frame->priority.pri_spec.spec.dep.exclusive);
}
fprintf(outfile, ")\n");
break; break;
case NGHTTP2_RST_STREAM: case NGHTTP2_RST_STREAM:

View File

@ -263,7 +263,7 @@ struct Request {
nghttp2_priority_spec resolve_dep(int32_t pri) nghttp2_priority_spec resolve_dep(int32_t pri)
{ {
nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE }; nghttp2_priority_spec pri_spec;
int exclusive = 0; int exclusive = 0;
int32_t stream_id = -1; int32_t stream_id = -1;
@ -271,6 +271,8 @@ struct Request {
return pri_spec; return pri_spec;
} }
nghttp2_priority_spec_default_init(&pri_spec);
auto start = std::min(pri, (int)dep->deps.size() - 1); auto start = std::min(pri, (int)dep->deps.size() - 1);
for(auto i = start; i >= 0; --i) { for(auto i = start; i >= 0; --i) {
@ -293,7 +295,8 @@ struct Request {
return pri_spec; return pri_spec;
} }
nghttp2_priority_spec_dep_init(&pri_spec, stream_id, exclusive); nghttp2_priority_spec_init(&pri_spec, stream_id, NGHTTP2_DEFAULT_WEIGHT,
exclusive);
return pri_spec; return pri_spec;
} }
@ -1014,12 +1017,9 @@ void update_html_parser(HttpClient *client, Request *req,
nghttp2_priority_spec pri_spec; nghttp2_priority_spec pri_spec;
// We always specify priority group of parent stream, so that // We adjust the priority using separate PRIORITY frame after
// even if the parent stream is closed, the dependent stream is // stream ID becomes known.
// in the same priority group. We adjust the priority using nghttp2_priority_spec_default_init(&pri_spec);
// separate PRIORITY frame after stream ID becomes known.
nghttp2_priority_spec_group_init(&pri_spec, req->stream_id,
config.weight);
if ( client->add_request(uri, nullptr, 0, pri_spec, req->dep, if ( client->add_request(uri, nullptr, 0, pri_spec, req->dep,
req->level+1) ) { req->level+1) ) {
@ -1108,9 +1108,8 @@ void check_stream_id(nghttp2_session *session, int32_t stream_id,
auto pri_spec = req->resolve_dep(req->pri); auto pri_spec = req->resolve_dep(req->pri);
if(pri_spec.pri_type == NGHTTP2_PRIORITY_TYPE_DEP) { if(!nghttp2_priority_spec_check_default(&pri_spec)) {
nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, stream_id, nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, stream_id, &pri_spec);
&pri_spec);
} }
auto itr = std::begin(req->dep->deps); auto itr = std::begin(req->dep->deps);
@ -1208,7 +1207,9 @@ int on_begin_headers_callback(nghttp2_session *session,
http_parser_url u; http_parser_url u;
memset(&u, 0, sizeof(u)); memset(&u, 0, sizeof(u));
// TODO Set pri and level // TODO Set pri and level
nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE }; nghttp2_priority_spec pri_spec;
nghttp2_priority_spec_default_init(&pri_spec);
auto req = util::make_unique<Request>("", u, nullptr, 0, pri_spec, auto req = util::make_unique<Request>("", u, nullptr, 0, pri_spec,
nullptr); nullptr);
@ -1624,10 +1625,12 @@ int communicate(const std::string& scheme, const std::string& host,
{ {
HttpClient client{callbacks, evbase, ssl_ctx}; HttpClient client{callbacks, evbase, ssl_ctx};
nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE }; nghttp2_priority_spec pri_spec;
if(config.weight != NGHTTP2_DEFAULT_WEIGHT) { if(config.weight != NGHTTP2_DEFAULT_WEIGHT) {
nghttp2_priority_spec_group_init(&pri_spec, -1, config.weight); nghttp2_priority_spec_init(&pri_spec, 0, config.weight, 0);
} else {
nghttp2_priority_spec_default_init(&pri_spec);
} }
for(auto req : requests) { for(auto req : requests) {

View File

@ -222,6 +222,8 @@ int main(int argc, char* argv[])
test_nghttp2_session_stream_dep_add_subtree) || test_nghttp2_session_stream_dep_add_subtree) ||
!CU_add_test(pSuite, "session_stream_dep_remove_subtree", !CU_add_test(pSuite, "session_stream_dep_remove_subtree",
test_nghttp2_session_stream_dep_remove_subtree) || test_nghttp2_session_stream_dep_remove_subtree) ||
!CU_add_test(pSuite, "session_stream_dep_all_your_stream_are_belong_to_us",
test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us) ||
!CU_add_test(pSuite, "session_stream_attach_data", !CU_add_test(pSuite, "session_stream_attach_data",
test_nghttp2_session_stream_attach_data) || test_nghttp2_session_stream_attach_data) ||
!CU_add_test(pSuite, "session_stream_attach_data_subtree", !CU_add_test(pSuite, "session_stream_attach_data_subtree",

View File

@ -92,7 +92,7 @@ void test_nghttp2_frame_pack_headers()
nva = headers(); nva = headers();
nvlen = HEADERS_LENGTH; nvlen = HEADERS_LENGTH;
pri_spec.pri_type = NGHTTP2_PRIORITY_TYPE_NONE; nghttp2_priority_spec_default_init(&pri_spec);
nghttp2_frame_headers_init(&frame, nghttp2_frame_headers_init(&frame,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_STREAM |
@ -110,8 +110,8 @@ void test_nghttp2_frame_pack_headers()
NGHTTP2_HEADERS, NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS,
1000000007, &oframe.hd); 1000000007, &oframe.hd);
/* We include NGHTTP2_PRIORITY_TYPE_NONE */ /* We did not include PRIORITY flag */
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_NONE == oframe.pri_spec.pri_type); CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == oframe.pri_spec.weight);
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN; hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN;
CU_ASSERT(hdblocklen == CU_ASSERT(hdblocklen ==
@ -126,9 +126,9 @@ void test_nghttp2_frame_pack_headers()
nghttp2_bufs_reset(&bufs); nghttp2_bufs_reset(&bufs);
memset(&oframe, 0, sizeof(oframe)); memset(&oframe, 0, sizeof(oframe));
/* Next, include NGHTTP2_PRIORITY_TYPE_GROUP */ /* Next, include NGHTTP2_FLAG_PRIORITY */
nghttp2_priority_spec_group_init(&frame.pri_spec, 1000000009, 12); nghttp2_priority_spec_init(&frame.pri_spec, 1000000009, 12, 1);
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY_GROUP; frame.hd.flags |= NGHTTP2_FLAG_PRIORITY;
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater); rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
@ -139,12 +139,12 @@ void test_nghttp2_frame_pack_headers()
check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN, check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_HEADERS, NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PRIORITY_GROUP, NGHTTP2_FLAG_PRIORITY,
1000000007, &oframe.hd); 1000000007, &oframe.hd);
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_GROUP == oframe.pri_spec.pri_type); CU_ASSERT(1000000009 == oframe.pri_spec.stream_id);
CU_ASSERT(1000000009 == oframe.pri_spec.spec.group.pri_group_id); CU_ASSERT(12 == oframe.pri_spec.weight);
CU_ASSERT(12 == oframe.pri_spec.spec.group.weight); CU_ASSERT(1 == oframe.pri_spec.exclusive);
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN
- nghttp2_frame_priority_len(oframe.hd.flags); - nghttp2_frame_priority_len(oframe.hd.flags);
@ -159,44 +159,7 @@ void test_nghttp2_frame_pack_headers()
nva_out_reset(&out); nva_out_reset(&out);
nghttp2_bufs_reset(&bufs); nghttp2_bufs_reset(&bufs);
memset(&oframe, 0, sizeof(oframe));
/* Next, include NGHTTP2_PRIORITY_TYPE_DEP */
nghttp2_priority_spec_dep_init(&frame.pri_spec, 123, 1);
frame.hd.flags =
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PRIORITY_DEPENDENCY;
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN,
NGHTTP2_HEADERS,
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
NGHTTP2_FLAG_PRIORITY_DEPENDENCY,
1000000007, &oframe.hd);
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_DEP == oframe.pri_spec.pri_type);
CU_ASSERT(123 == oframe.pri_spec.spec.dep.stream_id);
CU_ASSERT(1 == oframe.pri_spec.spec.dep.exclusive);
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN
- nghttp2_frame_priority_len(oframe.hd.flags);
CU_ASSERT(hdblocklen ==
inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN
+ nghttp2_frame_priority_len(oframe.hd.flags)));
nghttp2_nv_array_sort(out.nva, out.nvlen);
CU_ASSERT(nvnameeq("method", &out.nva[0]));
nghttp2_frame_headers_free(&oframe);
nva_out_reset(&out);
nghttp2_bufs_free(&bufs); nghttp2_bufs_free(&bufs);
nghttp2_frame_headers_free(&frame); nghttp2_frame_headers_free(&frame);
nghttp2_hd_inflate_free(&inflater); nghttp2_hd_inflate_free(&inflater);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
@ -208,7 +171,6 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
nghttp2_headers frame; nghttp2_headers frame;
nghttp2_bufs bufs; nghttp2_bufs bufs;
nghttp2_nv *nva; nghttp2_nv *nva;
nghttp2_priority_spec pri_spec;
ssize_t nvlen; ssize_t nvlen;
size_t big_vallen = NGHTTP2_HD_MAX_VALUE; size_t big_vallen = NGHTTP2_HD_MAX_VALUE;
nghttp2_nv big_hds[16]; nghttp2_nv big_hds[16];
@ -228,13 +190,11 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
big_hds[i].flags = NGHTTP2_NV_FLAG_NONE; big_hds[i].flags = NGHTTP2_NV_FLAG_NONE;
} }
pri_spec.pri_type = NGHTTP2_PRIORITY_TYPE_NONE;
nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen); nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen);
nghttp2_hd_deflate_init(&deflater); nghttp2_hd_deflate_init(&deflater);
nghttp2_frame_headers_init(&frame, nghttp2_frame_headers_init(&frame,
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
1000000007, &pri_spec, nva, nvlen); 1000000007, NULL, nva, nvlen);
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater); rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == rv); CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == rv);
@ -256,7 +216,7 @@ void test_nghttp2_frame_pack_priority(void)
frame_pack_bufs_init(&bufs); frame_pack_bufs_init(&bufs);
/* First, pack priority with priority group and weight */ /* First, pack priority with priority group and weight */
nghttp2_priority_spec_group_init(&pri_spec, 1000000009, 12); nghttp2_priority_spec_init(&pri_spec, 1000000009, 12, 1);
nghttp2_frame_priority_init(&frame, 1000000007, &pri_spec); nghttp2_frame_priority_init(&frame, 1000000007, &pri_spec);
rv = nghttp2_frame_pack_priority(&bufs, &frame); rv = nghttp2_frame_pack_priority(&bufs, &frame);
@ -264,34 +224,12 @@ void test_nghttp2_frame_pack_priority(void)
CU_ASSERT(0 == rv); CU_ASSERT(0 == rv);
CU_ASSERT(13 == nghttp2_bufs_len(&bufs)); CU_ASSERT(13 == nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs)); CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_PRIORITY_GROUP, check_frame_header(5, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE,
1000000007, &oframe.hd); 1000000007, &oframe.hd);
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_GROUP == oframe.pri_spec.pri_type); CU_ASSERT(1000000009 == oframe.pri_spec.stream_id);
CU_ASSERT(1000000009 == oframe.pri_spec.spec.group.pri_group_id); CU_ASSERT(12 == oframe.pri_spec.weight);
CU_ASSERT(12 == oframe.pri_spec.spec.group.weight); CU_ASSERT(1 == oframe.pri_spec.exclusive);
nghttp2_frame_priority_free(&oframe);
nghttp2_bufs_reset(&bufs);
memset(&oframe, 0, sizeof(oframe));
/* Next, pack priority with stream dependency */
nghttp2_priority_spec_dep_init(&pri_spec, 79, 1);
nghttp2_frame_priority_init(&frame, 1000000007, &pri_spec);
rv = nghttp2_frame_pack_priority(&bufs, &frame);
CU_ASSERT(0 == rv);
CU_ASSERT(12 == nghttp2_bufs_len(&bufs));
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_PRIORITY_DEPENDENCY,
1000000007, &oframe.hd);
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_DEP == oframe.pri_spec.pri_type);
CU_ASSERT(79 == oframe.pri_spec.spec.dep.stream_id);
CU_ASSERT(1 == oframe.pri_spec.spec.dep.exclusive);
nghttp2_frame_priority_free(&oframe); nghttp2_frame_priority_free(&oframe);
nghttp2_bufs_reset(&bufs); nghttp2_bufs_reset(&bufs);

File diff suppressed because it is too large Load Diff

View File

@ -103,6 +103,7 @@ void test_nghttp2_session_stream_dep_add(void);
void test_nghttp2_session_stream_dep_remove(void); void test_nghttp2_session_stream_dep_remove(void);
void test_nghttp2_session_stream_dep_add_subtree(void); void test_nghttp2_session_stream_dep_add_subtree(void);
void test_nghttp2_session_stream_dep_remove_subtree(void); void test_nghttp2_session_stream_dep_remove_subtree(void);
void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void);
void test_nghttp2_session_stream_attach_data(void); void test_nghttp2_session_stream_attach_data(void);
void test_nghttp2_session_stream_attach_data_subtree(void); void test_nghttp2_session_stream_attach_data_subtree(void);
void test_nghttp2_session_keep_closed_stream(void); void test_nghttp2_session_keep_closed_stream(void);

View File

@ -232,12 +232,22 @@ void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size)
nghttp2_bufs_init2(bufs, chunk_size, 16, NGHTTP2_FRAME_HDLEN + 2); nghttp2_bufs_init2(bufs, chunk_size, 16, NGHTTP2_FRAME_HDLEN + 2);
} }
nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id) static nghttp2_stream* open_stream_with_all(nghttp2_session *session,
int32_t stream_id,
int32_t weight,
uint8_t exclusive,
nghttp2_stream *dep_stream)
{ {
nghttp2_priority_spec pri_spec; nghttp2_priority_spec pri_spec;
int32_t dep_stream_id;
nghttp2_priority_spec_group_init(&pri_spec, stream_id, if(dep_stream) {
NGHTTP2_DEFAULT_WEIGHT); dep_stream_id = dep_stream->stream_id;
} else {
dep_stream_id = 0;
}
nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, exclusive);
return nghttp2_session_open_stream(session, stream_id, return nghttp2_session_open_stream(session, stream_id,
NGHTTP2_STREAM_FLAG_NONE, NGHTTP2_STREAM_FLAG_NONE,
@ -246,32 +256,45 @@ nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id)
NULL); NULL);
} }
nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id)
{
return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0,
NULL);
}
nghttp2_stream* open_stream_with_dep(nghttp2_session *session, nghttp2_stream* open_stream_with_dep(nghttp2_session *session,
int32_t stream_id, int32_t stream_id,
nghttp2_stream *dep_stream) nghttp2_stream *dep_stream)
{ {
nghttp2_priority_spec pri_spec; return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0,
dep_stream);
}
nghttp2_priority_spec_dep_init(&pri_spec, dep_stream->stream_id, 0); nghttp2_stream* open_stream_with_dep_weight(nghttp2_session *session,
int32_t stream_id,
return nghttp2_session_open_stream(session, stream_id, int32_t weight,
NGHTTP2_STREAM_FLAG_NONE, nghttp2_stream *dep_stream)
&pri_spec, {
NGHTTP2_STREAM_OPENED, return open_stream_with_all(session, stream_id, weight, 0, dep_stream);
NULL);
} }
nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session, nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session,
int32_t stream_id, int32_t stream_id,
nghttp2_stream *dep_stream) nghttp2_stream *dep_stream)
{ {
nghttp2_priority_spec pri_spec; return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 1,
dep_stream);
nghttp2_priority_spec_dep_init(&pri_spec, dep_stream->stream_id, 1);
return nghttp2_session_open_stream(session, stream_id,
NGHTTP2_STREAM_FLAG_NONE,
&pri_spec,
NGHTTP2_STREAM_OPENED,
NULL);
} }
nghttp2_outbound_item* create_data_ob_item(void)
{
nghttp2_outbound_item *item;
item = malloc(sizeof(nghttp2_outbound_item));
memset(item, 0, sizeof(nghttp2_outbound_item));
item->frame_cat = NGHTTP2_CAT_DATA;
return item;
}

View File

@ -89,8 +89,15 @@ nghttp2_stream* open_stream_with_dep(nghttp2_session *session,
int32_t stream_id, int32_t stream_id,
nghttp2_stream *dep_stream); nghttp2_stream *dep_stream);
nghttp2_stream* open_stream_with_dep_weight(nghttp2_session *session,
int32_t stream_id,
int32_t weight,
nghttp2_stream *dep_stream);
nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session, nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session,
int32_t stream_id, int32_t stream_id,
nghttp2_stream *dep_stream); nghttp2_stream *dep_stream);
nghttp2_outbound_item* create_data_ob_item(void);
#endif /* NGHTTP2_TEST_HELPER_H */ #endif /* NGHTTP2_TEST_HELPER_H */