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
|
* The ALTSVC frame, which is defined in `RFC 7383
|
||||||
* <https://tools.ietf.org/html/rfc7838#section-4>`_.
|
* <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;
|
} nghttp2_frame_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4477,6 +4482,66 @@ NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session,
|
||||||
const uint8_t *field_value,
|
const uint8_t *field_value,
|
||||||
size_t field_value_len);
|
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
|
* @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_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,
|
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||||
uint8_t *origin, size_t origin_len,
|
uint8_t *origin, size_t origin_len,
|
||||||
uint8_t *field_value, size_t field_value_len) {
|
uint8_t *field_value, size_t field_value_len) {
|
||||||
|
|
|
@ -70,7 +70,10 @@
|
||||||
#define NGHTTP2_MAX_PADLEN 256
|
#define NGHTTP2_MAX_PADLEN 256
|
||||||
|
|
||||||
/* Union of extension frame payload */
|
/* 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);
|
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);
|
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
|
* Returns the number of padding bytes after payload. The total
|
||||||
* padding length is given in the |padlen|. The returned value does
|
* 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->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC;
|
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC;
|
||||||
return;
|
return;
|
||||||
|
case NGHTTP2_ORIGIN:
|
||||||
|
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||||
|
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,6 +337,12 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
|
||||||
}
|
}
|
||||||
nghttp2_frame_altsvc_free(&iframe->frame.ext, mem);
|
nghttp2_frame_altsvc_free(&iframe->frame.ext, mem);
|
||||||
break;
|
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;
|
iframe->state = NGHTTP2_IB_READ_NBYTE;
|
||||||
inbound_frame_set_mark(iframe, 2);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
busy = 1;
|
busy = 1;
|
||||||
|
|
|
@ -61,7 +61,8 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NGHTTP2_TYPEMASK_NONE = 0,
|
NGHTTP2_TYPEMASK_NONE = 0,
|
||||||
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0
|
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
|
||||||
|
NGHTTP2_TYPEMASK_ORIGIN = 2 << 0
|
||||||
} nghttp2_typemask;
|
} nghttp2_typemask;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -486,6 +486,76 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
||||||
return 0;
|
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,
|
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id, const uint8_t *origin,
|
int32_t stream_id, const uint8_t *origin,
|
||||||
size_t origin_len, const uint8_t *field_value,
|
size_t origin_len, const uint8_t *field_value,
|
||||||
|
|
Loading…
Reference in New Issue