ORIGIN frame support
This commit is contained in:
parent
cc289972fc
commit
2a0cf7c8d8
|
@ -597,7 +597,12 @@ typedef enum {
|
|||
* The ALTSVC frame, which is defined in `RFC 7383
|
||||
* <https://tools.ietf.org/html/rfc7838#section-4>`_.
|
||||
*/
|
||||
NGHTTP2_ALTSVC = 0x0a
|
||||
NGHTTP2_ALTSVC = 0x0a,
|
||||
/**
|
||||
* The ORIGIN frame, whic is defined in `RFC XXXX
|
||||
* https://tools.ietf.org/html/draft-ietf-httpbis-origin-frame-03#section-2`_.
|
||||
*/
|
||||
NGHTTP2_ORIGIN = 0x0c
|
||||
} nghttp2_frame_type;
|
||||
|
||||
/**
|
||||
|
@ -4477,6 +4482,66 @@ NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session,
|
|||
const uint8_t *field_value,
|
||||
size_t field_value_len);
|
||||
|
||||
/**
|
||||
* @struct
|
||||
*
|
||||
* The payload of ORIGIN frame. ORIGIN frame is a non-critical
|
||||
* extension to HTTP/2. If this frame is received, and
|
||||
* `nghttp2_option_set_user_recv_extension_type()` is not set, and
|
||||
* `nghttp2_option_set_builtin_recv_extension_type()` is set for
|
||||
* :enum:`NGHTTP2_ORIGIN`, ``nghttp2_extension.payload`` will point to
|
||||
* this struct.
|
||||
*
|
||||
* It has the following members:
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* The pointer to an origin which the sender believes this connection is or
|
||||
* could be
|
||||
* authoritative for. This is not necessarily NULL-terminated.
|
||||
*/
|
||||
uint8_t *origin;
|
||||
/**
|
||||
* The length of the |origin|.
|
||||
*/
|
||||
size_t origin_len;
|
||||
} nghttp2_ext_origin;
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Submits ORIGIN frame.
|
||||
*
|
||||
* ORIGIN frame is a non-critical extension to HTTP/2, and defined in
|
||||
* `RFC XXX
|
||||
* <https://tools.ietf.org/html/draft-ietf-httpbis-origin-frame-03#section-2>`_.
|
||||
*
|
||||
* The |flags| is currently ignored and should be
|
||||
* :enum:`NGHTTP2_FLAG_NONE`.
|
||||
*
|
||||
* The |origin| points to the origin which the sender believes this connection
|
||||
* is or could be
|
||||
* authoritative for
|
||||
*
|
||||
* The ORIGIN frame is only usable from server side. If this function
|
||||
* is invoked with client side session, this function returns
|
||||
* :enum:`NGHTTP2_ERR_INVALID_STATE`.
|
||||
*
|
||||
* 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_STATE`
|
||||
* The function is called from client side session
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* The |origin_len| is larger than
|
||||
* 16382.
|
||||
*/
|
||||
NGHTTP2_EXTERN int nghttp2_submit_origin(nghttp2_session *session,
|
||||
uint8_t flags, const uint8_t *origin,
|
||||
size_t origin_len);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
|
|
@ -196,6 +196,26 @@ void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
|||
|
||||
void nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; }
|
||||
|
||||
void nghttp2_frame_origin_init(nghttp2_extension *frame, uint8_t *origin,
|
||||
size_t origin_len) {
|
||||
nghttp2_ext_origin *origin_frame;
|
||||
|
||||
/* Always send ORIGIN frame on stream 0 */
|
||||
nghttp2_frame_hd_init(&frame->hd, 2 + origin_len, NGHTTP2_ORIGIN,
|
||||
NGHTTP2_FLAG_NONE, 0);
|
||||
|
||||
origin_frame = frame->payload;
|
||||
origin_frame->origin = origin;
|
||||
origin_frame->origin_len = origin_len;
|
||||
}
|
||||
|
||||
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
|
||||
nghttp2_ext_origin *origin_frame;
|
||||
|
||||
origin_frame = frame->payload;
|
||||
nghttp2_mem_free(mem, origin_frame->origin);
|
||||
}
|
||||
|
||||
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
uint8_t *origin, size_t origin_len,
|
||||
uint8_t *field_value, size_t field_value_len) {
|
||||
|
|
|
@ -70,7 +70,10 @@
|
|||
#define NGHTTP2_MAX_PADLEN 256
|
||||
|
||||
/* Union of extension frame payload */
|
||||
typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload;
|
||||
typedef union {
|
||||
nghttp2_ext_altsvc altsvc;
|
||||
nghttp2_ext_origin origin;
|
||||
} nghttp2_ext_frame_payload;
|
||||
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
||||
|
||||
|
@ -487,6 +490,22 @@ void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
|||
*/
|
||||
void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes ORIGIN frame |frame| with given values. This function
|
||||
* assumes that frame->payload points to nghttp2_ext_origin object.
|
||||
* On success, this function takes ownership of
|
||||
* |origin|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_origin_init(nghttp2_extension *frame, uint8_t *origin,
|
||||
size_t origin_len);
|
||||
|
||||
/*
|
||||
* Frees up resources under |frame|. This function does not free
|
||||
* nghttp2_ext_origin object pointed by frame->payload. This function
|
||||
* only frees origin pointed by nghttp2_ext_origin.origin.
|
||||
*/
|
||||
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Returns the number of padding bytes after payload. The total
|
||||
* padding length is given in the |padlen|. The returned value does
|
||||
|
|
|
@ -86,6 +86,10 @@ void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
|
|||
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC;
|
||||
return;
|
||||
case NGHTTP2_ORIGIN:
|
||||
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -337,6 +337,12 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
|
|||
}
|
||||
nghttp2_frame_altsvc_free(&iframe->frame.ext, mem);
|
||||
break;
|
||||
case NGHTTP2_ORIGIN:
|
||||
if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN) == 0) {
|
||||
break;
|
||||
}
|
||||
nghttp2_frame_origin_free(&iframe->frame.ext, mem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5746,7 +5752,37 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||
|
||||
iframe->state = NGHTTP2_IB_READ_NBYTE;
|
||||
inbound_frame_set_mark(iframe, 2);
|
||||
case NGHTTP2_ORIGIN:
|
||||
if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN) ==
|
||||
0) {
|
||||
busy = 1;
|
||||
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUGF("recv: ORIGIN\n");
|
||||
|
||||
iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
|
||||
iframe->frame.ext.payload = &iframe->ext_frame_payload.origin;
|
||||
|
||||
if (session->server) {
|
||||
busy = 1;
|
||||
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
|
||||
break;
|
||||
}
|
||||
|
||||
if (iframe->payloadleft < 2) {
|
||||
busy = 1;
|
||||
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
busy = 1;
|
||||
|
||||
iframe->state = NGHTTP2_IB_READ_NBYTE;
|
||||
inbound_frame_set_mark(iframe, 2);
|
||||
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
busy = 1;
|
||||
|
|
|
@ -61,7 +61,8 @@ typedef enum {
|
|||
*/
|
||||
typedef enum {
|
||||
NGHTTP2_TYPEMASK_NONE = 0,
|
||||
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0
|
||||
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
|
||||
NGHTTP2_TYPEMASK_ORIGIN = 2 << 0
|
||||
} nghttp2_typemask;
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -486,6 +486,76 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
|
||||
const uint8_t *origin, size_t origin_len) {
|
||||
nghttp2_mem *mem;
|
||||
uint8_t *buf, *p;
|
||||
uint8_t *origin_copy;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_ext_origin *origin_frame;
|
||||
int rv;
|
||||
(void)flags;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (2 + origin_len > NGHTTP2_MAX_PAYLOADLEN) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
buf = nghttp2_mem_malloc(mem, origin_len + 2);
|
||||
if (buf == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
origin_copy = p;
|
||||
if (origin_len) {
|
||||
p = nghttp2_cpymem(p, origin, origin_len);
|
||||
}
|
||||
*p++ = '\0';
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail_item_malloc;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
item->aux_data.ext.builtin = 1;
|
||||
|
||||
origin_frame = &item->ext_frame_payload.origin;
|
||||
|
||||
frame = &item->frame;
|
||||
frame->ext.payload = origin_frame;
|
||||
//
|
||||
// nghttp2_frame_altsvc_init(&frame->ext, stream_id, origin_copy, origin_len,
|
||||
// field_value_copy, field_value_len);
|
||||
|
||||
nghttp2_frame_origin_init(&frame->ext, origin_copy, origin_len);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_altsvc_free(&frame->ext, mem);
|
||||
nghttp2_mem_free(mem, item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_item_malloc:
|
||||
free(buf);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *origin,
|
||||
size_t origin_len, const uint8_t *field_value,
|
||||
|
|
Loading…
Reference in New Issue