Add simple HTTP/2 extension framework
Application can utilize this framework to send/receive user defined extension frames. These frames are expected not to change existing protocol behaviour.
This commit is contained in:
parent
3f4b6f2b1c
commit
3785cf07ba
|
@ -62,16 +62,19 @@ APIDOCS= \
|
|||
nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_extension_chunk_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_frame_not_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_header_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback.rst \
|
||||
nghttp2_session_callbacks_set_pack_extension_callback.rst \
|
||||
nghttp2_session_callbacks_set_recv_callback.rst \
|
||||
nghttp2_session_callbacks_set_select_padding_callback.rst \
|
||||
nghttp2_session_callbacks_set_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_send_data_callback.rst \
|
||||
nghttp2_session_callbacks_set_unpack_extension_callback.rst \
|
||||
nghttp2_session_client_new.rst \
|
||||
nghttp2_session_client_new2.rst \
|
||||
nghttp2_session_client_new3.rst \
|
||||
|
@ -118,6 +121,7 @@ APIDOCS= \
|
|||
nghttp2_stream_get_weight.rst \
|
||||
nghttp2_strerror.rst \
|
||||
nghttp2_submit_data.rst \
|
||||
nghttp2_submit_extension.rst \
|
||||
nghttp2_submit_goaway.rst \
|
||||
nghttp2_submit_headers.rst \
|
||||
nghttp2_submit_ping.rst \
|
||||
|
|
|
@ -378,6 +378,10 @@ typedef enum {
|
|||
* Unexpected internal error, but recovered.
|
||||
*/
|
||||
NGHTTP2_ERR_INTERNAL = -534,
|
||||
/**
|
||||
* Indicates that a processing was canceled.
|
||||
*/
|
||||
NGHTTP2_ERR_CANCEL = -535,
|
||||
/**
|
||||
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
||||
* under unexpected condition and processing was terminated (e.g.,
|
||||
|
@ -1657,6 +1661,94 @@ typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session,
|
|||
const nghttp2_frame_hd *hd,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
* Callback function invoked when chunk of extension frame payload is
|
||||
* received. The |hd| points to frame header. The received
|
||||
* chunk is |data| of length |len|.
|
||||
*
|
||||
* The implementation of this function must return 0 if it succeeds.
|
||||
*
|
||||
* To abort processing this extension frame, return
|
||||
* :enum:`NGHTTP2_ERR_CANCEL`.
|
||||
*
|
||||
* If fatal error occurred, application should return
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
|
||||
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
|
||||
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
|
||||
* other values are returned, currently they are treated as
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_extension_chunk_recv_callback)(
|
||||
nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
|
||||
size_t len, void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
* Callback function invoked when library asks the application to
|
||||
* unpack extension payload from its wire format. The extension
|
||||
* payload has been passed to the application using
|
||||
* :type:`nghttp2_on_extension_chunk_recv_callback`. The frame header
|
||||
* is already unpacked by the library and provided as |hd|.
|
||||
*
|
||||
* The implementation of this function may store the pointer to the
|
||||
* created object as a result of unpacking in |*payload|, and returns
|
||||
* 0. The pointer stored in |*payload| is opaque to the library, and
|
||||
* the library does not own its pointer. |*payload| is initialled as
|
||||
* `NULL`.
|
||||
*
|
||||
* To abort processing this extension frame, return
|
||||
* :enum:`NGHTTP2_ERR_CANCEL`.
|
||||
*
|
||||
* If fatal error occurred, application should return
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
|
||||
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
|
||||
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
|
||||
* other values are returned, currently they are treated as
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
|
||||
void **payload,
|
||||
const nghttp2_frame_hd *hd,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
* Callbck function invoked when library asks the application to pack
|
||||
* extension payload in its wire format. The frame header will be
|
||||
* packed by library. Application must pack payload only.
|
||||
* frame->ext.payload is the object passed to
|
||||
* `nghttp2_submit_extension()` as payload parameter. The |*flags| is
|
||||
* initialized to the flags parameter passed in
|
||||
* `nghttp2_submit_extension()`. Application can modify flags value
|
||||
* if it wants. Application must pack extension payload to the |buf|
|
||||
* of its capacity |len| bytes.
|
||||
*
|
||||
* The implementation of this function returns the number of bytes
|
||||
* written into |buf| when it succeeds.
|
||||
*
|
||||
* To abort processing this extension frame, return
|
||||
* :enum:`NGHTTP2_ERR_CANCEL`, and
|
||||
* :type:`nghttp2_on_frame_not_send_callback` will be invoked.
|
||||
*
|
||||
* If fatal error occurred, application should return
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
|
||||
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
|
||||
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
|
||||
* other values are returned, currently they are treated as
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the return value is
|
||||
* strictly larger than |len|, it is treated as
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
|
||||
uint8_t *flags, uint8_t *buf,
|
||||
size_t len,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data);
|
||||
|
||||
struct nghttp2_session_callbacks;
|
||||
|
||||
/**
|
||||
|
@ -1849,6 +1941,37 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback(
|
|||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_send_data_callback send_data_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked when the library asks the
|
||||
* application to pack extension frame payload in wire format.
|
||||
*/
|
||||
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_pack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_pack_extension_callback pack_extension_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked when the library asks the
|
||||
* application to unpack extension frame payload from wire format.
|
||||
*/
|
||||
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_unpack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_unpack_extension_callback unpack_extension_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked when chunk of extension frame
|
||||
* payload is received.
|
||||
*/
|
||||
NGHTTP2_EXTERN void
|
||||
nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
|
@ -3515,6 +3638,37 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
|
|||
int32_t stream_id,
|
||||
int32_t window_size_increment);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Submits extension frame.
|
||||
*
|
||||
* Application can pass arbitrary frame flags and stream ID to |flags|
|
||||
* and |stream_id| respectively. The |payload| is opaque pointer, and
|
||||
* it can be accessible though frame->ext.payload in
|
||||
* :type:`nghttp2_pack_extension_callback`. The library will not own
|
||||
* passed |payload| pointer.
|
||||
*
|
||||
* The standard HTTP/2 frame cannot be sent with this function, so
|
||||
* |type| must be strictly grater than 0x9. Otherwise, this function
|
||||
* will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_INVALID_STATE`
|
||||
* If :type:`nghttp2_pack_extension_callback` is not set.
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* If |type| specifies standard HTTP/2 frame type. The frame
|
||||
* types in the rage [0x0, 0x9], both inclusive, are standard
|
||||
* HTTP/2 frame type, and cannot be sent using this function.
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory
|
||||
*/
|
||||
NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
|
||||
uint8_t type, uint8_t flags,
|
||||
int32_t stream_id, void *payload);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
|
|
@ -127,3 +127,21 @@ void nghttp2_session_callbacks_set_send_data_callback(
|
|||
nghttp2_send_data_callback send_data_callback) {
|
||||
cbs->send_data_callback = send_data_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_pack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_pack_extension_callback pack_extension_callback) {
|
||||
cbs->pack_extension_callback = pack_extension_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_unpack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_unpack_extension_callback unpack_extension_callback) {
|
||||
cbs->unpack_extension_callback = unpack_extension_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) {
|
||||
cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,9 @@ struct nghttp2_session_callbacks {
|
|||
*/
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
||||
nghttp2_send_data_callback send_data_callback;
|
||||
nghttp2_pack_extension_callback pack_extension_callback;
|
||||
nghttp2_unpack_extension_callback unpack_extension_callback;
|
||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_CALLBACKS_H */
|
||||
|
|
|
@ -184,6 +184,15 @@ void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
|
|||
|
||||
void nghttp2_frame_data_free(nghttp2_data *frame _U_) {}
|
||||
|
||||
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
void *payload) {
|
||||
nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id);
|
||||
frame->payload = payload;
|
||||
}
|
||||
|
||||
void nghttp2_frame_extension_free(nghttp2_extension *frame _U_) {}
|
||||
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags) {
|
||||
if (flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
return NGHTTP2_PRIORITY_SPECLEN;
|
||||
|
|
|
@ -439,6 +439,12 @@ void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
|||
|
||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
|
||||
|
||||
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
void *payload);
|
||||
|
||||
void nghttp2_frame_extension_free(nghttp2_extension *frame);
|
||||
|
||||
/*
|
||||
* Returns the number of padding bytes after payload. The total
|
||||
* padding length is given in the |padlen|. The returned value does
|
||||
|
|
|
@ -288,6 +288,8 @@ const char *nghttp2_strerror(int error_code) {
|
|||
return "Stream was refused";
|
||||
case NGHTTP2_ERR_INTERNAL:
|
||||
return "Internal error";
|
||||
case NGHTTP2_ERR_CANCEL:
|
||||
return "Cancel";
|
||||
case NGHTTP2_ERR_NOMEM:
|
||||
return "Out of memory";
|
||||
case NGHTTP2_ERR_CALLBACK_FAILURE:
|
||||
|
|
|
@ -72,6 +72,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
|||
case NGHTTP2_WINDOW_UPDATE:
|
||||
nghttp2_frame_window_update_free(&frame->window_update);
|
||||
break;
|
||||
default:
|
||||
nghttp2_frame_extension_free(&frame->ext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1718,6 +1718,44 @@ static size_t session_estimate_headers_payload(nghttp2_session *session,
|
|||
additional;
|
||||
}
|
||||
|
||||
static int session_pack_extension(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||
nghttp2_frame *frame) {
|
||||
ssize_t rv;
|
||||
uint8_t flags;
|
||||
nghttp2_buf *buf;
|
||||
size_t buflen;
|
||||
size_t framelen;
|
||||
|
||||
assert(session->callbacks.pack_extension_callback);
|
||||
|
||||
flags = frame->hd.flags;
|
||||
buf = &bufs->head->buf;
|
||||
buflen = nghttp2_min(nghttp2_buf_avail(buf), NGHTTP2_MAX_PAYLOADLEN);
|
||||
|
||||
rv = session->callbacks.pack_extension_callback(
|
||||
session, &flags, buf->last, buflen, frame, session->user_data);
|
||||
if (rv == NGHTTP2_ERR_CANCEL) {
|
||||
return (int)rv;
|
||||
}
|
||||
|
||||
if (rv < 0 || (size_t)rv > buflen) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
framelen = (size_t)rv;
|
||||
|
||||
frame->hd.flags = flags;
|
||||
frame->hd.length = framelen;
|
||||
|
||||
assert(buf->pos == buf->last);
|
||||
buf->last += framelen;
|
||||
buf->pos -= NGHTTP2_FRAME_HDLEN;
|
||||
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function serializes frame for transmission.
|
||||
*
|
||||
|
@ -1956,8 +1994,18 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
nghttp2_frame_pack_window_update(&session->aob.framebufs,
|
||||
&frame->window_update);
|
||||
break;
|
||||
case NGHTTP2_CONTINUATION:
|
||||
/* We never handle CONTINUATION here. */
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
/* extension frame */
|
||||
rv = session_pack_extension(session, &session->aob.framebufs, frame);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -3016,6 +3064,47 @@ static int session_call_on_header(nghttp2_session *session,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
session_call_on_extension_chunk_recv_callback(nghttp2_session *session,
|
||||
const uint8_t *data, size_t len) {
|
||||
int rv;
|
||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||
nghttp2_frame *frame = &iframe->frame;
|
||||
|
||||
if (session->callbacks.on_extension_chunk_recv_callback) {
|
||||
rv = session->callbacks.on_extension_chunk_recv_callback(
|
||||
session, &frame->hd, data, len, session->user_data);
|
||||
if (rv == NGHTTP2_ERR_CANCEL) {
|
||||
return rv;
|
||||
}
|
||||
if (rv != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_call_unpack_extension_callback(nghttp2_session *session) {
|
||||
int rv;
|
||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||
nghttp2_frame *frame = &iframe->frame;
|
||||
void *payload = NULL;
|
||||
|
||||
rv = session->callbacks.unpack_extension_callback(
|
||||
session, &payload, &frame->hd, session->user_data);
|
||||
if (rv == NGHTTP2_ERR_CANCEL) {
|
||||
return rv;
|
||||
}
|
||||
if (rv != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
frame->ext.payload = payload;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles frame size error.
|
||||
*
|
||||
|
@ -4383,6 +4472,24 @@ static int session_process_window_update_frame(nghttp2_session *session) {
|
|||
return nghttp2_session_on_window_update_received(session, frame);
|
||||
}
|
||||
|
||||
static int session_process_extension_frame(nghttp2_session *session) {
|
||||
int rv;
|
||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||
nghttp2_frame *frame = &iframe->frame;
|
||||
|
||||
rv = session_call_unpack_extension_callback(session);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* This handles the case where rv == NGHTTP2_ERR_CANCEL as well */
|
||||
if (rv != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_call_on_frame_received(session, frame);
|
||||
}
|
||||
|
||||
int nghttp2_session_on_data_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame) {
|
||||
int rv = 0;
|
||||
|
@ -5184,6 +5291,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||
default:
|
||||
DEBUGF(fprintf(stderr, "recv: unknown frame\n"));
|
||||
|
||||
if (!session->callbacks.unpack_extension_callback) {
|
||||
/* Silently ignore unknown frame type. */
|
||||
|
||||
busy = 1;
|
||||
|
@ -5193,6 +5301,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||
break;
|
||||
}
|
||||
|
||||
busy = 1;
|
||||
|
||||
iframe->state = NGHTTP2_IB_READ_EXTENSION_PAYLOAD;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!on_begin_frame_called) {
|
||||
switch (iframe->state) {
|
||||
case NGHTTP2_IB_IGN_HEADER_BLOCK:
|
||||
|
@ -5886,6 +6001,44 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||
break;
|
||||
case NGHTTP2_IB_IGN_ALL:
|
||||
return (ssize_t)inlen;
|
||||
case NGHTTP2_IB_READ_EXTENSION_PAYLOAD:
|
||||
DEBUGF(fprintf(stderr, "recv: [IB_READ_EXTENSION_PAYLOAD]\n"));
|
||||
|
||||
readlen = inbound_frame_payload_readlen(iframe, in, last);
|
||||
iframe->payloadleft -= readlen;
|
||||
in += readlen;
|
||||
|
||||
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", readlen,
|
||||
iframe->payloadleft));
|
||||
|
||||
if (readlen > 0) {
|
||||
rv = session_call_on_extension_chunk_recv_callback(
|
||||
session, in - readlen, readlen);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
busy = 1;
|
||||
|
||||
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iframe->payloadleft > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
rv = session_process_extension_frame(session);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
session_inbound_frame_reset(session);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!busy && in == last) {
|
||||
|
|
|
@ -102,7 +102,8 @@ typedef enum {
|
|||
NGHTTP2_IB_READ_PAD_DATA,
|
||||
NGHTTP2_IB_READ_DATA,
|
||||
NGHTTP2_IB_IGN_DATA,
|
||||
NGHTTP2_IB_IGN_ALL
|
||||
NGHTTP2_IB_IGN_ALL,
|
||||
NGHTTP2_IB_READ_EXTENSION_PAYLOAD
|
||||
} nghttp2_inbound_state;
|
||||
|
||||
#define NGHTTP2_INBOUND_NUM_IV 7
|
||||
|
|
|
@ -479,3 +479,40 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
|
|||
|
||||
return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv);
|
||||
}
|
||||
|
||||
int nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id, void *payload) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (type <= NGHTTP2_CONTINUATION) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!session->callbacks.pack_extension_callback) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_extension_free(&frame->ext);
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ const char *strsettingsid(int32_t id) {
|
|||
} // namespace
|
||||
|
||||
namespace {
|
||||
const char *strframetype(uint8_t type) {
|
||||
std::string strframetype(uint8_t type) {
|
||||
switch (type) {
|
||||
case NGHTTP2_DATA:
|
||||
return "DATA";
|
||||
|
@ -141,9 +141,13 @@ const char *strframetype(uint8_t type) {
|
|||
return "GOAWAY";
|
||||
case NGHTTP2_WINDOW_UPDATE:
|
||||
return "WINDOW_UPDATE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
std::string s = "UNKNOWN(0x";
|
||||
s += util::format_hex(&type, 1);
|
||||
s += ")";
|
||||
|
||||
return s;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -280,7 +284,7 @@ const char *frame_name_ansi_esc(print_type ptype) {
|
|||
namespace {
|
||||
void print_frame(print_type ptype, const nghttp2_frame *frame) {
|
||||
fprintf(outfile, "%s%s%s frame ", frame_name_ansi_esc(ptype),
|
||||
strframetype(frame->hd.type), ansi_escend());
|
||||
strframetype(frame->hd.type).c_str(), ansi_escend());
|
||||
print_frame_hd(frame->hd);
|
||||
if (frame->hd.flags) {
|
||||
print_frame_attr_indent();
|
||||
|
|
Loading…
Reference in New Issue