Implement ALTSVC frame
This commit is contained in:
parent
b143039b60
commit
f785e56dba
|
@ -409,7 +409,11 @@ typedef enum {
|
||||||
/**
|
/**
|
||||||
* The CONTINUATION frame.
|
* The CONTINUATION frame.
|
||||||
*/
|
*/
|
||||||
NGHTTP2_CONTINUATION = 9
|
NGHTTP2_CONTINUATION = 9,
|
||||||
|
/**
|
||||||
|
* The ALTSVC frame.
|
||||||
|
*/
|
||||||
|
NGHTTP2_ALTSVC = 10
|
||||||
} nghttp2_frame_type;
|
} nghttp2_frame_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -950,6 +954,50 @@ typedef struct {
|
||||||
int32_t window_size_increment;
|
int32_t window_size_increment;
|
||||||
} nghttp2_window_update;
|
} nghttp2_window_update;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct
|
||||||
|
*
|
||||||
|
* The ALTSVC frame. It has following members:
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* The frame header.
|
||||||
|
*/
|
||||||
|
nghttp2_frame_hd hd;
|
||||||
|
/**
|
||||||
|
* Protocol ID
|
||||||
|
*/
|
||||||
|
uint8_t *protocol_id;
|
||||||
|
/**
|
||||||
|
* Host
|
||||||
|
*/
|
||||||
|
uint8_t *host;
|
||||||
|
/**
|
||||||
|
* Origin
|
||||||
|
*/
|
||||||
|
uint8_t *origin;
|
||||||
|
/**
|
||||||
|
* The length of |protocol_id|
|
||||||
|
*/
|
||||||
|
size_t protocol_id_len;
|
||||||
|
/**
|
||||||
|
* The length of |host|
|
||||||
|
*/
|
||||||
|
size_t host_len;
|
||||||
|
/**
|
||||||
|
* The length of |origin|
|
||||||
|
*/
|
||||||
|
size_t origin_len;
|
||||||
|
/**
|
||||||
|
* Max-Age
|
||||||
|
*/
|
||||||
|
uint32_t max_age;
|
||||||
|
/**
|
||||||
|
* Port
|
||||||
|
*/
|
||||||
|
uint16_t port;
|
||||||
|
} nghttp2_altsvc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @union
|
* @union
|
||||||
*
|
*
|
||||||
|
@ -998,6 +1046,10 @@ typedef union {
|
||||||
* The WINDOW_UPDATE frame.
|
* The WINDOW_UPDATE frame.
|
||||||
*/
|
*/
|
||||||
nghttp2_window_update window_update;
|
nghttp2_window_update window_update;
|
||||||
|
/**
|
||||||
|
* The ALTSVC frame.
|
||||||
|
*/
|
||||||
|
nghttp2_altsvc altsvc;
|
||||||
} nghttp2_frame;
|
} nghttp2_frame;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2442,6 +2494,40 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
int32_t window_size_increment);
|
int32_t window_size_increment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Submits ALTSVC frame with given parameters.
|
||||||
|
*
|
||||||
|
* The |flags| is currently ignored and should be
|
||||||
|
* :enum:`NGHTTP2_FLAG_NONE`.
|
||||||
|
*
|
||||||
|
* Only the server can send the ALTSVC frame. If |session| is
|
||||||
|
* initialized as client, this function fails and returns
|
||||||
|
* NGHTTP2_ERR_INVALID_STATE.
|
||||||
|
*
|
||||||
|
* If the |protocol_id_len| is 0, the |protocol_id| could be ``NULL``.
|
||||||
|
*
|
||||||
|
* If the |host_len| is 0, the |host| could be ``NULL``.
|
||||||
|
*
|
||||||
|
* If the |origin_len| is 0, the |origin| could be ``NULL``.
|
||||||
|
*
|
||||||
|
* 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 invoked with |session| which was initialized as
|
||||||
|
* client.
|
||||||
|
*/
|
||||||
|
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||||
|
int32_t stream_id,
|
||||||
|
uint32_t max_age, uint16_t port,
|
||||||
|
const uint8_t *protocol_id, size_t protocol_id_len,
|
||||||
|
const uint8_t *host, size_t host_len,
|
||||||
|
const uint8_t *origin, size_t origin_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
|
|
|
@ -194,6 +194,37 @@ void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
||||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame)
|
void nghttp2_frame_window_update_free(nghttp2_window_update *frame)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void nghttp2_frame_altsvc_init(nghttp2_altsvc *frame, int32_t stream_id,
|
||||||
|
uint32_t max_age,
|
||||||
|
uint16_t port,
|
||||||
|
uint8_t *protocol_id,
|
||||||
|
size_t protocol_id_len,
|
||||||
|
uint8_t *host, size_t host_len,
|
||||||
|
uint8_t *origin, size_t origin_len)
|
||||||
|
{
|
||||||
|
size_t payloadlen;
|
||||||
|
|
||||||
|
/* 8 for Max-Age, Port, Reserved and PID_LEN. 1 for HOST_LEN. */
|
||||||
|
payloadlen = 8 + protocol_id_len + 1 + host_len + origin_len;
|
||||||
|
|
||||||
|
nghttp2_frame_set_hd(&frame->hd, payloadlen, NGHTTP2_ALTSVC,
|
||||||
|
NGHTTP2_FLAG_NONE, stream_id);
|
||||||
|
|
||||||
|
frame->max_age = max_age;
|
||||||
|
frame->port = port;
|
||||||
|
frame->protocol_id = protocol_id;
|
||||||
|
frame->protocol_id_len = protocol_id_len;
|
||||||
|
frame->host = host;
|
||||||
|
frame->host_len = host_len;
|
||||||
|
frame->origin = origin;
|
||||||
|
frame->origin_len = origin_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_frame_altsvc_free(nghttp2_altsvc *frame)
|
||||||
|
{
|
||||||
|
free(frame->protocol_id);
|
||||||
|
}
|
||||||
|
|
||||||
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata)
|
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata)
|
||||||
{
|
{
|
||||||
frame->hd = pdata->hd;
|
frame->hd = pdata->hd;
|
||||||
|
@ -700,6 +731,101 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||||
NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
|
NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_altsvc *frame)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
nghttp2_buf *buf;
|
||||||
|
|
||||||
|
assert(bufs->head == bufs->cur);
|
||||||
|
|
||||||
|
buf = &bufs->head->buf;
|
||||||
|
|
||||||
|
buf->pos -= NGHTTP2_FRAME_HDLEN;
|
||||||
|
|
||||||
|
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
|
||||||
|
|
||||||
|
nghttp2_put_uint32be(buf->last, frame->max_age);
|
||||||
|
buf->last += 4;
|
||||||
|
|
||||||
|
nghttp2_put_uint16be(buf->last, frame->port);
|
||||||
|
buf->last += 2;
|
||||||
|
|
||||||
|
/* Reserved */
|
||||||
|
buf->last[0] = 0;
|
||||||
|
++buf->last;
|
||||||
|
|
||||||
|
buf->last[0] = frame->protocol_id_len;
|
||||||
|
++buf->last;
|
||||||
|
|
||||||
|
rv = nghttp2_bufs_add(bufs, frame->protocol_id, frame->protocol_id_len);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp2_bufs_addb(bufs, frame->host_len);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp2_bufs_add(bufs, frame->host, frame->host_len);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp2_bufs_add(bufs, frame->origin, frame->origin_len);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nghttp2_frame_unpack_altsvc_payload(nghttp2_altsvc *frame,
|
||||||
|
const uint8_t *payload,
|
||||||
|
size_t payloadlen,
|
||||||
|
uint8_t *var_gift_payload,
|
||||||
|
size_t var_gift_payloadlen)
|
||||||
|
{
|
||||||
|
nghttp2_buf buf;
|
||||||
|
|
||||||
|
frame->max_age = nghttp2_get_uint32(payload);
|
||||||
|
payload += 4;
|
||||||
|
|
||||||
|
frame->port = nghttp2_get_uint16(payload);
|
||||||
|
payload += 2;
|
||||||
|
|
||||||
|
/* Skip Reserved */
|
||||||
|
++payload;
|
||||||
|
|
||||||
|
frame->protocol_id_len = *payload;
|
||||||
|
|
||||||
|
nghttp2_buf_wrap_init(&buf, var_gift_payload, var_gift_payloadlen);
|
||||||
|
buf.last += var_gift_payloadlen;
|
||||||
|
|
||||||
|
/* 1 for HOST_LEN */
|
||||||
|
if(nghttp2_buf_len(&buf) < 1 + (ssize_t)frame->protocol_id_len) {
|
||||||
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->protocol_id = buf.pos;
|
||||||
|
buf.pos += frame->protocol_id_len;
|
||||||
|
|
||||||
|
frame->host_len = *buf.pos;
|
||||||
|
++buf.pos;
|
||||||
|
|
||||||
|
if(nghttp2_buf_len(&buf) < (ssize_t)frame->host_len) {
|
||||||
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->host = buf.pos;
|
||||||
|
buf.pos += frame->host_len;
|
||||||
|
|
||||||
|
frame->origin = buf.pos;
|
||||||
|
frame->origin_len = nghttp2_buf_len(&buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||||
size_t niv)
|
size_t niv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -407,6 +407,44 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
size_t payloadlen);
|
size_t payloadlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs ALTSVC frame |frame| in wire format and store it in |bufs|.
|
||||||
|
* This function expands |bufs| as necessary to store frame.
|
||||||
|
*
|
||||||
|
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||||
|
* before calling this function.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_BUFFER_ERROR
|
||||||
|
* Out of buffer space.
|
||||||
|
*/
|
||||||
|
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_altsvc *frame);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks ALTSVC frame byte sequence into |frame|.
|
||||||
|
* The |payload| of length |payloadlen| contains first 8 bytes of
|
||||||
|
* payload. The |var_gift_payload| of length |var_gift_payloadlen|
|
||||||
|
* contains remaining payload and its buffer is gifted to the function
|
||||||
|
* and then |frame|. The |var_gift_payloadlen| must be freed by
|
||||||
|
* nghttp2_frame_altsvc_free().
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||||
|
* The |var_gift_payload| does not contain required data.
|
||||||
|
*/
|
||||||
|
int nghttp2_frame_unpack_altsvc_payload(nghttp2_altsvc *frame,
|
||||||
|
const uint8_t *payload,
|
||||||
|
size_t payloadlen,
|
||||||
|
uint8_t *var_gift_payload,
|
||||||
|
size_t var_gift_payloadlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes HEADERS frame |frame| with given values. |frame| takes
|
* Initializes HEADERS frame |frame| with given values. |frame| takes
|
||||||
* ownership of |nva|, so caller must not free it. If |stream_id| is
|
* ownership of |nva|, so caller must not free it. If |stream_id| is
|
||||||
|
@ -481,6 +519,22 @@ void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
||||||
|
|
||||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
|
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
|
||||||
|
|
||||||
|
/* protocol_id, host and origin must be allocated to the one chunk of
|
||||||
|
memory region and protocol_id must point to it. We only free
|
||||||
|
protocol_id. This means that |protocol_id| is not NULL even if
|
||||||
|
|protocol_id_len| == 0 and |host_len| + |origin_len| > 0. If
|
||||||
|
|protocol_id_len|, |host_len| and |origin_len| are all zero,
|
||||||
|
|protocol_id| can be NULL. */
|
||||||
|
void nghttp2_frame_altsvc_init(nghttp2_altsvc *frame, int32_t stream_id,
|
||||||
|
uint32_t max_age,
|
||||||
|
uint16_t port,
|
||||||
|
uint8_t *protocol_id,
|
||||||
|
size_t protocol_id_len,
|
||||||
|
uint8_t *host, size_t host_len,
|
||||||
|
uint8_t *origin, size_t origin_len);
|
||||||
|
|
||||||
|
void nghttp2_frame_altsvc_free(nghttp2_altsvc *frame);
|
||||||
|
|
||||||
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
|
void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -62,6 +62,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item)
|
||||||
case NGHTTP2_WINDOW_UPDATE:
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
nghttp2_frame_window_update_free(&frame->window_update);
|
nghttp2_frame_window_update_free(&frame->window_update);
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
nghttp2_frame_altsvc_free(&frame->altsvc);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if(item->frame_cat == NGHTTP2_CAT_DATA) {
|
} else if(item->frame_cat == NGHTTP2_CAT_DATA) {
|
||||||
nghttp2_private_data *data_frame;
|
nghttp2_private_data *data_frame;
|
||||||
|
|
|
@ -199,6 +199,9 @@ static void nghttp2_inbound_frame_reset(nghttp2_session *session)
|
||||||
case NGHTTP2_WINDOW_UPDATE:
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
nghttp2_frame_window_update_free(&iframe->frame.window_update);
|
nghttp2_frame_window_update_free(&iframe->frame.window_update);
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
nghttp2_frame_altsvc_free(&iframe->frame.altsvc);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
memset(&iframe->frame, 0, sizeof(nghttp2_frame));
|
memset(&iframe->frame, 0, sizeof(nghttp2_frame));
|
||||||
|
|
||||||
|
@ -662,6 +665,8 @@ int nghttp2_session_add_frame(nghttp2_session *session,
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_WINDOW_UPDATE:
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frame->hd.type == NGHTTP2_HEADERS &&
|
if(frame->hd.type == NGHTTP2_HEADERS &&
|
||||||
|
@ -1665,6 +1670,15 @@ static int nghttp2_session_prep_frame(nghttp2_session *session,
|
||||||
if(framebuflen < 0) {
|
if(framebuflen < 0) {
|
||||||
return framebuflen;
|
return framebuflen;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
framebuflen = nghttp2_frame_pack_altsvc(&session->aob.framebufs,
|
||||||
|
&frame->altsvc);
|
||||||
|
|
||||||
|
if(framebuflen < 0) {
|
||||||
|
return framebuflen;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
@ -2027,6 +2041,9 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
|
||||||
case NGHTTP2_WINDOW_UPDATE:
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
/* nothing to do */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
nghttp2_active_outbound_item_reset(&session->aob);
|
nghttp2_active_outbound_item_reset(&session->aob);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3518,6 +3535,42 @@ static int session_process_goaway_frame(nghttp2_session *session)
|
||||||
return nghttp2_session_on_goaway_received(session, frame);
|
return nghttp2_session_on_goaway_received(session, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_session_on_altsvc_received(nghttp2_session *session,
|
||||||
|
nghttp2_frame *frame)
|
||||||
|
{
|
||||||
|
/* ALTSVC is exptected to be received by client only. We have
|
||||||
|
already rejected ALTSVC if it is received by server. */
|
||||||
|
if(frame->hd.stream_id != 0 &&
|
||||||
|
!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
|
||||||
|
return nghttp2_session_handle_invalid_connection(session, frame,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nghttp2_session_call_on_frame_received(session, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int session_process_altsvc_frame(nghttp2_session *session)
|
||||||
|
{
|
||||||
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv = nghttp2_frame_unpack_altsvc_payload(&frame->altsvc,
|
||||||
|
iframe->sbuf.pos,
|
||||||
|
nghttp2_buf_len(&iframe->sbuf),
|
||||||
|
iframe->lbuf.pos,
|
||||||
|
nghttp2_buf_len(&iframe->lbuf));
|
||||||
|
|
||||||
|
if(rv != 0) {
|
||||||
|
return nghttp2_session_handle_invalid_connection(session, frame,
|
||||||
|
NGHTTP2_FRAME_SIZE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0);
|
||||||
|
|
||||||
|
return nghttp2_session_on_altsvc_received(session, frame);
|
||||||
|
}
|
||||||
|
|
||||||
static int nghttp2_push_back_deferred_data_func(nghttp2_map_entry *entry,
|
static int nghttp2_push_back_deferred_data_func(nghttp2_map_entry *entry,
|
||||||
void *ptr)
|
void *ptr)
|
||||||
{
|
{
|
||||||
|
@ -4320,6 +4373,37 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
iframe->state = NGHTTP2_IB_READ_NBYTE;
|
iframe->state = NGHTTP2_IB_READ_NBYTE;
|
||||||
inbound_frame_set_mark(iframe, 8);
|
inbound_frame_set_mark(iframe, 8);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
DEBUGF(fprintf(stderr, "recv: ALTSVC\n"));
|
||||||
|
|
||||||
|
iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
|
||||||
|
|
||||||
|
if(session->server) {
|
||||||
|
rv = nghttp2_session_terminate_session(session,
|
||||||
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
busy = 1;
|
||||||
|
|
||||||
|
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iframe->payloadleft < 9) {
|
||||||
|
busy = 1;
|
||||||
|
|
||||||
|
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe->state = NGHTTP2_IB_READ_NBYTE;
|
||||||
|
inbound_frame_set_mark(iframe, 8);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUGF(fprintf(stderr, "recv: unknown frame\n"));
|
DEBUGF(fprintf(stderr, "recv: unknown frame\n"));
|
||||||
|
@ -4503,6 +4587,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
nghttp2_inbound_frame_reset(session);
|
nghttp2_inbound_frame_reset(session);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_ALTSVC: {
|
||||||
|
size_t varlen;
|
||||||
|
|
||||||
|
varlen = iframe->frame.hd.length - 8;
|
||||||
|
|
||||||
|
iframe->raw_lbuf = malloc(varlen);
|
||||||
|
|
||||||
|
if(iframe->raw_lbuf == NULL) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, varlen);
|
||||||
|
|
||||||
|
busy = 1;
|
||||||
|
|
||||||
|
iframe->state = NGHTTP2_IB_READ_ALTSVC;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
/* This is unknown frame */
|
/* This is unknown frame */
|
||||||
nghttp2_inbound_frame_reset(session);
|
nghttp2_inbound_frame_reset(session);
|
||||||
|
@ -4710,7 +4813,14 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_IB_READ_GOAWAY_DEBUG:
|
case NGHTTP2_IB_READ_GOAWAY_DEBUG:
|
||||||
DEBUGF(fprintf(stderr, "recv: [IB_READ_GOAWAY_DEBUG]\n"));
|
case NGHTTP2_IB_READ_ALTSVC:
|
||||||
|
#ifdef DEBUGBUILD
|
||||||
|
if(iframe->state == NGHTTP2_IB_READ_GOAWAY_DEBUG) {
|
||||||
|
fprintf(stderr, "recv: [IB_READ_GOAWAY_DEBUG]\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "recv: [IB_READ_ALTSVC]\n");
|
||||||
|
}
|
||||||
|
#endif /* DEBUGBUILD */
|
||||||
|
|
||||||
readlen = inbound_frame_payload_readlen(iframe, in, last);
|
readlen = inbound_frame_payload_readlen(iframe, in, last);
|
||||||
|
|
||||||
|
@ -4728,7 +4838,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = session_process_goaway_frame(session);
|
if(iframe->state == NGHTTP2_IB_READ_GOAWAY_DEBUG) {
|
||||||
|
rv = session_process_goaway_frame(session);
|
||||||
|
} else {
|
||||||
|
rv = session_process_altsvc_frame(session);
|
||||||
|
}
|
||||||
|
|
||||||
if(nghttp2_is_fatal(rv)) {
|
if(nghttp2_is_fatal(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
@ -73,6 +73,7 @@ typedef enum {
|
||||||
NGHTTP2_IB_FRAME_SIZE_ERROR,
|
NGHTTP2_IB_FRAME_SIZE_ERROR,
|
||||||
NGHTTP2_IB_READ_SETTINGS,
|
NGHTTP2_IB_READ_SETTINGS,
|
||||||
NGHTTP2_IB_READ_GOAWAY_DEBUG,
|
NGHTTP2_IB_READ_GOAWAY_DEBUG,
|
||||||
|
NGHTTP2_IB_READ_ALTSVC,
|
||||||
NGHTTP2_IB_EXPECT_CONTINUATION,
|
NGHTTP2_IB_EXPECT_CONTINUATION,
|
||||||
NGHTTP2_IB_IGN_CONTINUATION,
|
NGHTTP2_IB_IGN_CONTINUATION,
|
||||||
NGHTTP2_IB_READ_PAD_CONTINUATION,
|
NGHTTP2_IB_READ_PAD_CONTINUATION,
|
||||||
|
@ -433,6 +434,11 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_IGN_HEADER_BLOCK
|
||||||
|
* Frame was rejected and header block must be decoded but
|
||||||
|
* result must be ignored.
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The read_callback failed
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_headers_received(nghttp2_session *session,
|
int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame,
|
nghttp2_frame *frame,
|
||||||
|
@ -448,6 +454,8 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The read_callback failed
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_priority_received(nghttp2_session *session,
|
int nghttp2_session_on_priority_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
@ -459,7 +467,10 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
|
||||||
* This function returns 0 if it succeeds, or one the following
|
* This function returns 0 if it succeeds, or one the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
*
|
*
|
||||||
* TBD
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The read_callback failed
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
@ -475,8 +486,6 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory
|
* Out of memory
|
||||||
* NGHTTP2_ERR_PAUSE
|
|
||||||
* Callback function returns NGHTTP2_ERR_PAUSE
|
|
||||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
* The read_callback failed
|
* The read_callback failed
|
||||||
*/
|
*/
|
||||||
|
@ -493,6 +502,11 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_IGN_HEADER_BLOCK
|
||||||
|
* Frame was rejected and header block must be decoded but
|
||||||
|
* result must be ignored.
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The read_callback failed
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
@ -506,6 +520,8 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The callback function failed.
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_ping_received(nghttp2_session *session,
|
int nghttp2_session_on_ping_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
@ -514,7 +530,13 @@ int nghttp2_session_on_ping_received(nghttp2_session *session,
|
||||||
* Called when GOAWAY is received, assuming |frame| is properly
|
* Called when GOAWAY is received, assuming |frame| is properly
|
||||||
* initialized.
|
* initialized.
|
||||||
*
|
*
|
||||||
* This function returns 0 and never fail.
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The callback function failed.
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_goaway_received(nghttp2_session *session,
|
int nghttp2_session_on_goaway_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
@ -528,10 +550,27 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session,
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory.
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The callback function failed.
|
||||||
*/
|
*/
|
||||||
int nghttp2_session_on_window_update_received(nghttp2_session *session,
|
int nghttp2_session_on_window_update_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when ALTSVC is received, assuming |frame| is properly
|
||||||
|
* initialized.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The callback function failed.
|
||||||
|
*/
|
||||||
|
int nghttp2_session_on_altsvc_received(nghttp2_session *session,
|
||||||
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when DATA is received, assuming |frame| is properly
|
* Called when DATA is received, assuming |frame| is properly
|
||||||
* initialized.
|
* initialized.
|
||||||
|
|
|
@ -316,6 +316,79 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||||
|
int32_t stream_id,
|
||||||
|
uint32_t max_age, uint16_t port,
|
||||||
|
const uint8_t *protocol_id, size_t protocol_id_len,
|
||||||
|
const uint8_t *host, size_t host_len,
|
||||||
|
const uint8_t *origin, size_t origin_len)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
size_t varlen;
|
||||||
|
uint8_t *var, *varp;
|
||||||
|
nghttp2_frame *frame;
|
||||||
|
uint8_t *copy_protocol_id, *copy_host, *copy_origin;
|
||||||
|
|
||||||
|
if(!session->server) {
|
||||||
|
return NGHTTP2_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
varlen = protocol_id_len + host_len + origin_len;
|
||||||
|
|
||||||
|
if(varlen == 0) {
|
||||||
|
var = NULL;
|
||||||
|
copy_protocol_id = NULL;
|
||||||
|
copy_host = NULL;
|
||||||
|
copy_origin = NULL;
|
||||||
|
} else {
|
||||||
|
var = malloc(varlen);
|
||||||
|
|
||||||
|
if(var == NULL) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
varp = var;
|
||||||
|
|
||||||
|
memcpy(varp, protocol_id, protocol_id_len);
|
||||||
|
|
||||||
|
copy_protocol_id = varp;
|
||||||
|
varp += protocol_id_len;
|
||||||
|
|
||||||
|
memcpy(varp, host, host_len);
|
||||||
|
|
||||||
|
copy_host = varp;
|
||||||
|
varp += host_len;
|
||||||
|
|
||||||
|
memcpy(varp, origin, origin_len);
|
||||||
|
|
||||||
|
copy_origin = varp;
|
||||||
|
varp += origin_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = malloc(sizeof(nghttp2_frame));
|
||||||
|
|
||||||
|
if(frame == NULL) {
|
||||||
|
free(var);
|
||||||
|
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_frame_altsvc_init(&frame->altsvc, stream_id, max_age, port,
|
||||||
|
copy_protocol_id, protocol_id_len,
|
||||||
|
copy_host, host_len, copy_origin, origin_len);
|
||||||
|
|
||||||
|
rv = nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL);
|
||||||
|
|
||||||
|
if(rv != 0) {
|
||||||
|
nghttp2_frame_altsvc_free(&frame->altsvc);
|
||||||
|
free(frame);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
||||||
const nghttp2_data_provider *data_prd)
|
const nghttp2_data_provider *data_prd)
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,6 +88,8 @@ int main(int argc, char* argv[])
|
||||||
test_nghttp2_session_recv_headers_with_priority) ||
|
test_nghttp2_session_recv_headers_with_priority) ||
|
||||||
!CU_add_test(pSuite, "session_recv_premature_headers",
|
!CU_add_test(pSuite, "session_recv_premature_headers",
|
||||||
test_nghttp2_session_recv_premature_headers) ||
|
test_nghttp2_session_recv_premature_headers) ||
|
||||||
|
!CU_add_test(pSuite, "session_recv_altsvc",
|
||||||
|
test_nghttp2_session_recv_altsvc) ||
|
||||||
!CU_add_test(pSuite, "session_continue", test_nghttp2_session_continue) ||
|
!CU_add_test(pSuite, "session_continue", test_nghttp2_session_continue) ||
|
||||||
!CU_add_test(pSuite, "session_add_frame",
|
!CU_add_test(pSuite, "session_add_frame",
|
||||||
test_nghttp2_session_add_frame) ||
|
test_nghttp2_session_add_frame) ||
|
||||||
|
@ -161,6 +163,7 @@ int main(int argc, char* argv[])
|
||||||
test_nghttp2_submit_window_update) ||
|
test_nghttp2_submit_window_update) ||
|
||||||
!CU_add_test(pSuite, "submit_window_update_local_window_size",
|
!CU_add_test(pSuite, "submit_window_update_local_window_size",
|
||||||
test_nghttp2_submit_window_update_local_window_size) ||
|
test_nghttp2_submit_window_update_local_window_size) ||
|
||||||
|
!CU_add_test(pSuite, "submit_altsvc", test_nghttp2_submit_altsvc) ||
|
||||||
!CU_add_test(pSuite, "submit_invalid_nv",
|
!CU_add_test(pSuite, "submit_invalid_nv",
|
||||||
test_nghttp2_submit_invalid_nv) ||
|
test_nghttp2_submit_invalid_nv) ||
|
||||||
!CU_add_test(pSuite, "session_open_stream",
|
!CU_add_test(pSuite, "session_open_stream",
|
||||||
|
@ -242,6 +245,8 @@ int main(int argc, char* argv[])
|
||||||
test_nghttp2_frame_pack_goaway) ||
|
test_nghttp2_frame_pack_goaway) ||
|
||||||
!CU_add_test(pSuite, "frame_pack_window_update",
|
!CU_add_test(pSuite, "frame_pack_window_update",
|
||||||
test_nghttp2_frame_pack_window_update) ||
|
test_nghttp2_frame_pack_window_update) ||
|
||||||
|
!CU_add_test(pSuite, "frame_pack_altsvc",
|
||||||
|
test_nghttp2_frame_pack_altsvc) ||
|
||||||
!CU_add_test(pSuite, "nv_array_copy", test_nghttp2_nv_array_copy) ||
|
!CU_add_test(pSuite, "nv_array_copy", test_nghttp2_nv_array_copy) ||
|
||||||
!CU_add_test(pSuite, "iv_check", test_nghttp2_iv_check) ||
|
!CU_add_test(pSuite, "iv_check", test_nghttp2_iv_check) ||
|
||||||
!CU_add_test(pSuite, "hd_deflate", test_nghttp2_hd_deflate) ||
|
!CU_add_test(pSuite, "hd_deflate", test_nghttp2_hd_deflate) ||
|
||||||
|
|
|
@ -490,6 +490,133 @@ void test_nghttp2_frame_pack_window_update(void)
|
||||||
nghttp2_frame_window_update_free(&frame);
|
nghttp2_frame_window_update_free(&frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_frame_pack_altsvc(void)
|
||||||
|
{
|
||||||
|
nghttp2_altsvc frame, oframe;
|
||||||
|
nghttp2_bufs bufs;
|
||||||
|
nghttp2_buf *buf;
|
||||||
|
size_t protocol_id_len, host_len, origin_len;
|
||||||
|
uint8_t *protocol_id, *host, *origin;
|
||||||
|
uint8_t *data;
|
||||||
|
size_t datalen;
|
||||||
|
int rv;
|
||||||
|
size_t payloadlen;
|
||||||
|
|
||||||
|
protocol_id_len = strlen("h2");
|
||||||
|
host_len = strlen("h2.example.org");
|
||||||
|
origin_len = strlen("www.example.org");
|
||||||
|
|
||||||
|
datalen = protocol_id_len + host_len + origin_len;
|
||||||
|
data = malloc(datalen);
|
||||||
|
|
||||||
|
memcpy(data, "h2", protocol_id_len);
|
||||||
|
protocol_id = data;
|
||||||
|
|
||||||
|
memcpy(data + protocol_id_len, "h2.example.org", host_len);
|
||||||
|
host = data + protocol_id_len;
|
||||||
|
|
||||||
|
memcpy(data + protocol_id_len + host_len,
|
||||||
|
"http://www.example.org", origin_len);
|
||||||
|
origin = data + protocol_id_len + host_len;
|
||||||
|
|
||||||
|
frame_pack_bufs_init(&bufs);
|
||||||
|
|
||||||
|
nghttp2_frame_altsvc_init(&frame, 1000000007, 1u << 31, 4000,
|
||||||
|
protocol_id, protocol_id_len,
|
||||||
|
host, host_len, origin, origin_len);
|
||||||
|
|
||||||
|
rv = nghttp2_frame_pack_altsvc(&bufs, &frame);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
|
||||||
|
/* 1 for HOST_LEN */
|
||||||
|
CU_ASSERT((ssize_t)(NGHTTP2_FRAME_HDLEN + 8 + 1 + datalen) ==
|
||||||
|
nghttp2_bufs_len(&bufs));
|
||||||
|
|
||||||
|
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs));
|
||||||
|
|
||||||
|
check_frame_header(8 + 1 + datalen, NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE,
|
||||||
|
1000000007, &oframe.hd);
|
||||||
|
CU_ASSERT(1u << 31 == oframe.max_age);
|
||||||
|
CU_ASSERT(4000 == oframe.port);
|
||||||
|
|
||||||
|
CU_ASSERT(protocol_id_len == oframe.protocol_id_len);
|
||||||
|
CU_ASSERT(memcmp(protocol_id, oframe.protocol_id, protocol_id_len) == 0);
|
||||||
|
|
||||||
|
CU_ASSERT(host_len == oframe.host_len);
|
||||||
|
CU_ASSERT(memcmp(host, oframe.host, host_len) == 0);
|
||||||
|
|
||||||
|
CU_ASSERT(origin_len == oframe.origin_len);
|
||||||
|
CU_ASSERT(memcmp(origin, oframe.origin, origin_len) == 0);
|
||||||
|
|
||||||
|
nghttp2_frame_altsvc_free(&oframe);
|
||||||
|
nghttp2_frame_altsvc_free(&frame);
|
||||||
|
|
||||||
|
memset(&oframe, 0, sizeof(oframe));
|
||||||
|
|
||||||
|
buf = &bufs.head->buf;
|
||||||
|
|
||||||
|
CU_ASSERT(buf->pos - buf->begin == 2);
|
||||||
|
|
||||||
|
/* Check no origin case */
|
||||||
|
|
||||||
|
payloadlen = 8 + protocol_id_len + 1 + host_len;
|
||||||
|
nghttp2_put_uint16be(buf->pos, payloadlen);
|
||||||
|
|
||||||
|
CU_ASSERT(0 ==
|
||||||
|
nghttp2_frame_unpack_altsvc_payload
|
||||||
|
(&oframe,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN,
|
||||||
|
8,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN + 8,
|
||||||
|
payloadlen - 8));
|
||||||
|
|
||||||
|
CU_ASSERT(host_len == oframe.host_len);
|
||||||
|
CU_ASSERT(0 == oframe.origin_len);
|
||||||
|
|
||||||
|
/* Check insufficient payload length for host */
|
||||||
|
payloadlen = 8 + protocol_id_len + 1 + host_len - 1;
|
||||||
|
nghttp2_put_uint16be(buf->pos, payloadlen);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_FRAME_SIZE_ERROR ==
|
||||||
|
nghttp2_frame_unpack_altsvc_payload
|
||||||
|
(&oframe,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN,
|
||||||
|
8,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN + 8,
|
||||||
|
payloadlen - 8));
|
||||||
|
|
||||||
|
/* Check no host case */
|
||||||
|
payloadlen = 8 + protocol_id_len + 1;
|
||||||
|
nghttp2_put_uint16be(buf->pos, payloadlen);
|
||||||
|
buf->pos[NGHTTP2_FRAME_HDLEN + 8 + protocol_id_len] = 0;
|
||||||
|
|
||||||
|
CU_ASSERT(0 ==
|
||||||
|
nghttp2_frame_unpack_altsvc_payload
|
||||||
|
(&oframe,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN,
|
||||||
|
8,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN + 8,
|
||||||
|
payloadlen - 8));
|
||||||
|
|
||||||
|
CU_ASSERT(0 == oframe.host_len);
|
||||||
|
CU_ASSERT(0 == oframe.origin_len);
|
||||||
|
|
||||||
|
/* Check missing HOST_LEN */
|
||||||
|
payloadlen = 8 + protocol_id_len;
|
||||||
|
nghttp2_put_uint16be(buf->pos, payloadlen);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_FRAME_SIZE_ERROR ==
|
||||||
|
nghttp2_frame_unpack_altsvc_payload
|
||||||
|
(&oframe,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN,
|
||||||
|
8,
|
||||||
|
buf->pos + NGHTTP2_FRAME_HDLEN + 8,
|
||||||
|
payloadlen - 8));
|
||||||
|
|
||||||
|
nghttp2_bufs_free(&bufs);
|
||||||
|
}
|
||||||
|
|
||||||
void test_nghttp2_nv_array_copy(void)
|
void test_nghttp2_nv_array_copy(void)
|
||||||
{
|
{
|
||||||
nghttp2_nv *nva;
|
nghttp2_nv *nva;
|
||||||
|
|
|
@ -34,6 +34,7 @@ void test_nghttp2_frame_pack_push_promise(void);
|
||||||
void test_nghttp2_frame_pack_ping(void);
|
void test_nghttp2_frame_pack_ping(void);
|
||||||
void test_nghttp2_frame_pack_goaway(void);
|
void test_nghttp2_frame_pack_goaway(void);
|
||||||
void test_nghttp2_frame_pack_window_update(void);
|
void test_nghttp2_frame_pack_window_update(void);
|
||||||
|
void test_nghttp2_frame_pack_altsvc(void);
|
||||||
void test_nghttp2_nv_array_copy(void);
|
void test_nghttp2_nv_array_copy(void);
|
||||||
void test_nghttp2_iv_check(void);
|
void test_nghttp2_iv_check(void);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ typedef struct {
|
||||||
accumulator *acc;
|
accumulator *acc;
|
||||||
scripted_data_feed *df;
|
scripted_data_feed *df;
|
||||||
int frame_recv_cb_called, invalid_frame_recv_cb_called;
|
int frame_recv_cb_called, invalid_frame_recv_cb_called;
|
||||||
|
nghttp2_frame_type recv_frame_type;
|
||||||
int frame_send_cb_called;
|
int frame_send_cb_called;
|
||||||
nghttp2_frame_type sent_frame_type;
|
nghttp2_frame_type sent_frame_type;
|
||||||
int frame_not_send_cb_called;
|
int frame_not_send_cb_called;
|
||||||
|
@ -161,6 +162,7 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
||||||
{
|
{
|
||||||
my_user_data *ud = (my_user_data*)user_data;
|
my_user_data *ud = (my_user_data*)user_data;
|
||||||
++ud->frame_recv_cb_called;
|
++ud->frame_recv_cb_called;
|
||||||
|
ud->recv_frame_type = frame->hd.type;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1084,6 +1086,100 @@ void test_nghttp2_session_recv_premature_headers(void)
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_session_recv_altsvc(void)
|
||||||
|
{
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
nghttp2_frame frame;
|
||||||
|
size_t protocol_id_len, host_len, origin_len;
|
||||||
|
uint8_t *protocol_id, *host, *origin;
|
||||||
|
uint8_t *data;
|
||||||
|
size_t datalen;
|
||||||
|
nghttp2_bufs bufs;
|
||||||
|
nghttp2_buf *buf;
|
||||||
|
ssize_t rv;
|
||||||
|
my_user_data ud;
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
|
||||||
|
frame_pack_bufs_init(&bufs);
|
||||||
|
|
||||||
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
|
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||||
|
|
||||||
|
protocol_id_len = strlen("h2");
|
||||||
|
host_len = strlen("h2.example.org");
|
||||||
|
origin_len = strlen("www.example.org");
|
||||||
|
|
||||||
|
datalen = protocol_id_len + host_len + origin_len;
|
||||||
|
data = malloc(datalen);
|
||||||
|
|
||||||
|
memcpy(data, "h2", protocol_id_len);
|
||||||
|
protocol_id = data;
|
||||||
|
|
||||||
|
memcpy(data + protocol_id_len, "h2.example.org", host_len);
|
||||||
|
host = data + protocol_id_len;
|
||||||
|
|
||||||
|
memcpy(data + protocol_id_len + host_len,
|
||||||
|
"http://www.example.org", origin_len);
|
||||||
|
origin = data + protocol_id_len + host_len;
|
||||||
|
|
||||||
|
nghttp2_frame_altsvc_init(&frame.altsvc, 1000000007, 1u << 31, 4000,
|
||||||
|
protocol_id, protocol_id_len,
|
||||||
|
host, host_len, origin, origin_len);
|
||||||
|
|
||||||
|
rv = nghttp2_frame_pack_altsvc(&bufs, &frame.altsvc);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == rv);
|
||||||
|
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
|
||||||
|
|
||||||
|
nghttp2_frame_altsvc_free(&frame.altsvc);
|
||||||
|
|
||||||
|
buf = &bufs.head->buf;
|
||||||
|
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
|
||||||
|
|
||||||
|
/* error if server receives ALTSVC */
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||||
|
|
||||||
|
ud.frame_recv_cb_called = 0;
|
||||||
|
|
||||||
|
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||||
|
|
||||||
|
CU_ASSERT(rv == nghttp2_buf_len(buf));
|
||||||
|
CU_ASSERT(0 == ud.frame_recv_cb_called);
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
nghttp2_session_client_new(&session, &callbacks, &ud);
|
||||||
|
|
||||||
|
ud.frame_recv_cb_called = 0;
|
||||||
|
|
||||||
|
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||||
|
|
||||||
|
CU_ASSERT(rv == nghttp2_buf_len(buf));
|
||||||
|
CU_ASSERT(1 == ud.frame_recv_cb_called);
|
||||||
|
CU_ASSERT(NGHTTP2_ALTSVC == ud.recv_frame_type);
|
||||||
|
|
||||||
|
/* premature payload */
|
||||||
|
nghttp2_put_uint16be(buf->pos, 8);
|
||||||
|
|
||||||
|
ud.frame_recv_cb_called = 0;
|
||||||
|
|
||||||
|
rv = nghttp2_session_mem_recv(session, buf->pos, NGHTTP2_FRAME_HDLEN + 8);
|
||||||
|
|
||||||
|
CU_ASSERT(rv == NGHTTP2_FRAME_HDLEN + 8);
|
||||||
|
CU_ASSERT(0 == ud.frame_recv_cb_called);
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
|
|
||||||
|
nghttp2_bufs_free(&bufs);
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
void test_nghttp2_session_continue(void)
|
void test_nghttp2_session_continue(void)
|
||||||
{
|
{
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
|
@ -3381,6 +3477,73 @@ void test_nghttp2_submit_window_update_local_window_size(void)
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_submit_altsvc(void)
|
||||||
|
{
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
const char protocol_id[] = "h2";
|
||||||
|
const char host[] = "localhost";
|
||||||
|
const char origin[] = "http://localhost/";
|
||||||
|
nghttp2_frame *frame;
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
my_user_data ud;
|
||||||
|
|
||||||
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
|
callbacks.send_callback = null_send_callback;
|
||||||
|
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||||
|
|
||||||
|
nghttp2_session_client_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_INVALID_STATE ==
|
||||||
|
nghttp2_submit_altsvc(session, NGHTTP2_FLAG_NONE,
|
||||||
|
0, 0, 3000,
|
||||||
|
(const uint8_t*)protocol_id,
|
||||||
|
strlen(protocol_id),
|
||||||
|
(const uint8_t*)host, strlen(host),
|
||||||
|
(const uint8_t*)origin, strlen(origin)));
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||||
|
|
||||||
|
CU_ASSERT(0 ==
|
||||||
|
nghttp2_submit_altsvc(session, NGHTTP2_FLAG_NONE,
|
||||||
|
9, 12345, 3000,
|
||||||
|
(const uint8_t*)protocol_id,
|
||||||
|
strlen(protocol_id),
|
||||||
|
(const uint8_t*)host, strlen(host),
|
||||||
|
(const uint8_t*)origin, strlen(origin)));
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
|
frame = OB_CTRL(item);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ALTSVC == frame->hd.type);
|
||||||
|
CU_ASSERT(9 == frame->hd.stream_id);
|
||||||
|
|
||||||
|
CU_ASSERT(12345 == frame->altsvc.max_age);
|
||||||
|
CU_ASSERT(3000 == frame->altsvc.port);
|
||||||
|
|
||||||
|
CU_ASSERT(strlen(protocol_id) == frame->altsvc.protocol_id_len);
|
||||||
|
CU_ASSERT(strlen(host) == frame->altsvc.host_len);
|
||||||
|
CU_ASSERT(strlen(origin) == frame->altsvc.origin_len);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == memcmp(protocol_id, frame->altsvc.protocol_id,
|
||||||
|
frame->altsvc.protocol_id_len));
|
||||||
|
CU_ASSERT(0 == memcmp(host, frame->altsvc.host, frame->altsvc.host_len));
|
||||||
|
CU_ASSERT(0 == memcmp(origin, frame->altsvc.origin,
|
||||||
|
frame->altsvc.origin_len));
|
||||||
|
|
||||||
|
ud.frame_send_cb_called = 0;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
|
||||||
|
CU_ASSERT(1 == ud.frame_send_cb_called);
|
||||||
|
CU_ASSERT(NGHTTP2_ALTSVC == ud.sent_frame_type);
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
void test_nghttp2_submit_invalid_nv(void)
|
void test_nghttp2_submit_invalid_nv(void)
|
||||||
{
|
{
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
|
|
|
@ -33,6 +33,7 @@ void test_nghttp2_session_recv_data(void);
|
||||||
void test_nghttp2_session_recv_continuation(void);
|
void test_nghttp2_session_recv_continuation(void);
|
||||||
void test_nghttp2_session_recv_headers_with_priority(void);
|
void test_nghttp2_session_recv_headers_with_priority(void);
|
||||||
void test_nghttp2_session_recv_premature_headers(void);
|
void test_nghttp2_session_recv_premature_headers(void);
|
||||||
|
void test_nghttp2_session_recv_altsvc(void);
|
||||||
void test_nghttp2_session_continue(void);
|
void test_nghttp2_session_continue(void);
|
||||||
void test_nghttp2_session_add_frame(void);
|
void test_nghttp2_session_add_frame(void);
|
||||||
void test_nghttp2_session_on_request_headers_received(void);
|
void test_nghttp2_session_on_request_headers_received(void);
|
||||||
|
@ -72,6 +73,7 @@ void test_nghttp2_submit_settings_update_local_window_size(void);
|
||||||
void test_nghttp2_submit_push_promise(void);
|
void test_nghttp2_submit_push_promise(void);
|
||||||
void test_nghttp2_submit_window_update(void);
|
void test_nghttp2_submit_window_update(void);
|
||||||
void test_nghttp2_submit_window_update_local_window_size(void);
|
void test_nghttp2_submit_window_update_local_window_size(void);
|
||||||
|
void test_nghttp2_submit_altsvc(void);
|
||||||
void test_nghttp2_submit_invalid_nv(void);
|
void test_nghttp2_submit_invalid_nv(void);
|
||||||
void test_nghttp2_session_open_stream(void);
|
void test_nghttp2_session_open_stream(void);
|
||||||
void test_nghttp2_session_get_next_ob_item(void);
|
void test_nghttp2_session_get_next_ob_item(void);
|
||||||
|
|
|
@ -47,6 +47,8 @@ int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len)
|
||||||
const uint8_t *payload = in + NGHTTP2_FRAME_HDLEN;
|
const uint8_t *payload = in + NGHTTP2_FRAME_HDLEN;
|
||||||
size_t payloadlen = len - NGHTTP2_FRAME_HDLEN;
|
size_t payloadlen = len - NGHTTP2_FRAME_HDLEN;
|
||||||
size_t payloadoff;
|
size_t payloadoff;
|
||||||
|
uint8_t *gift_payload;
|
||||||
|
size_t gift_payloadlen;
|
||||||
|
|
||||||
nghttp2_frame_unpack_frame_hd(&frame->hd, in);
|
nghttp2_frame_unpack_frame_hd(&frame->hd, in);
|
||||||
switch(frame->hd.type) {
|
switch(frame->hd.type) {
|
||||||
|
@ -85,6 +87,18 @@ int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len)
|
||||||
nghttp2_frame_unpack_window_update_payload
|
nghttp2_frame_unpack_window_update_payload
|
||||||
(&frame->window_update, payload, payloadlen);
|
(&frame->window_update, payload, payloadlen);
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
gift_payloadlen = payloadlen - 8;
|
||||||
|
gift_payload = malloc(gift_payloadlen);
|
||||||
|
|
||||||
|
memcpy(gift_payload, payload + 8, gift_payloadlen);
|
||||||
|
|
||||||
|
payloadlen -= 8;
|
||||||
|
|
||||||
|
rv = nghttp2_frame_unpack_altsvc_payload(&frame->altsvc,
|
||||||
|
payload, payloadlen,
|
||||||
|
gift_payload, gift_payloadlen);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Must not be reachable */
|
/* Must not be reachable */
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
Loading…
Reference in New Issue