Implement dependency based priority
This commit is contained in:
parent
8ccb6e463d
commit
f7162ab702
|
@ -521,7 +521,6 @@ static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
|
|||
*/
|
||||
static void submit_request(struct Connection *connection, struct Request *req)
|
||||
{
|
||||
int pri = 0;
|
||||
int rv;
|
||||
const nghttp2_nv nva[] = {
|
||||
/* Make sure that the last item is NULL */
|
||||
|
@ -532,7 +531,7 @@ static void submit_request(struct Connection *connection, struct Request *req)
|
|||
MAKE_NV("accept", "*/*"),
|
||||
MAKE_NV("user-agent", "nghttp2/"NGHTTP2_VERSION)
|
||||
};
|
||||
rv = nghttp2_submit_request(connection->session, pri,
|
||||
rv = nghttp2_submit_request(connection->session, NULL,
|
||||
nva, sizeof(nva)/sizeof(nva[0]), NULL, req);
|
||||
if(rv != 0) {
|
||||
diec("nghttp2_submit_request", rv);
|
||||
|
|
|
@ -402,7 +402,7 @@ static void submit_request(http2_session_data *session_data)
|
|||
};
|
||||
fprintf(stderr, "Request headers:\n");
|
||||
print_headers(stderr, hdrs, ARRLEN(hdrs));
|
||||
rv = nghttp2_submit_request(session_data->session, NGHTTP2_PRI_DEFAULT,
|
||||
rv = nghttp2_submit_request(session_data->session, NULL,
|
||||
hdrs, ARRLEN(hdrs), NULL, stream_data);
|
||||
if(rv != 0) {
|
||||
errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(rv));
|
||||
|
|
|
@ -39,7 +39,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
|
|||
nghttp2_helper.c \
|
||||
nghttp2_npn.c nghttp2_gzip.c \
|
||||
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \
|
||||
nghttp2_version.c
|
||||
nghttp2_version.c \
|
||||
nghttp2_priority_spec.c
|
||||
|
||||
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||
nghttp2_frame.h \
|
||||
|
@ -48,7 +49,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
|||
nghttp2_npn.h nghttp2_gzip.h \
|
||||
nghttp2_submit.h nghttp2_outbound_item.h \
|
||||
nghttp2_net.h \
|
||||
nghttp2_hd.h nghttp2_hd_huffman.h
|
||||
nghttp2_hd.h nghttp2_hd_huffman.h \
|
||||
nghttp2_priority_spec.h
|
||||
|
||||
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||
libnghttp2_la_LDFLAGS = -no-undefined \
|
||||
|
|
|
@ -97,15 +97,16 @@ typedef struct {
|
|||
/**
|
||||
* @macro
|
||||
*
|
||||
* The default priority value
|
||||
* The default weight of priority group.
|
||||
*/
|
||||
#define NGHTTP2_PRI_DEFAULT (1 << 30)
|
||||
#define NGHTTP2_DEFAULT_WEIGHT 16
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* The lowest priority value
|
||||
* The maximum weight of priority group.
|
||||
*/
|
||||
#define NGHTTP2_PRI_LOWEST ((1U << 31) - 1)
|
||||
#define NGHTTP2_MAX_WEIGHT 255
|
||||
|
||||
/**
|
||||
* @macro
|
||||
|
@ -278,6 +279,11 @@ typedef enum {
|
|||
* The server push is disabled.
|
||||
*/
|
||||
NGHTTP2_ERR_PUSH_DISABLED = -528,
|
||||
/**
|
||||
* DATA frame for a given stream has been already submitted and has
|
||||
* not been fully processed yet.
|
||||
*/
|
||||
NGHTTP2_ERR_DATA_EXIST = -529,
|
||||
/**
|
||||
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
||||
* under unexpected condition and cannot process any further data
|
||||
|
@ -390,10 +396,6 @@ typedef enum {
|
|||
* The END_HEADERS flag.
|
||||
*/
|
||||
NGHTTP2_FLAG_END_HEADERS = 0x4,
|
||||
/**
|
||||
* The PRIORITY flag.
|
||||
*/
|
||||
NGHTTP2_FLAG_PRIORITY = 0x8,
|
||||
/**
|
||||
* The ACK flag.
|
||||
*/
|
||||
|
@ -405,11 +407,19 @@ typedef enum {
|
|||
/**
|
||||
* The PAD_LOW flag.
|
||||
*/
|
||||
NGHTTP2_FLAG_PAD_LOW = 0x10,
|
||||
NGHTTP2_FLAG_PAD_LOW = 0x08,
|
||||
/**
|
||||
* The PAD_HIGH flag.
|
||||
*/
|
||||
NGHTTP2_FLAG_PAD_HIGH = 0x20
|
||||
NGHTTP2_FLAG_PAD_HIGH = 0x10,
|
||||
/**
|
||||
* The PRIORITY_GROUP flag.
|
||||
*/
|
||||
NGHTTP2_FLAG_PRIORITY_GROUP = 0x20,
|
||||
/**
|
||||
* The PRIORITY_DEPENDENCY flag.
|
||||
*/
|
||||
NGHTTP2_FLAG_PRIORITY_DEPENDENCY = 0x40
|
||||
} nghttp2_flag;
|
||||
|
||||
/**
|
||||
|
@ -634,6 +644,85 @@ typedef enum {
|
|||
NGHTTP2_HCAT_HEADERS = 3
|
||||
} nghttp2_headers_category;
|
||||
|
||||
/**
|
||||
* @enum
|
||||
*
|
||||
* The type of priority specified in :type:`nghttp2_priority_spec`.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* No priority is given.
|
||||
*/
|
||||
NGHTTP2_PRIORITY_TYPE_NONE,
|
||||
/**
|
||||
* Priority group ID and its weight are specified.
|
||||
*/
|
||||
NGHTTP2_PRIORITY_TYPE_GROUP,
|
||||
/**
|
||||
* The stream ID of a stream to depend on and its exclusive flag is
|
||||
* specified.
|
||||
*/
|
||||
NGHTTP2_PRIORITY_TYPE_DEP
|
||||
} nghttp2_priority_type;
|
||||
|
||||
/**
|
||||
* @struct
|
||||
*
|
||||
* This structure stores priority group ID and its weight.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* The priority group ID
|
||||
*/
|
||||
int32_t pri_group_id;
|
||||
/**
|
||||
* The weight of the priority group
|
||||
*/
|
||||
uint8_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;
|
||||
/**
|
||||
* nonzero means exclusive dependency
|
||||
*/
|
||||
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 {
|
||||
nghttp2_priority_group group;
|
||||
nghttp2_priority_dep dep;
|
||||
};
|
||||
} nghttp2_priority_spec;
|
||||
|
||||
/**
|
||||
* @struct
|
||||
* The HEADERS frame. It has the following members:
|
||||
|
@ -648,6 +737,10 @@ typedef struct {
|
|||
* and PAD_LOW.
|
||||
*/
|
||||
size_t padlen;
|
||||
/**
|
||||
* The priority specification
|
||||
*/
|
||||
nghttp2_priority_spec pri_spec;
|
||||
/**
|
||||
* The name/value pairs.
|
||||
*/
|
||||
|
@ -660,10 +753,6 @@ typedef struct {
|
|||
* The category of this HEADERS frame.
|
||||
*/
|
||||
nghttp2_headers_category cat;
|
||||
/**
|
||||
* The priority.
|
||||
*/
|
||||
int32_t pri;
|
||||
} nghttp2_headers;
|
||||
|
||||
/**
|
||||
|
@ -676,9 +765,9 @@ typedef struct {
|
|||
*/
|
||||
nghttp2_frame_hd hd;
|
||||
/**
|
||||
* The priority.
|
||||
* The priority specification.
|
||||
*/
|
||||
int32_t pri;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
} nghttp2_priority;
|
||||
|
||||
/**
|
||||
|
@ -1883,13 +1972,39 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf,
|
|||
*/
|
||||
const char* nghttp2_strerror(int lib_error_code);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Initializes |pri_spec| with priority group ID |pri_group_id| and
|
||||
* its weight |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,
|
||||
int32_t pri_group_id, uint8_t weight);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Initializes |pri_spec| with the |stream_id| of the stream to depend
|
||||
* on and its exclusive flag. If |exclusive| is nonzero, exclusive
|
||||
* flag is set.
|
||||
*/
|
||||
void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec,
|
||||
int32_t stream_id, int exclusive);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Submits HEADERS frame and optionally one or more DATA frames.
|
||||
*
|
||||
* The |pri| is priority of this request. 0 is the highest priority
|
||||
* value and :macro:`NGHTTP2_PRI_LOWEST` is the lowest value.
|
||||
* The |pri_spec| is priority specification of this request. ``NULL``
|
||||
* means the default priority (priority group ID becomes its stream ID
|
||||
* and weight is :macro:`NGHTTP2_DEFAULT_WEIGHT). To specify the
|
||||
* priority, use either `nghttp2_priority_spec_group_init()` or
|
||||
* `nghttp2_priority_spec_dep_init()`. If |pri_spec| is not ``NULL``,
|
||||
* this function will copy its data members.
|
||||
*
|
||||
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
||||
* |nvlen| elements. The value is opaque sequence of bytes and
|
||||
|
@ -1931,12 +2046,11 @@ const char* nghttp2_strerror(int lib_error_code);
|
|||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* The |pri| is invalid
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_submit_request(nghttp2_session *session, int32_t pri,
|
||||
int nghttp2_submit_request(nghttp2_session *session,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data);
|
||||
|
@ -1990,7 +2104,6 @@ int nghttp2_submit_response(nghttp2_session *session,
|
|||
* following values:
|
||||
*
|
||||
* * :enum:`NGHTTP2_FLAG_END_STREAM`
|
||||
* * :enum:`NGHTTP2_FLAG_PRIORITY`
|
||||
*
|
||||
* If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has
|
||||
* END_STREAM flag set.
|
||||
|
@ -2004,7 +2117,12 @@ int nghttp2_submit_response(nghttp2_session *session,
|
|||
* actual stream ID is assigned just before the frame is sent. For
|
||||
* response, specify stream ID in |stream_id|.
|
||||
*
|
||||
* The |pri| is priority of this request.
|
||||
* The |pri_spec| is priority specification of this request. ``NULL``
|
||||
* means the default priority (priority group ID becomes its stream ID
|
||||
* and weight is :macro:`NGHTTP2_DEFAULT_WEIGHT). To specify the
|
||||
* priority, use either `nghttp2_priority_spec_group_init()` or
|
||||
* `nghttp2_priority_spec_dep_init()`. If |pri_spec| is not ``NULL``,
|
||||
* this function will copy its data members.
|
||||
*
|
||||
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
||||
* |nvlen| elements. The value is opaque sequence of bytes and
|
||||
|
@ -2028,13 +2146,12 @@ int nghttp2_submit_response(nghttp2_session *session,
|
|||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* The |pri| is invalid
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, int32_t pri,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
void *stream_user_data);
|
||||
|
||||
|
@ -2064,21 +2181,28 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
|||
* @function
|
||||
*
|
||||
* Submits PRIORITY frame to change the priority of stream |stream_id|
|
||||
* to the priority value |pri|.
|
||||
* to the priority specification |pri_spec|.
|
||||
*
|
||||
* The |flags| is currently ignored and should be
|
||||
* :enum:`NGHTTP2_FLAG_NONE`.
|
||||
*
|
||||
* The |pri_spec| is priority specification of this request. ``NULL``
|
||||
* is not allowed for this function. To specify the priority, use
|
||||
* either `nghttp2_priority_spec_group_init()` or
|
||||
* `nghttp2_priority_spec_dep_init()`. This function will copy its
|
||||
* data members.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* The |pri| is negative.
|
||||
* The |pri_spec| is NULL; or trying to depend on itself.
|
||||
*/
|
||||
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, int32_t pri);
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
/**
|
||||
* @function
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_net.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
int nghttp2_frame_is_data_frame(uint8_t *head)
|
||||
{
|
||||
|
@ -64,7 +65,8 @@ static void nghttp2_frame_set_hd(nghttp2_frame_hd *hd, uint16_t length,
|
|||
}
|
||||
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame,
|
||||
uint8_t flags, int32_t stream_id, int32_t pri,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
nghttp2_frame_set_hd(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
|
||||
|
@ -72,7 +74,7 @@ void nghttp2_frame_headers_init(nghttp2_headers *frame,
|
|||
frame->nva = nva;
|
||||
frame->nvlen = nvlen;
|
||||
frame->cat = NGHTTP2_HCAT_REQUEST;
|
||||
frame->pri = pri;
|
||||
frame->pri_spec = *pri_spec;
|
||||
}
|
||||
|
||||
void nghttp2_frame_headers_free(nghttp2_headers *frame)
|
||||
|
@ -81,11 +83,25 @@ void nghttp2_frame_headers_free(nghttp2_headers *frame)
|
|||
}
|
||||
|
||||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
||||
int32_t pri)
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
nghttp2_frame_set_hd(&frame->hd, 4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE,
|
||||
stream_id);
|
||||
frame->pri = pri;
|
||||
uint8_t flags;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void nghttp2_frame_priority_free(nghttp2_priority *frame)
|
||||
|
@ -212,13 +228,22 @@ void nghttp2_frame_private_data_init(nghttp2_private_data *frame,
|
|||
void nghttp2_frame_private_data_free(nghttp2_private_data *frame)
|
||||
{}
|
||||
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags)
|
||||
{
|
||||
if(flags & NGHTTP2_FLAG_PRIORITY_GROUP) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
if(flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
|
||||
{
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
return 4;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return nghttp2_frame_priority_len(frame->hd.flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -319,9 +344,7 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
|
|||
return rv;
|
||||
}
|
||||
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_put_uint32be(buf->pos, frame->pri);
|
||||
}
|
||||
nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec);
|
||||
|
||||
frame->padlen = 0;
|
||||
frame->hd.length = nghttp2_bufs_len(bufs);
|
||||
|
@ -329,17 +352,64 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
|
|||
return frame_pack_headers_shared(bufs, &frame->hd);
|
||||
}
|
||||
|
||||
void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
switch(pri_spec->pri_type) {
|
||||
case NGHTTP2_PRIORITY_TYPE_GROUP:
|
||||
|
||||
nghttp2_put_uint32be(buf, pri_spec->group.pri_group_id);
|
||||
buf[4] = pri_spec->group.weight;
|
||||
|
||||
return;
|
||||
case NGHTTP2_PRIORITY_TYPE_DEP:
|
||||
|
||||
nghttp2_put_uint32be(buf, pri_spec->dep.stream_id);
|
||||
if(pri_spec->dep.exclusive) {
|
||||
buf[0] |= 0x80;
|
||||
}
|
||||
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
uint8_t flags,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
if(flags & NGHTTP2_FLAG_PRIORITY_GROUP) {
|
||||
int32_t pri_group_id;
|
||||
uint8_t weight;
|
||||
|
||||
pri_group_id = nghttp2_get_uint32(payload) & NGHTTP2_PRI_GROUP_ID_MASK;
|
||||
weight = payload[4];
|
||||
|
||||
nghttp2_priority_spec_group_init(pri_spec, pri_group_id, weight);
|
||||
} 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,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
|
||||
} else {
|
||||
frame->pri = NGHTTP2_PRI_DEFAULT;
|
||||
}
|
||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags,
|
||||
payload, payloadlen);
|
||||
frame->nva = NULL;
|
||||
frame->nvlen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -354,8 +424,9 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame)
|
|||
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
|
||||
|
||||
nghttp2_put_uint32be(buf->last, frame->pri);
|
||||
buf->last += 4;
|
||||
nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec);
|
||||
|
||||
buf->last += nghttp2_frame_priority_len(frame->hd.flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -364,7 +435,8 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
|||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
|
||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags,
|
||||
payload, payloadlen);
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 14) - 1)
|
||||
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
|
||||
|
@ -97,6 +98,31 @@ void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
|||
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf);
|
||||
|
||||
/**
|
||||
* Returns the number of priority field depending on the |flags|. If
|
||||
* |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
|
||||
* NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0.
|
||||
*/
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags);
|
||||
|
||||
/**
|
||||
* Packs the |pri_spec| in |buf|. This function assumes |buf| has
|
||||
* enough space for serialization.
|
||||
*/
|
||||
void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
/**
|
||||
* Unpacks the priority specification from payload |payload| of length
|
||||
* |payloadlen| to |pri_spec|. The |flags| is used to determine what
|
||||
* kind of priority specification is in |payload|. This function
|
||||
* assumes the |payload| contains whole priority specification.
|
||||
*/
|
||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
uint8_t flags,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen);
|
||||
|
||||
/*
|
||||
* Returns the offset from the HEADERS frame payload where the
|
||||
* compressed header block starts. The frame payload does not include
|
||||
|
@ -387,14 +413,15 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
|||
* not assigned yet, it must be -1.
|
||||
*/
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame,
|
||||
uint8_t flags, int32_t stream_id, int32_t pri,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
void nghttp2_frame_headers_free(nghttp2_headers *frame);
|
||||
|
||||
|
||||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
||||
int32_t pri);
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
void nghttp2_frame_priority_free(nghttp2_priority *frame);
|
||||
|
||||
|
|
|
@ -32,10 +32,12 @@
|
|||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_frame.h"
|
||||
|
||||
/* Priority for PING */
|
||||
#define NGHTTP2_OB_PRI_PING -10
|
||||
/* Priority for SETTINGS */
|
||||
#define NGHTTP2_OB_PRI_SETTINGS -9
|
||||
/* A bit higher weight for non-DATA frames */
|
||||
#define NGHTTP2_OB_EX_WEIGHT 256
|
||||
/* Higher weight for SETTINGS */
|
||||
#define NGHTTP2_OB_SETTINGS_WEIGHT 257
|
||||
/* Highest weight for PING */
|
||||
#define NGHTTP2_OB_PING_WEIGHT 258
|
||||
|
||||
typedef struct {
|
||||
nghttp2_data_provider *data_prd;
|
||||
|
@ -49,8 +51,11 @@ typedef struct {
|
|||
/* Type of |frame|. NGHTTP2_CTRL: nghttp2_frame*, NGHTTP2_DATA:
|
||||
nghttp2_private_data* */
|
||||
nghttp2_frame_category frame_cat;
|
||||
/* The priority used in priority comparion */
|
||||
int32_t pri;
|
||||
/* The priority used in priority comparion. Larger is served
|
||||
ealier. */
|
||||
int32_t weight;
|
||||
/* nonzero if this object is queued. */
|
||||
uint8_t queued;
|
||||
} nghttp2_outbound_item;
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2.0 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
void nghttp2_priority_spec_group_init(nghttp2_priority_spec *pri_spec,
|
||||
int32_t pri_group_id, uint8_t weight)
|
||||
{
|
||||
pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_GROUP;
|
||||
pri_spec->group.pri_group_id = pri_group_id;
|
||||
pri_spec->group.weight = weight;
|
||||
}
|
||||
|
||||
void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec,
|
||||
int32_t stream_id, int exclusive)
|
||||
{
|
||||
pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_DEP;
|
||||
pri_spec->dep.stream_id = stream_id;
|
||||
pri_spec->dep.exclusive = exclusive != 0;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* nghttp2 - HTTP/2.0 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_PRIORITY_SPEC_H
|
||||
#define NGHTTP2_PRIORITY_SPEC_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#endif /* NGHTTP2_PRIORITY_SPEC_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -116,6 +116,7 @@ typedef enum {
|
|||
|
||||
struct nghttp2_session {
|
||||
nghttp2_map /* <nghttp2_stream*> */ streams;
|
||||
nghttp2_map /* <nghttp2_stream_group*> */ stream_groups;
|
||||
/* Queue for outbound frames other than stream-creating HEADERS */
|
||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
|
||||
/* Queue for outbound stream-creating HEADERS frame */
|
||||
|
@ -307,9 +308,8 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
|||
|
||||
/*
|
||||
* Creates new stream in |session| with stream ID |stream_id|,
|
||||
* priority |pri| and flags |flags|. NGHTTP2_FLAG_END_STREAM flag is
|
||||
* set in |flags|, the sender of HEADERS will not send any further
|
||||
* data in this stream. Since this function is called when initial
|
||||
* priority |pri_spec| and flags |flags|. The |flags| is bitwise OR
|
||||
* of nghttp2_stream_flag. Since this function is called when initial
|
||||
* HEADERS is sent or received, these flags are taken from it. The
|
||||
* state of stream is set to |initial_state|. The |stream_user_data|
|
||||
* is a pointer to the arbitrary user supplied data to be associated
|
||||
|
@ -320,7 +320,8 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
|||
*/
|
||||
nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint8_t flags, int32_t pri,
|
||||
uint8_t flags,
|
||||
nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_stream_state initial_state,
|
||||
void *stream_user_data);
|
||||
|
||||
|
@ -332,8 +333,12 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
|
|||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The specified stream does not exist.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
||||
nghttp2_error_code error_code);
|
||||
|
@ -506,6 +511,14 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
|
|||
nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
|
||||
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
|
||||
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
|
||||
|
@ -580,9 +593,32 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
|
|||
size_t niv);
|
||||
|
||||
/*
|
||||
* Re-prioritize |stream|. The new priority is |pri|.
|
||||
* Re-prioritize |stream|. The new priority specification is
|
||||
* |pri_spec|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
void nghttp2_session_reprioritize_stream
|
||||
(nghttp2_session *session, nghttp2_stream *stream, int32_t pri);
|
||||
int nghttp2_session_reprioritize_stream
|
||||
(nghttp2_session *session, nghttp2_stream *stream,
|
||||
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 */
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
#include "nghttp2_stream.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
uint8_t flags, int32_t pri,
|
||||
uint8_t flags,
|
||||
nghttp2_stream_state initial_state,
|
||||
int32_t remote_initial_window_size,
|
||||
int32_t local_initial_window_size,
|
||||
|
@ -36,22 +37,33 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
|||
nghttp2_map_entry_init(&stream->map_entry, stream_id);
|
||||
stream->stream_id = stream_id;
|
||||
stream->flags = flags;
|
||||
stream->pri = pri;
|
||||
stream->state = initial_state;
|
||||
stream->shut_flags = NGHTTP2_SHUT_NONE;
|
||||
stream->stream_user_data = stream_user_data;
|
||||
stream->data = NULL;
|
||||
stream->deferred_data = NULL;
|
||||
stream->deferred_flags = NGHTTP2_DEFERRED_NONE;
|
||||
stream->remote_window_size = remote_initial_window_size;
|
||||
stream->local_window_size = local_initial_window_size;
|
||||
stream->recv_window_size = 0;
|
||||
stream->recv_reduction = 0;
|
||||
|
||||
stream->dep_prev = NULL;
|
||||
stream->dep_next = NULL;
|
||||
stream->sib_prev = NULL;
|
||||
stream->sib_next = NULL;
|
||||
|
||||
stream->stream_group = NULL;
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
|
||||
stream->num_substreams = 1;
|
||||
}
|
||||
|
||||
void nghttp2_stream_free(nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_outbound_item_free(stream->deferred_data);
|
||||
free(stream->deferred_data);
|
||||
|
||||
/* We don't free stream->data. */
|
||||
}
|
||||
|
||||
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
|
||||
|
@ -59,19 +71,216 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
|
|||
stream->shut_flags |= flag;
|
||||
}
|
||||
|
||||
static nghttp2_stream* stream_first_sib(nghttp2_stream *stream)
|
||||
{
|
||||
for(; stream->sib_prev; stream = stream->sib_prev);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static nghttp2_stream* stream_last_sib(nghttp2_stream *stream)
|
||||
{
|
||||
for(; stream->sib_next; stream = stream->sib_next);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static nghttp2_stream* stream_update_dep_length(nghttp2_stream *stream,
|
||||
ssize_t delta)
|
||||
{
|
||||
stream->num_substreams += delta;
|
||||
|
||||
stream = stream_first_sib(stream);
|
||||
|
||||
if(stream->dep_prev) {
|
||||
return stream_update_dep_length(stream->dep_prev, delta);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static void stream_update_dep_set_rest_stream_group
|
||||
(nghttp2_stream *stream, nghttp2_stream_group *stream_group)
|
||||
{
|
||||
if(stream == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp2_stream_group_remove_stream(stream->stream_group, stream);
|
||||
nghttp2_stream_group_add_stream(stream_group, stream);
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
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)
|
||||
{
|
||||
if(stream == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
|
||||
|
||||
stream_update_dep_set_rest(stream->sib_next);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
stream_update_dep_set_rest(stream->sib_next);
|
||||
stream_update_dep_set_rest(stream->dep_next);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs dfs starting |stream|, search stream which can become
|
||||
* NGHTTP2_STREAM_DPRI_TOP and queues its data.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if(stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
return stream_update_dep_set_top(stream->sib_next, pq);
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n",
|
||||
stream->stream_id));
|
||||
|
||||
if(!stream->data->queued) {
|
||||
rv = nghttp2_pq_push(pq, stream->data);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream->data->queued = 1;
|
||||
}
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
|
||||
|
||||
return stream_update_dep_set_top(stream->sib_next, pq);
|
||||
}
|
||||
|
||||
assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_DATA);
|
||||
|
||||
rv = stream_update_dep_set_top(stream->sib_next, pq);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return stream_update_dep_set_top(stream->dep_next, pq);
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
|
||||
|
||||
stream_update_dep_set_rest(stream->dep_next);
|
||||
|
||||
root_stream = nghttp2_stream_get_dep_root(stream);
|
||||
|
||||
DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream));
|
||||
|
||||
rv = stream_update_dep_set_top(root_stream, pq);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_detach_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq)
|
||||
{
|
||||
if(stream->dpri != NGHTTP2_STREAM_DPRI_TOP) {
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
|
||||
|
||||
return stream_update_dep_set_top(stream->dep_next, pq);
|
||||
}
|
||||
|
||||
int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *data,
|
||||
nghttp2_pq *pq)
|
||||
{
|
||||
assert(stream->data == NULL);
|
||||
assert(stream->deferred_data == NULL);
|
||||
|
||||
stream->data = data;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d attach data=%p\n",
|
||||
stream->stream_id, data));
|
||||
|
||||
return stream_update_dep_on_attach_data(stream, pq);
|
||||
}
|
||||
|
||||
int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq)
|
||||
{
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d detach data=%p\n",
|
||||
stream->stream_id, stream->data));
|
||||
|
||||
stream->data = NULL;
|
||||
|
||||
return stream_update_dep_on_detach_data(stream, pq);
|
||||
}
|
||||
|
||||
void nghttp2_stream_defer_data(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *data,
|
||||
uint8_t flags)
|
||||
{
|
||||
assert(stream->data);
|
||||
assert(stream->data == data);
|
||||
assert(stream->deferred_data == NULL);
|
||||
|
||||
stream->deferred_data = data;
|
||||
stream->deferred_flags = flags;
|
||||
|
||||
stream->data = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_stream_detach_deferred_data(nghttp2_stream *stream)
|
||||
int nghttp2_stream_detach_deferred_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq)
|
||||
{
|
||||
nghttp2_outbound_item *data;
|
||||
assert(stream->data == NULL);
|
||||
assert(stream->deferred_data);
|
||||
|
||||
data = stream->deferred_data;
|
||||
|
||||
stream->deferred_data = NULL;
|
||||
stream->deferred_flags = NGHTTP2_DEFERRED_NONE;
|
||||
|
||||
return nghttp2_stream_attach_data(stream, data, pq);
|
||||
}
|
||||
|
||||
static int update_initial_window_size
|
||||
|
@ -113,3 +322,344 @@ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream)
|
|||
{
|
||||
stream->state = NGHTTP2_STREAM_OPENED;
|
||||
}
|
||||
|
||||
nghttp2_stream* nghttp2_stream_get_dep_root(nghttp2_stream *stream)
|
||||
{
|
||||
for(;;) {
|
||||
if(stream->sib_prev) {
|
||||
stream = stream->sib_prev;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(stream->dep_prev) {
|
||||
stream = stream->dep_prev;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
|
||||
nghttp2_stream *target)
|
||||
{
|
||||
if(stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(stream == target) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(nghttp2_stream_dep_subtree_find(stream->sib_next, target)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return nghttp2_stream_dep_subtree_find(stream->dep_next, target);
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *si;
|
||||
|
||||
assert(stream->data == NULL);
|
||||
|
||||
DEBUGF(fprintf(stderr,
|
||||
"stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
|
||||
if(dep_stream->dep_next) {
|
||||
for(si = dep_stream->dep_next; si; si = si->sib_next) {
|
||||
stream->num_substreams += si->num_substreams;
|
||||
}
|
||||
|
||||
stream->dep_next = dep_stream->dep_next;
|
||||
stream->dep_next->dep_prev = stream;
|
||||
}
|
||||
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
|
||||
stream_update_dep_length(dep_stream, 1);
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *last_sib;
|
||||
|
||||
assert(stream->data == NULL);
|
||||
|
||||
DEBUGF(fprintf(stderr,
|
||||
"stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
|
||||
stream_update_dep_length(dep_stream, 1);
|
||||
|
||||
if(dep_stream->dep_next == NULL) {
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
last_sib = stream_last_sib(dep_stream->dep_next);
|
||||
last_sib->sib_next = stream;
|
||||
stream->sib_prev = last_sib;
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *prev, *next, *dep_next;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n",
|
||||
stream, stream->stream_id));
|
||||
|
||||
prev = stream_first_sib(stream);
|
||||
|
||||
if(prev->dep_prev) {
|
||||
stream_update_dep_length(prev->dep_prev, -1);
|
||||
}
|
||||
|
||||
if(stream->sib_prev) {
|
||||
prev = stream->sib_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
if(dep_next) {
|
||||
dep_next->dep_prev = NULL;
|
||||
|
||||
prev->sib_next = dep_next;
|
||||
dep_next->sib_prev = prev;
|
||||
} else {
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->sib_next = next;
|
||||
|
||||
if(next) {
|
||||
next->sib_prev = prev;
|
||||
}
|
||||
}
|
||||
} else if(stream->dep_prev) {
|
||||
prev = stream->dep_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
if(dep_next) {
|
||||
prev->dep_next = dep_next;
|
||||
dep_next->dep_prev = prev;
|
||||
} else if(stream->sib_next) {
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->dep_next = next;
|
||||
next->dep_prev = prev;
|
||||
|
||||
next->sib_prev = NULL;
|
||||
} else {
|
||||
prev->dep_next = NULL;
|
||||
dep_next = NULL;
|
||||
}
|
||||
} else {
|
||||
nghttp2_stream *si;
|
||||
|
||||
dep_next = NULL;
|
||||
|
||||
/* stream is a root of tree. Removing stream makes its
|
||||
descendants a root of its own subtree. */
|
||||
|
||||
for(si = stream->dep_next; si;) {
|
||||
next = si->sib_next;
|
||||
|
||||
si->dep_prev = NULL;
|
||||
si->sib_prev = NULL;
|
||||
si->sib_next = NULL;
|
||||
|
||||
si = next;
|
||||
}
|
||||
}
|
||||
|
||||
if(dep_next && stream->sib_next) {
|
||||
prev = stream_last_sib(dep_next);
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->sib_next = next;
|
||||
next->sib_prev = prev;
|
||||
}
|
||||
|
||||
stream->num_substreams = 1;
|
||||
stream->dep_prev = NULL;
|
||||
stream->dep_next = NULL;
|
||||
stream->sib_prev = NULL;
|
||||
stream->sib_next = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq)
|
||||
{
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *dep_next;
|
||||
nghttp2_stream *root_stream;
|
||||
nghttp2_stream *si;
|
||||
size_t delta_substreams;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
|
||||
"stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
|
||||
delta_substreams = stream->num_substreams;
|
||||
|
||||
stream_update_dep_set_rest_stream_group(stream, dep_stream->stream_group);
|
||||
|
||||
if(dep_stream->dep_next) {
|
||||
dep_next = dep_stream->dep_next;
|
||||
|
||||
for(si = dep_stream->dep_next; si; si = si->sib_next) {
|
||||
stream->num_substreams += si->num_substreams;
|
||||
}
|
||||
|
||||
stream_update_dep_set_rest(dep_next);
|
||||
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
|
||||
if(stream->dep_next) {
|
||||
last_sib = stream_last_sib(stream->dep_next);
|
||||
|
||||
last_sib->sib_next = dep_next;
|
||||
dep_next->sib_prev = last_sib;
|
||||
|
||||
dep_next->dep_prev = NULL;
|
||||
} else {
|
||||
stream->dep_next = dep_next;
|
||||
dep_next->dep_prev = stream;
|
||||
}
|
||||
} else {
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
}
|
||||
|
||||
root_stream = stream_update_dep_length(dep_stream, delta_substreams);
|
||||
|
||||
return stream_update_dep_set_top(root_stream, pq);
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq)
|
||||
{
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d "
|
||||
"stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
|
||||
stream_update_dep_set_rest_stream_group(stream, dep_stream->stream_group);
|
||||
|
||||
if(dep_stream->dep_next) {
|
||||
last_sib = stream_last_sib(dep_stream->dep_next);
|
||||
|
||||
last_sib->sib_next = stream;
|
||||
stream->sib_prev = last_sib;
|
||||
} else {
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
}
|
||||
|
||||
root_stream = stream_update_dep_length(dep_stream, stream->num_substreams);
|
||||
|
||||
return stream_update_dep_set_top(root_stream, pq);
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *prev, *next;
|
||||
|
||||
if(stream->sib_prev) {
|
||||
prev = stream->sib_prev;
|
||||
|
||||
prev->sib_next = stream->sib_next;
|
||||
if(prev->sib_next) {
|
||||
prev->sib_next->sib_prev = prev;
|
||||
}
|
||||
|
||||
prev = stream_first_sib(prev);
|
||||
if(prev->dep_prev) {
|
||||
stream_update_dep_length(prev->dep_prev, -stream->num_substreams);
|
||||
}
|
||||
} else if(stream->dep_prev) {
|
||||
prev = stream->dep_prev;
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->dep_next = next;
|
||||
|
||||
if(next) {
|
||||
next->dep_prev = prev;
|
||||
|
||||
next->sib_prev = NULL;
|
||||
}
|
||||
|
||||
stream_update_dep_length(prev, -stream->num_substreams);
|
||||
}
|
||||
|
||||
stream->sib_prev = NULL;
|
||||
stream->sib_next = NULL;
|
||||
stream->dep_prev = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_make_root(nghttp2_stream_group *stream_group,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq)
|
||||
{
|
||||
stream_update_dep_set_rest_stream_group(stream, stream_group);
|
||||
|
||||
return stream_update_dep_set_top(stream, pq);
|
||||
}
|
||||
|
||||
void nghttp2_stream_group_init(nghttp2_stream_group *stream_group,
|
||||
int32_t pri_group_id,
|
||||
int32_t weight)
|
||||
{
|
||||
nghttp2_map_entry_init(&stream_group->map_entry, pri_group_id);
|
||||
|
||||
stream_group->num_streams = 0;
|
||||
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_group = stream_group;
|
||||
|
||||
++stream_group->num_streams;
|
||||
}
|
||||
|
||||
void nghttp2_stream_group_remove_stream(nghttp2_stream_group *stream_group,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
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;
|
||||
|
||||
--stream_group->num_streams;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_outbound_item.h"
|
||||
#include "nghttp2_map.h"
|
||||
#include "nghttp2_pq.h"
|
||||
#include "nghttp2_int.h"
|
||||
|
||||
/*
|
||||
* If local peer is stream initiator:
|
||||
|
@ -78,23 +80,54 @@ typedef enum {
|
|||
NGHTTP2_STREAM_FLAG_PUSH = 0x01
|
||||
} nghttp2_stream_flag;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_STREAM_DPRI_NONE = 0,
|
||||
NGHTTP2_STREAM_DPRI_NO_DATA = 0x01,
|
||||
NGHTTP2_STREAM_DPRI_TOP = 0x02,
|
||||
NGHTTP2_STREAM_DPRI_REST = 0x04
|
||||
} nghttp2_stream_dpri;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_DEFERRED_NONE = 0,
|
||||
/* Indicates the DATA is deferred due to flow control. */
|
||||
NGHTTP2_DEFERRED_FLOW_CONTROL = 0x01
|
||||
} nghttp2_deferred_flag;
|
||||
|
||||
typedef struct {
|
||||
struct nghttp2_stream_group;
|
||||
|
||||
typedef struct nghttp2_stream_group nghttp2_stream_group;
|
||||
|
||||
struct nghttp2_stream;
|
||||
|
||||
typedef struct nghttp2_stream nghttp2_stream;
|
||||
|
||||
struct nghttp2_stream {
|
||||
/* Intrusive Map */
|
||||
nghttp2_map_entry map_entry;
|
||||
/* pointers to form dependency tree. If multiple streams depend on
|
||||
a stream, only one stream (left most) has non-NULL dep_prev which
|
||||
points to the stream it depends on. The remaining streams are
|
||||
linked using sib_prev and sib_next. The stream which has
|
||||
non-NULL dep_prev always NULL sib_prev. The right most stream
|
||||
has NULL sib_next. If this stream is a root of dependency tree,
|
||||
dep_prev and sib_prev are NULL. */
|
||||
nghttp2_stream *dep_prev, *dep_next;
|
||||
nghttp2_stream *sib_prev, *sib_next;
|
||||
/* The arbitrary data provided by user for this stream. */
|
||||
void *stream_user_data;
|
||||
/* Active DATA frame */
|
||||
nghttp2_outbound_item *data;
|
||||
/* Deferred DATA frame */
|
||||
nghttp2_outbound_item *deferred_data;
|
||||
/* stream ID */
|
||||
int32_t stream_id;
|
||||
/* Use same value in request HEADERS frame */
|
||||
int32_t pri;
|
||||
/* priority group this stream belongs to */
|
||||
nghttp2_stream_group *stream_group;
|
||||
/* categorized priority of this stream. Only stream bearing
|
||||
NGHTTP2_STREAM_DPRI_TOP can send DATA frame. */
|
||||
nghttp2_stream_dpri dpri;
|
||||
/* the number of nodes in subtree */
|
||||
size_t num_substreams;
|
||||
/* Current remote window size. This value is computed against the
|
||||
current initial window size of remote endpoint. */
|
||||
int32_t remote_window_size;
|
||||
|
@ -117,10 +150,10 @@ typedef struct {
|
|||
/* The flags for defered DATA. Bitwise OR of zero or more
|
||||
nghttp2_deferred_flag values */
|
||||
uint8_t deferred_flags;
|
||||
} nghttp2_stream;
|
||||
};
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
uint8_t flags, int32_t pri,
|
||||
uint8_t flags,
|
||||
nghttp2_stream_state initial_state,
|
||||
int32_t remote_initial_window_size,
|
||||
int32_t local_initial_window_size,
|
||||
|
@ -147,7 +180,8 @@ void nghttp2_stream_defer_data(nghttp2_stream *stream,
|
|||
* Detaches deferred data from this stream. This function does not
|
||||
* free deferred data.
|
||||
*/
|
||||
void nghttp2_stream_detach_deferred_data(nghttp2_stream *stream);
|
||||
int nghttp2_stream_detach_deferred_data(nghttp2_stream *stream,
|
||||
nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Updates the remote window size with the new value
|
||||
|
@ -182,4 +216,154 @@ int nghttp2_stream_update_local_initial_window_size
|
|||
*/
|
||||
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns the stream positioned in root of the dependency tree the
|
||||
* |stream| belongs to.
|
||||
*/
|
||||
nghttp2_stream* nghttp2_stream_get_dep_root(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |target| is found in subtree of |stream|.
|
||||
*/
|
||||
int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
|
||||
nghttp2_stream *target);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* exclusive. All existing direct descendants of |dep_stream| become
|
||||
* the descendants of the |stream|. This function assumes
|
||||
* |stream->data| is NULL and no dpri members are changed in this
|
||||
* dependency tree. It also does not change stream->stream_group.
|
||||
*/
|
||||
void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* not exclusive. This function assumes |stream->data| is NULL and no
|
||||
* dpri members are changed in this dependency tree. It also does not
|
||||
* change stream->stream_group.
|
||||
*/
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Removes the |stream| from the current dependency tree. This
|
||||
* function assumes |stream->data| is NULL.
|
||||
*/
|
||||
void nghttp2_stream_dep_remove(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Attaches |data| to |stream|. Updates dpri members in this
|
||||
* dependency tree.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *data,
|
||||
nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Detaches |data| from |stream|. Updates dpri members in this
|
||||
* dependency tree.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq);
|
||||
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* exclusive. Updates dpri members in this dependency tree.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* not exclusive. Updates dpri members in this dependency tree.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Removes subtree whose root stream is |stream|. Removing subtree
|
||||
* does not change dpri values.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| as root for |stream_group|. Updates dpri
|
||||
* members in this dependency tree.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_make_root(nghttp2_stream_group *stream_group,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Priority group of streams.
|
||||
*/
|
||||
struct nghttp2_stream_group {
|
||||
/* Intrusive Map */
|
||||
nghttp2_map_entry map_entry;
|
||||
/* The number of streams this priority group contains */
|
||||
size_t num_streams;
|
||||
/* The priority group ID */
|
||||
int32_t pri_group_id;
|
||||
/* The weight of this group */
|
||||
int32_t weight;
|
||||
};
|
||||
|
||||
void nghttp2_stream_group_init(nghttp2_stream_group *stream_group,
|
||||
int32_t pri_group_id,
|
||||
int32_t weight);
|
||||
|
||||
void nghttp2_stream_group_free(nghttp2_stream_group *stream_group);
|
||||
|
||||
/*
|
||||
* Adds |stream| to |stream_group|.
|
||||
*/
|
||||
void nghttp2_stream_group_add_stream(nghttp2_stream_group *stream_group,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Removes |stream| from |stream_group|.
|
||||
*/
|
||||
void nghttp2_stream_group_remove_stream(nghttp2_stream_group *stream_group,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
#endif /* NGHTTP2_STREAM */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "nghttp2_session.h"
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
/* This function takes ownership of |nva_copy|. Regardless of the
|
||||
return value, the caller must not free |nva_copy| after this
|
||||
|
@ -38,7 +39,7 @@ static int nghttp2_submit_headers_shared
|
|||
(nghttp2_session *session,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t pri,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva_copy,
|
||||
size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
|
@ -49,10 +50,7 @@ static int nghttp2_submit_headers_shared
|
|||
nghttp2_frame *frame = NULL;
|
||||
nghttp2_data_provider *data_prd_copy = NULL;
|
||||
nghttp2_headers_aux_data *aux_data = NULL;
|
||||
if(pri < 0) {
|
||||
rv = NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(data_prd != NULL && data_prd->read_callback != NULL) {
|
||||
data_prd_copy = malloc(sizeof(nghttp2_data_provider));
|
||||
if(data_prd_copy == NULL) {
|
||||
|
@ -75,15 +73,20 @@ static int nghttp2_submit_headers_shared
|
|||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
flags_copy =
|
||||
(flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY |
|
||||
NGHTTP2_FLAG_END_SEGMENT)) |
|
||||
(flags & (NGHTTP2_FLAG_END_STREAM |
|
||||
NGHTTP2_FLAG_END_SEGMENT |
|
||||
NGHTTP2_FLAG_PRIORITY_GROUP |
|
||||
NGHTTP2_FLAG_PRIORITY_DEPENDENCY)) |
|
||||
NGHTTP2_FLAG_END_HEADERS;
|
||||
|
||||
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri,
|
||||
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri_spec,
|
||||
nva_copy, nvlen);
|
||||
|
||||
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame,
|
||||
aux_data);
|
||||
|
||||
if(rv != 0) {
|
||||
nghttp2_frame_headers_free(&frame->headers);
|
||||
goto fail2;
|
||||
|
@ -103,7 +106,7 @@ static int nghttp2_submit_headers_shared_nva
|
|||
(nghttp2_session *session,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t pri,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva,
|
||||
size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
|
@ -111,21 +114,52 @@ static int nghttp2_submit_headers_shared_nva
|
|||
{
|
||||
ssize_t rv;
|
||||
nghttp2_nv *nva_copy;
|
||||
nghttp2_priority_spec pri_spec_none = {
|
||||
NGHTTP2_PRIORITY_TYPE_NONE
|
||||
};
|
||||
const nghttp2_priority_spec *pri_spec_ptr;
|
||||
|
||||
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen);
|
||||
if(rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if(pri_spec == NULL) {
|
||||
pri_spec_ptr = &pri_spec_none;
|
||||
} else {
|
||||
pri_spec_ptr = pri_spec;
|
||||
}
|
||||
|
||||
return nghttp2_submit_headers_shared(session, flags, stream_id,
|
||||
pri, nva_copy, rv, data_prd,
|
||||
pri_spec_ptr, nva_copy, rv, data_prd,
|
||||
stream_user_data);
|
||||
}
|
||||
|
||||
int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, int32_t pri,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
void *stream_user_data)
|
||||
{
|
||||
return nghttp2_submit_headers_shared_nva(session, flags, stream_id, pri,
|
||||
flags &= NGHTTP2_FLAG_END_STREAM;
|
||||
|
||||
if(pri_spec) {
|
||||
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:
|
||||
/* Default weight */
|
||||
pri_spec = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nghttp2_submit_headers_shared_nva(session, flags, stream_id, pri_spec,
|
||||
nva, nvlen, NULL, stream_user_data);
|
||||
}
|
||||
|
||||
|
@ -137,24 +171,46 @@ int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
|
|||
}
|
||||
|
||||
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, int32_t pri)
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_frame *frame;
|
||||
if(pri < 0) {
|
||||
|
||||
if(pri_spec == NULL) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
switch(pri_spec->pri_type) {
|
||||
case NGHTTP2_PRIORITY_TYPE_GROUP:
|
||||
break;
|
||||
case NGHTTP2_PRIORITY_TYPE_DEP:
|
||||
if(stream_id == pri_spec->dep.stream_id) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
frame = malloc(sizeof(nghttp2_frame));
|
||||
|
||||
if(frame == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
nghttp2_frame_priority_init(&frame->priority, stream_id, pri);
|
||||
|
||||
nghttp2_frame_priority_init(&frame->priority, stream_id, pri_spec);
|
||||
|
||||
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
|
||||
|
||||
if(rv != 0) {
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
free(frame);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -260,26 +316,43 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t set_request_flags(int32_t pri,
|
||||
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_data_provider *data_prd)
|
||||
{
|
||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||
if(data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
flags |= NGHTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
if(pri != NGHTTP2_PRI_DEFAULT) {
|
||||
flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
|
||||
if(pri_spec) {
|
||||
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:
|
||||
/* Default weight */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
int nghttp2_submit_request(nghttp2_session *session, int32_t pri,
|
||||
int nghttp2_submit_request(nghttp2_session *session,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data)
|
||||
{
|
||||
uint8_t flags = set_request_flags(pri, data_prd);
|
||||
return nghttp2_submit_headers_shared_nva(session, flags, -1, pri, nva, nvlen,
|
||||
uint8_t flags;
|
||||
|
||||
flags = set_request_flags(pri_spec, data_prd);
|
||||
|
||||
return nghttp2_submit_headers_shared_nva(session, flags, -1, pri_spec,
|
||||
nva, nvlen,
|
||||
data_prd, stream_user_data);
|
||||
}
|
||||
|
||||
|
@ -299,7 +372,7 @@ int nghttp2_submit_response(nghttp2_session *session,
|
|||
{
|
||||
uint8_t flags = set_response_flags(data_prd);
|
||||
return nghttp2_submit_headers_shared_nva(session, flags, stream_id,
|
||||
NGHTTP2_PRI_DEFAULT, nva, nvlen,
|
||||
NULL, nva, nvlen,
|
||||
data_prd, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ void start_element_func
|
|||
if(!src_attr) {
|
||||
return;
|
||||
}
|
||||
add_link(parser_data, src_attr, REQ_PRI_MEDIUM);
|
||||
add_link(parser_data, src_attr, REQ_PRI_LOW);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -247,12 +247,6 @@ void print_flags(const nghttp2_frame_hd& hd)
|
|||
}
|
||||
s += "END_HEADERS";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PRIORITY";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PAD_LOW) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
|
@ -265,6 +259,27 @@ void print_flags(const nghttp2_frame_hd& hd)
|
|||
}
|
||||
s += "PAD_HIGH";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PRIORITY_GROUP";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
|
||||
if(!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PRIORITY_DEPENDENCY";
|
||||
}
|
||||
|
||||
break;
|
||||
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;
|
||||
case NGHTTP2_SETTINGS:
|
||||
if(hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
|
@ -332,8 +347,14 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
|||
case NGHTTP2_HEADERS:
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "(");
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
fprintf(outfile, "pri=%d, ", frame->headers.pri);
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) {
|
||||
fprintf(outfile, "pri_group_id=%d, weight=%u, ",
|
||||
frame->headers.pri_spec.group.pri_group_id,
|
||||
frame->headers.pri_spec.group.weight);
|
||||
} else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
|
||||
fprintf(outfile, "stream_id=%d, exclusive=%d, ",
|
||||
frame->headers.pri_spec.dep.stream_id,
|
||||
frame->headers.pri_spec.dep.exclusive);
|
||||
}
|
||||
fprintf(outfile, "padlen=%zu)\n", frame->headers.padlen);
|
||||
switch(frame->headers.cat) {
|
||||
|
@ -356,7 +377,21 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
|||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "(pri=%d)\n", frame->priority.pri);
|
||||
|
||||
fprintf(outfile, "(");
|
||||
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) {
|
||||
fprintf(outfile, "pri_group_id=%d, weight=%u",
|
||||
frame->priority.pri_spec.group.pri_group_id,
|
||||
frame->priority.pri_spec.group.weight);
|
||||
} else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) {
|
||||
fprintf(outfile, "stream_id=%d, exclusive=%d",
|
||||
frame->priority.pri_spec.dep.stream_id,
|
||||
frame->priority.pri_spec.dep.exclusive);
|
||||
}
|
||||
|
||||
fprintf(outfile, ")\n");
|
||||
|
||||
break;
|
||||
case NGHTTP2_RST_STREAM:
|
||||
print_frame_attr_indent();
|
||||
|
|
|
@ -148,7 +148,7 @@ void Http2Session::submit_request()
|
|||
client_->reqidx = 0;
|
||||
}
|
||||
|
||||
nghttp2_submit_request(session_, 0, nva.data(), nva.size(),
|
||||
nghttp2_submit_request(session_, nullptr, nva.data(), nva.size(),
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
|
191
src/nghttp.cc
191
src/nghttp.cc
|
@ -85,7 +85,7 @@ struct Config {
|
|||
size_t padding;
|
||||
ssize_t peer_max_concurrent_streams;
|
||||
ssize_t header_table_size;
|
||||
int32_t pri;
|
||||
int32_t weight;
|
||||
int multiply;
|
||||
// milliseconds
|
||||
int timeout;
|
||||
|
@ -103,7 +103,7 @@ struct Config {
|
|||
padding(0),
|
||||
peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS),
|
||||
header_table_size(-1),
|
||||
pri(NGHTTP2_PRI_DEFAULT),
|
||||
weight(NGHTTP2_DEFAULT_WEIGHT),
|
||||
multiply(1),
|
||||
timeout(-1),
|
||||
window_bits(-1),
|
||||
|
@ -146,6 +146,16 @@ std::string strip_fragment(const char *raw_uri)
|
|||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
struct Request;
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
struct Dependency {
|
||||
std::vector<std::vector<Request*>> deps;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
struct Request {
|
||||
Headers res_nva;
|
||||
|
@ -154,28 +164,37 @@ struct Request {
|
|||
std::string uri;
|
||||
std::string status;
|
||||
http_parser_url u;
|
||||
std::shared_ptr<Dependency> dep;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
RequestStat stat;
|
||||
int64_t data_length;
|
||||
int64_t data_offset;
|
||||
nghttp2_gzip *inflater;
|
||||
HtmlParser *html_parser;
|
||||
const nghttp2_data_provider *data_prd;
|
||||
int32_t pri;
|
||||
int32_t stream_id;
|
||||
// Recursion level: 0: first entity, 1: entity linked from first entity
|
||||
int level;
|
||||
// RequestPriority value defined in HtmlParser.h
|
||||
int pri;
|
||||
|
||||
// For pushed request, |uri| is empty and |u| is zero-cleared.
|
||||
Request(const std::string& uri, const http_parser_url &u,
|
||||
const nghttp2_data_provider *data_prd, int64_t data_length,
|
||||
int32_t pri, int level = 0)
|
||||
const nghttp2_priority_spec& pri_spec,
|
||||
std::shared_ptr<Dependency> dep, int level = 0)
|
||||
: uri(uri),
|
||||
u(u),
|
||||
dep(std::move(dep)),
|
||||
pri_spec(pri_spec),
|
||||
data_length(data_length),
|
||||
data_offset(0),
|
||||
inflater(nullptr),
|
||||
html_parser(nullptr),
|
||||
data_prd(data_prd),
|
||||
pri(pri),
|
||||
level(level)
|
||||
stream_id(-1),
|
||||
level(level),
|
||||
pri(0)
|
||||
{}
|
||||
|
||||
~Request()
|
||||
|
@ -219,6 +238,55 @@ struct Request {
|
|||
return path;
|
||||
}
|
||||
|
||||
int32_t find_dep_stream_id(int start)
|
||||
{
|
||||
for(auto i = start; i >= 0; --i) {
|
||||
for(auto req : dep->deps[i]) {
|
||||
if(req->stat.stage != STAT_ON_COMPLETE) {
|
||||
return req->stream_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
nghttp2_priority_spec resolve_dep(int32_t pri)
|
||||
{
|
||||
nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE };
|
||||
int exclusive = 0;
|
||||
int32_t stream_id = -1;
|
||||
|
||||
if(pri == 0) {
|
||||
return pri_spec;
|
||||
}
|
||||
|
||||
auto start = std::min(pri, (int)dep->deps.size() - 1);
|
||||
|
||||
for(auto i = start; i >= 0; --i) {
|
||||
if(dep->deps[i][0]->pri < pri) {
|
||||
stream_id = find_dep_stream_id(i);
|
||||
|
||||
if(i != (int)dep->deps.size() - 1) {
|
||||
exclusive = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
} else if(dep->deps[i][0]->pri == pri) {
|
||||
stream_id = find_dep_stream_id(i - 1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(stream_id == -1) {
|
||||
return pri_spec;
|
||||
}
|
||||
|
||||
nghttp2_priority_spec_dep_init(&pri_spec, stream_id, exclusive);
|
||||
|
||||
return pri_spec;
|
||||
}
|
||||
|
||||
bool is_ipv6_literal_addr() const
|
||||
{
|
||||
if(util::has_uri_field(u, UF_HOST)) {
|
||||
|
@ -773,7 +841,8 @@ struct HttpClient {
|
|||
bool add_request(const std::string& uri,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
int64_t data_length,
|
||||
int32_t pri,
|
||||
const nghttp2_priority_spec& pri_spec,
|
||||
std::shared_ptr<Dependency> dep,
|
||||
int level = 0)
|
||||
{
|
||||
http_parser_url u;
|
||||
|
@ -787,8 +856,11 @@ struct HttpClient {
|
|||
if(config.multiply == 1) {
|
||||
path_cache.insert(uri);
|
||||
}
|
||||
|
||||
reqvec.push_back(util::make_unique<Request>(uri, u, data_prd,
|
||||
data_length, pri, level));
|
||||
data_length,
|
||||
pri_spec, std::move(dep),
|
||||
level));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -892,8 +964,9 @@ int submit_request
|
|||
for(auto& kv : build_headers) {
|
||||
nva.push_back(http2::make_nv(kv.first, kv.second));
|
||||
}
|
||||
int rv = nghttp2_submit_request(client->session, req->pri,
|
||||
nva.data(), nva.size(), req->data_prd, req);
|
||||
|
||||
auto rv = nghttp2_submit_request(client->session, &req->pri_spec,
|
||||
nva.data(), nva.size(), req->data_prd, req);
|
||||
if(rv != 0) {
|
||||
std::cerr << "nghttp2_submit_request() returned error: "
|
||||
<< nghttp2_strerror(rv) << std::endl;
|
||||
|
@ -903,17 +976,6 @@ int submit_request
|
|||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int32_t adjust_pri(int32_t base_pri, int32_t rel_pri)
|
||||
{
|
||||
if((int32_t)NGHTTP2_PRI_LOWEST - rel_pri < base_pri) {
|
||||
return NGHTTP2_PRI_LOWEST;
|
||||
} else {
|
||||
return base_pri + rel_pri;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void update_html_parser(HttpClient *client, Request *req,
|
||||
const uint8_t *data, size_t len, int fin)
|
||||
|
@ -931,9 +993,23 @@ void update_html_parser(HttpClient *client, Request *req,
|
|||
util::fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_SCHEMA) &&
|
||||
util::fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_HOST) &&
|
||||
util::porteq(uri.c_str(), u, req->uri.c_str(), req->u)) {
|
||||
int32_t pri = adjust_pri(req->pri, p.second);
|
||||
// No POST data for assets
|
||||
if ( client->add_request(uri, nullptr, 0, pri, req->level+1) ) {
|
||||
|
||||
nghttp2_priority_spec pri_spec;
|
||||
|
||||
// We always specify priority group of parent stream, so that
|
||||
// even if the parent stream is closed, the dependent stream is
|
||||
// in the same priority group. We adjust the priority using
|
||||
// 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,
|
||||
req->level+1) ) {
|
||||
auto& req = client->reqvec.back();
|
||||
|
||||
req->pri = p.second;
|
||||
|
||||
submit_request(client, config.headers,
|
||||
client->reqvec.back().get());
|
||||
}
|
||||
|
@ -997,8 +1073,48 @@ void check_stream_id(nghttp2_session *session, int32_t stream_id,
|
|||
auto req = (Request*)nghttp2_session_get_stream_user_data(session,
|
||||
stream_id);
|
||||
assert(req);
|
||||
req->stream_id = stream_id;
|
||||
client->streams[stream_id] = req;
|
||||
req->record_request_time();
|
||||
|
||||
if(req->pri == 0) {
|
||||
assert(req->dep->deps.empty());
|
||||
|
||||
req->dep->deps.push_back(std::vector<Request*>{req});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(stream_id % 2 == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pri_spec = req->resolve_dep(req->pri);
|
||||
|
||||
if(pri_spec.pri_type == NGHTTP2_PRIORITY_TYPE_DEP) {
|
||||
nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, stream_id,
|
||||
&pri_spec);
|
||||
}
|
||||
|
||||
auto itr = std::begin(req->dep->deps);
|
||||
for(; itr != std::end(req->dep->deps); ++itr) {
|
||||
if((*itr)[0]->pri == req->pri) {
|
||||
(*itr).push_back(req);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if((*itr)[0]->pri > req->pri) {
|
||||
auto v = std::vector<Request*>{req};
|
||||
req->dep->deps.insert(itr, std::move(v));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(itr == std::end(req->dep->deps)) {
|
||||
req->dep->deps.push_back(std::vector<Request*>{req});
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -1075,7 +1191,10 @@ int on_begin_headers_callback(nghttp2_session *session,
|
|||
http_parser_url u;
|
||||
memset(&u, 0, sizeof(u));
|
||||
// TODO Set pri and level
|
||||
auto req = util::make_unique<Request>("", u, nullptr, 0, 0, 0);
|
||||
nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE };
|
||||
|
||||
auto req = util::make_unique<Request>("", u, nullptr, 0, pri_spec,
|
||||
nullptr);
|
||||
nghttp2_session_set_stream_user_data(session, stream_id, req.get());
|
||||
client->reqvec.push_back(std::move(req));
|
||||
check_stream_id(session, stream_id, user_data);
|
||||
|
@ -1484,10 +1603,18 @@ int communicate(const std::string& scheme, const std::string& host,
|
|||
}
|
||||
{
|
||||
HttpClient client{callbacks, evbase, ssl_ctx};
|
||||
|
||||
nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE };
|
||||
|
||||
if(config.weight != NGHTTP2_DEFAULT_WEIGHT) {
|
||||
nghttp2_priority_spec_group_init(&pri_spec, -1, config.weight);
|
||||
}
|
||||
|
||||
for(auto req : requests) {
|
||||
for(int i = 0; i < config.multiply; ++i) {
|
||||
auto dep = std::make_shared<Dependency>();
|
||||
client.add_request(std::get<0>(req), std::get<1>(req),
|
||||
std::get<2>(req), config.pri);
|
||||
std::get<2>(req), pri_spec, std::move(dep));
|
||||
}
|
||||
}
|
||||
client.update_hostport();
|
||||
|
@ -1682,9 +1809,9 @@ Options:
|
|||
is ignored if the request URI has https scheme.
|
||||
If -d is used, the HTTP upgrade request is
|
||||
performed with OPTIONS method.
|
||||
-p, --pri=<PRIORITY>
|
||||
Sets stream priority. Default: )"
|
||||
<< NGHTTP2_PRI_DEFAULT << R"(
|
||||
-p, --weight=<WEIGHT>
|
||||
Sets priority group weight. Default: )"
|
||||
<< NGHTTP2_DEFAULT_WEIGHT << R"(
|
||||
-M, --peer-max-concurrent-streams=<N>
|
||||
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value
|
||||
of remote endpoint as if it is received in
|
||||
|
@ -1721,7 +1848,7 @@ int main(int argc, char **argv)
|
|||
{"data", required_argument, nullptr, 'd'},
|
||||
{"multiply", required_argument, nullptr, 'm'},
|
||||
{"upgrade", no_argument, nullptr, 'u'},
|
||||
{"pri", required_argument, nullptr, 'p'},
|
||||
{"weight", required_argument, nullptr, 'p'},
|
||||
{"peer-max-concurrent-streams", required_argument, nullptr, 'M'},
|
||||
{"header-table-size", required_argument, nullptr, 'c'},
|
||||
{"padding", required_argument, nullptr, 'b'},
|
||||
|
@ -1758,11 +1885,11 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
case 'p': {
|
||||
auto n = strtoul(optarg, nullptr, 10);
|
||||
if(n <= NGHTTP2_PRI_LOWEST) {
|
||||
config.pri = n;
|
||||
if(n <= NGHTTP2_MAX_WEIGHT) {
|
||||
config.weight = n;
|
||||
} else {
|
||||
std::cerr << "-p: specify the integer in the range [0, "
|
||||
<< NGHTTP2_PRI_LOWEST << "], inclusive"
|
||||
<< NGHTTP2_MAX_WEIGHT << "], inclusive"
|
||||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
|
@ -578,7 +578,8 @@ int Http2Session::submit_request(Http2DownstreamConnection *dconn,
|
|||
{
|
||||
assert(state_ == CONNECTED);
|
||||
auto sd = util::make_unique<StreamData>();
|
||||
int rv = nghttp2_submit_request(session_, pri, nva, nvlen,
|
||||
// TODO Specify nullptr to pri_spec for now
|
||||
int rv = nghttp2_submit_request(session_, nullptr, nva, nvlen,
|
||||
data_prd, sd.get());
|
||||
if(rv == 0) {
|
||||
dconn->attach_stream_data(sd.get());
|
||||
|
@ -640,9 +641,15 @@ int Http2Session::submit_priority(Http2DownstreamConnection *dconn,
|
|||
return 0;
|
||||
}
|
||||
int rv;
|
||||
rv = nghttp2_submit_priority(session_, NGHTTP2_FLAG_NONE,
|
||||
dconn->get_downstream()->
|
||||
get_downstream_stream_id(), pri);
|
||||
|
||||
// TODO Disabled temporarily
|
||||
|
||||
// rv = nghttp2_submit_priority(session_, NGHTTP2_FLAG_NONE,
|
||||
// dconn->get_downstream()->
|
||||
// get_downstream_stream_id(), pri);
|
||||
|
||||
rv = 0;
|
||||
|
||||
if(rv < NGHTTP2_ERR_FATAL) {
|
||||
SSLOG(FATAL, this) << "nghttp2_submit_priority() failed: "
|
||||
<< nghttp2_strerror(rv);
|
||||
|
|
|
@ -223,9 +223,12 @@ int on_begin_headers_callback(nghttp2_session *session,
|
|||
ULOG(INFO, upstream) << "Received upstream request HEADERS stream_id="
|
||||
<< frame->hd.stream_id;
|
||||
}
|
||||
|
||||
// TODO Use priority 0 for now
|
||||
auto downstream = new Downstream(upstream,
|
||||
frame->hd.stream_id,
|
||||
frame->headers.pri);
|
||||
0);
|
||||
|
||||
upstream->add_downstream(downstream);
|
||||
downstream->init_response_body_buf();
|
||||
|
||||
|
@ -367,10 +370,11 @@ int on_frame_recv_callback
|
|||
if(!downstream) {
|
||||
break;
|
||||
}
|
||||
rv = downstream->change_priority(frame->priority.pri);
|
||||
if(rv != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
// TODO comment out for now
|
||||
// rv = downstream->change_priority(frame->priority.pri);
|
||||
// if(rv != 0) {
|
||||
// return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
// }
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_SETTINGS:
|
||||
|
|
|
@ -75,7 +75,8 @@ int htp_msg_begin(http_parser *htp)
|
|||
ULOG(INFO, upstream) << "HTTP request started";
|
||||
}
|
||||
upstream->reset_current_header_length();
|
||||
auto downstream = new Downstream(upstream, 0, NGHTTP2_PRI_DEFAULT);
|
||||
// TODO specify 0 as priority for now
|
||||
auto downstream = new Downstream(upstream, 0, 0);
|
||||
upstream->attach_downstream(downstream);
|
||||
return 0;
|
||||
}
|
||||
|
|
14
tests/main.c
14
tests/main.c
|
@ -84,6 +84,8 @@ int main(int argc, char* argv[])
|
|||
test_nghttp2_session_recv_data) ||
|
||||
!CU_add_test(pSuite, "session_recv_continuation",
|
||||
test_nghttp2_session_recv_continuation) ||
|
||||
!CU_add_test(pSuite, "session_recv_headers_with_priority",
|
||||
test_nghttp2_session_recv_headers_with_priority) ||
|
||||
!CU_add_test(pSuite, "session_recv_premature_headers",
|
||||
test_nghttp2_session_recv_premature_headers) ||
|
||||
!CU_add_test(pSuite, "session_continue", test_nghttp2_session_continue) ||
|
||||
|
@ -209,6 +211,18 @@ int main(int argc, char* argv[])
|
|||
test_nghttp2_session_pack_headers_with_padding4) ||
|
||||
!CU_add_test(pSuite, "pack_settings_payload",
|
||||
test_nghttp2_pack_settings_payload) ||
|
||||
!CU_add_test(pSuite, "session_stream_dep_add",
|
||||
test_nghttp2_session_stream_dep_add) ||
|
||||
!CU_add_test(pSuite, "session_stream_dep_remove",
|
||||
test_nghttp2_session_stream_dep_remove) ||
|
||||
!CU_add_test(pSuite, "session_stream_dep_add_subtree",
|
||||
test_nghttp2_session_stream_dep_add_subtree) ||
|
||||
!CU_add_test(pSuite, "session_stream_dep_remove_subtree",
|
||||
test_nghttp2_session_stream_dep_remove_subtree) ||
|
||||
!CU_add_test(pSuite, "session_stream_attach_data",
|
||||
test_nghttp2_session_stream_attach_data) ||
|
||||
!CU_add_test(pSuite, "session_stream_attach_data_subtree",
|
||||
test_nghttp2_session_stream_attach_data_subtree) ||
|
||||
!CU_add_test(pSuite, "frame_pack_headers",
|
||||
test_nghttp2_frame_pack_headers) ||
|
||||
!CU_add_test(pSuite, "frame_pack_headers_frame_too_large",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_test_helper.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
static nghttp2_nv make_nv(const char *name, const char *value)
|
||||
{
|
||||
|
@ -74,6 +75,7 @@ void test_nghttp2_frame_pack_headers()
|
|||
nghttp2_headers frame, oframe;
|
||||
nghttp2_bufs bufs;
|
||||
nghttp2_nv *nva;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
ssize_t nvlen;
|
||||
nva_out out;
|
||||
ssize_t hdblocklen;
|
||||
|
@ -87,10 +89,13 @@ void test_nghttp2_frame_pack_headers()
|
|||
|
||||
nva = headers();
|
||||
nvlen = HEADERS_LENGTH;
|
||||
|
||||
pri_spec.pri_type = NGHTTP2_PRIORITY_TYPE_NONE;
|
||||
|
||||
nghttp2_frame_headers_init(&frame,
|
||||
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
|
||||
1000000007,
|
||||
1 << 20, nva, nvlen);
|
||||
NGHTTP2_FLAG_END_STREAM |
|
||||
NGHTTP2_FLAG_END_HEADERS,
|
||||
1000000007, &pri_spec, nva, nvlen);
|
||||
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
|
||||
|
||||
nghttp2_bufs_rewind(&bufs);
|
||||
|
@ -103,8 +108,8 @@ void test_nghttp2_frame_pack_headers()
|
|||
NGHTTP2_HEADERS,
|
||||
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS,
|
||||
1000000007, &oframe.hd);
|
||||
/* We didn't include PRIORITY flag so priority is not packed */
|
||||
CU_ASSERT(1 << 30 == oframe.pri);
|
||||
/* We include NGHTTP2_PRIORITY_TYPE_NONE */
|
||||
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_NONE == oframe.pri_spec.pri_type);
|
||||
|
||||
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN;
|
||||
CU_ASSERT(hdblocklen ==
|
||||
|
@ -119,8 +124,10 @@ void test_nghttp2_frame_pack_headers()
|
|||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
memset(&oframe, 0, sizeof(oframe));
|
||||
/* Next, include PRIORITY flag */
|
||||
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
/* Next, include NGHTTP2_PRIORITY_TYPE_GROUP */
|
||||
nghttp2_priority_spec_group_init(&frame.pri_spec, 1000000009, 12);
|
||||
frame.hd.flags |= NGHTTP2_FLAG_PRIORITY_GROUP;
|
||||
|
||||
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
|
@ -130,20 +137,64 @@ void test_nghttp2_frame_pack_headers()
|
|||
check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN,
|
||||
NGHTTP2_HEADERS,
|
||||
NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS |
|
||||
NGHTTP2_FLAG_PRIORITY,
|
||||
NGHTTP2_FLAG_PRIORITY_GROUP,
|
||||
1000000007, &oframe.hd);
|
||||
CU_ASSERT(1 << 20 == oframe.pri);
|
||||
|
||||
hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN - 4;
|
||||
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_GROUP == oframe.pri_spec.pri_type);
|
||||
CU_ASSERT(1000000009 == oframe.pri_spec.group.pri_group_id);
|
||||
CU_ASSERT(12 == oframe.pri_spec.group.weight);
|
||||
|
||||
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 + 4));
|
||||
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_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.dep.stream_id);
|
||||
CU_ASSERT(1 == oframe.pri_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_frame_headers_free(&oframe);
|
||||
|
||||
nghttp2_frame_headers_free(&frame);
|
||||
nghttp2_hd_inflate_free(&inflater);
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
|
@ -155,6 +206,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
|
|||
nghttp2_headers frame;
|
||||
nghttp2_bufs bufs;
|
||||
nghttp2_nv *nva;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
ssize_t nvlen;
|
||||
size_t big_vallen = NGHTTP2_HD_MAX_VALUE;
|
||||
nghttp2_nv big_hds[16];
|
||||
|
@ -173,12 +225,13 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void)
|
|||
big_hds[i].valuelen = big_vallen;
|
||||
}
|
||||
|
||||
pri_spec.pri_type = NGHTTP2_PRIORITY_TYPE_NONE;
|
||||
|
||||
nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen);
|
||||
nghttp2_hd_deflate_init(&deflater);
|
||||
nghttp2_frame_headers_init(&frame,
|
||||
NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS,
|
||||
1000000007,
|
||||
0, nva, nvlen);
|
||||
1000000007, &pri_spec, nva, nvlen);
|
||||
rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater);
|
||||
CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == rv);
|
||||
|
||||
|
@ -194,22 +247,53 @@ void test_nghttp2_frame_pack_priority(void)
|
|||
{
|
||||
nghttp2_priority frame, oframe;
|
||||
nghttp2_bufs bufs;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
int rv;
|
||||
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
nghttp2_frame_priority_init(&frame, 1000000007, 1 << 30);
|
||||
/* First, pack priority with priority group and weight */
|
||||
nghttp2_priority_spec_group_init(&pri_spec, 1000000009, 12);
|
||||
|
||||
nghttp2_frame_priority_init(&frame, 1000000007, &pri_spec);
|
||||
rv = nghttp2_frame_pack_priority(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(13 == nghttp2_bufs_len(&bufs));
|
||||
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
|
||||
check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_PRIORITY_GROUP,
|
||||
1000000007, &oframe.hd);
|
||||
|
||||
CU_ASSERT(NGHTTP2_PRIORITY_TYPE_GROUP == oframe.pri_spec.pri_type);
|
||||
CU_ASSERT(1000000009 == oframe.pri_spec.group.pri_group_id);
|
||||
CU_ASSERT(12 == oframe.pri_spec.group.weight);
|
||||
|
||||
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_NONE, 1000000007,
|
||||
&oframe.hd);
|
||||
CU_ASSERT(1 << 30 == oframe.pri);
|
||||
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.dep.stream_id);
|
||||
CU_ASSERT(1 == oframe.pri_spec.dep.exclusive);
|
||||
|
||||
nghttp2_frame_priority_free(&oframe);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
nghttp2_bufs_free(&bufs);
|
||||
nghttp2_frame_priority_free(&oframe);
|
||||
nghttp2_frame_priority_free(&frame);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,7 @@ void test_nghttp2_session_recv_invalid_frame(void);
|
|||
void test_nghttp2_session_recv_eof(void);
|
||||
void test_nghttp2_session_recv_data(void);
|
||||
void test_nghttp2_session_recv_continuation(void);
|
||||
void test_nghttp2_session_recv_headers_with_priority(void);
|
||||
void test_nghttp2_session_recv_premature_headers(void);
|
||||
void test_nghttp2_session_continue(void);
|
||||
void test_nghttp2_session_add_frame(void);
|
||||
|
@ -96,5 +97,11 @@ void test_nghttp2_session_pack_headers_with_padding2(void);
|
|||
void test_nghttp2_session_pack_headers_with_padding3(void);
|
||||
void test_nghttp2_session_pack_headers_with_padding4(void);
|
||||
void test_nghttp2_pack_settings_payload(void);
|
||||
void test_nghttp2_session_stream_dep_add(void);
|
||||
void test_nghttp2_session_stream_dep_remove(void);
|
||||
void test_nghttp2_session_stream_dep_add_subtree(void);
|
||||
void test_nghttp2_session_stream_dep_remove_subtree(void);
|
||||
void test_nghttp2_session_stream_attach_data(void);
|
||||
void test_nghttp2_session_stream_attach_data_subtree(void);
|
||||
|
||||
#endif /* NGHTTP2_SESSION_TEST_H */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <CUnit/CUnit.h>
|
||||
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
int unpack_framebuf(nghttp2_frame *frame, nghttp2_bufs *bufs)
|
||||
{
|
||||
|
@ -213,3 +214,47 @@ void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size)
|
|||
/* 2 for PAD_HIGH and PAD_LOW */
|
||||
nghttp2_bufs_init2(bufs, chunk_size, 16, NGHTTP2_FRAME_HDLEN + 2);
|
||||
}
|
||||
|
||||
nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id)
|
||||
{
|
||||
nghttp2_priority_spec pri_spec;
|
||||
|
||||
nghttp2_priority_spec_group_init(&pri_spec, stream_id,
|
||||
NGHTTP2_DEFAULT_WEIGHT);
|
||||
|
||||
return nghttp2_session_open_stream(session, stream_id,
|
||||
NGHTTP2_STREAM_FLAG_NONE,
|
||||
&pri_spec,
|
||||
NGHTTP2_STREAM_OPENED,
|
||||
NULL);
|
||||
}
|
||||
|
||||
nghttp2_stream* open_stream_with_dep(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
nghttp2_stream *dep_stream)
|
||||
{
|
||||
nghttp2_priority_spec pri_spec;
|
||||
|
||||
nghttp2_priority_spec_dep_init(&pri_spec, dep_stream->stream_id, 0);
|
||||
|
||||
return nghttp2_session_open_stream(session, stream_id,
|
||||
NGHTTP2_STREAM_FLAG_NONE,
|
||||
&pri_spec,
|
||||
NGHTTP2_STREAM_OPENED,
|
||||
NULL);
|
||||
}
|
||||
|
||||
nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
nghttp2_stream *dep_stream)
|
||||
{
|
||||
nghttp2_priority_spec pri_spec;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_session.h"
|
||||
|
||||
#define MAKE_NV(NAME, VALUE) \
|
||||
{ (uint8_t*)NAME, (uint8_t*)VALUE, strlen(NAME), strlen(VALUE) }
|
||||
|
@ -81,4 +82,14 @@ void frame_pack_bufs_init(nghttp2_bufs *bufs);
|
|||
|
||||
void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size);
|
||||
|
||||
nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id);
|
||||
|
||||
nghttp2_stream* open_stream_with_dep(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
nghttp2_stream *dep_stream);
|
||||
|
||||
nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
nghttp2_stream *dep_stream);
|
||||
|
||||
#endif /* NGHTTP2_TEST_HELPER_H */
|
||||
|
|
Loading…
Reference in New Issue