Queue RST_STREAM if invalid stream ID is received in SYN_STREAM or SYN_REPLY.
Fixed bug that Z_DATA_ERROR is not handled. Fixed bug that spdylay_frame_alloc_pack_nv does not use nv_offset correctly.
This commit is contained in:
parent
fa549aa3a7
commit
3bfe48972c
|
@ -40,12 +40,70 @@ typedef enum {
|
||||||
SPDYLAY_ERR_WOULDBLOCK = -504,
|
SPDYLAY_ERR_WOULDBLOCK = -504,
|
||||||
SPDYLAY_ERR_PROTO = -505,
|
SPDYLAY_ERR_PROTO = -505,
|
||||||
SPDYLAY_ERR_CALLBACK_FAILURE = -505,
|
SPDYLAY_ERR_CALLBACK_FAILURE = -505,
|
||||||
|
SPDYLAY_ERR_INVALID_FRAME = -506,
|
||||||
} spdylay_error;
|
} spdylay_error;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPDYLAY_MSG_MORE
|
SPDYLAY_MSG_MORE
|
||||||
} spdylay_io_flag;
|
} spdylay_io_flag;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_SYN_STREAM = 1,
|
||||||
|
SPDYLAY_SYN_REPLY = 2,
|
||||||
|
SPDYLAY_RST_STREAM = 3,
|
||||||
|
SPDYLAY_SETTINGS = 4,
|
||||||
|
SPDYLAY_NOOP = 5,
|
||||||
|
SPDYLAY_PING = 6,
|
||||||
|
SPDYLAY_GOAWAY = 7,
|
||||||
|
} spdylay_frame_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_FLAG_FIN = 1
|
||||||
|
} spdylay_flag;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_PROTOCOL_ERROR = 1,
|
||||||
|
SPDYLAY_INVALID_STREAM = 2,
|
||||||
|
SPDYLAY_REFUSED_STREAM = 3,
|
||||||
|
SPDYLAY_UNSUPPORTED_VERSION = 4,
|
||||||
|
SPDYLAY_CANCEL = 5,
|
||||||
|
SPDYLAY_INTERNAL_ERROR = 6,
|
||||||
|
SPDYLAY_FLOW_CONTROL_ERROR = 7
|
||||||
|
} spdylay_status_code;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t type;
|
||||||
|
uint8_t flags;
|
||||||
|
int32_t length;
|
||||||
|
} spdylay_ctrl_hd;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_ctrl_hd hd;
|
||||||
|
int32_t stream_id;
|
||||||
|
int32_t assoc_stream_id;
|
||||||
|
uint8_t pri;
|
||||||
|
char **nv;
|
||||||
|
} spdylay_syn_stream;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_ctrl_hd hd;
|
||||||
|
int32_t stream_id;
|
||||||
|
char **nv;
|
||||||
|
} spdylay_syn_reply;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_ctrl_hd hd;
|
||||||
|
int32_t stream_id;
|
||||||
|
uint32_t status_code;
|
||||||
|
} spdylay_rst_stream;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
spdylay_syn_stream syn_stream;
|
||||||
|
spdylay_syn_reply syn_reply;
|
||||||
|
spdylay_rst_stream rst_stream;
|
||||||
|
} spdylay_frame;
|
||||||
|
|
||||||
struct spdylay_session;
|
struct spdylay_session;
|
||||||
typedef struct spdylay_session spdylay_session;
|
typedef struct spdylay_session spdylay_session;
|
||||||
|
|
||||||
|
@ -57,9 +115,28 @@ typedef ssize_t (*spdylay_recv_callback)
|
||||||
(spdylay_session *session,
|
(spdylay_session *session,
|
||||||
uint8_t *buf, size_t length, int flags, void *user_data);
|
uint8_t *buf, size_t length, int flags, void *user_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback function invoked by spdylay_session_recv() when a control
|
||||||
|
* frame is arrived.
|
||||||
|
*/
|
||||||
|
typedef void (*spdylay_on_ctrl_recv_callback)
|
||||||
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback function invoked by spdylay_session_recv() when an invalid
|
||||||
|
* control frame is arrived, which typically the case where RST_STREAM
|
||||||
|
* will be sent
|
||||||
|
*/
|
||||||
|
typedef void (*spdylay_on_invalid_ctrl_recv_callback)
|
||||||
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spdylay_send_callback send_callback;
|
spdylay_send_callback send_callback;
|
||||||
spdylay_recv_callback recv_callback;
|
spdylay_recv_callback recv_callback;
|
||||||
|
spdylay_on_ctrl_recv_callback on_ctrl_recv_callback;
|
||||||
|
spdylay_on_invalid_ctrl_recv_callback on_invalid_ctrl_recv_callback;
|
||||||
} spdylay_session_callbacks;
|
} spdylay_session_callbacks;
|
||||||
|
|
||||||
int spdylay_session_client_new(spdylay_session **session_ptr,
|
int spdylay_session_client_new(spdylay_session **session_ptr,
|
||||||
|
|
|
@ -75,14 +75,16 @@ static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
||||||
uint8_t *framebuf = malloc(maxframelen);
|
uint8_t *framebuf = malloc(maxframelen);
|
||||||
ssize_t framelen;
|
ssize_t framelen;
|
||||||
spdylay_frame_pack_nv(nvbuf, nv);
|
spdylay_frame_pack_nv(nvbuf, nv);
|
||||||
framelen = spdylay_zlib_deflate_hd(deflater, framebuf+18, maxframelen-18,
|
framelen = spdylay_zlib_deflate_hd(deflater,
|
||||||
|
framebuf+nv_offset,
|
||||||
|
maxframelen-nv_offset,
|
||||||
nvbuf, nvbuflen);
|
nvbuf, nvbuflen);
|
||||||
free(nvbuf);
|
free(nvbuf);
|
||||||
if(framelen < 0) {
|
if(framelen < 0) {
|
||||||
free(framebuf);
|
free(framebuf);
|
||||||
return framelen;
|
return framelen;
|
||||||
}
|
}
|
||||||
framelen += 18;
|
framelen += nv_offset;
|
||||||
*buf_ptr = framebuf;
|
*buf_ptr = framebuf;
|
||||||
return framelen;
|
return framelen;
|
||||||
}
|
}
|
||||||
|
@ -337,12 +339,38 @@ void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame)
|
||||||
free(frame->nv);
|
free(frame->nv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_syn_reply_init(spdylay_syn_reply *frame, uint8_t flags,
|
||||||
|
int32_t stream_id, char **nv)
|
||||||
|
{
|
||||||
|
memset(frame, 0, sizeof(spdylay_syn_reply));
|
||||||
|
frame->hd.version = 2;
|
||||||
|
frame->hd.type = SPDYLAY_SYN_REPLY;
|
||||||
|
frame->hd.flags = flags;
|
||||||
|
frame->stream_id = stream_id;
|
||||||
|
frame->nv = nv;
|
||||||
|
}
|
||||||
|
|
||||||
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame)
|
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame)
|
||||||
{
|
{
|
||||||
spdylay_frame_nv_free(frame->nv);
|
spdylay_frame_nv_free(frame->nv);
|
||||||
free(frame->nv);
|
free(frame->nv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame,
|
||||||
|
int32_t stream_id, uint32_t status_code)
|
||||||
|
{
|
||||||
|
memset(frame, 0, sizeof(spdylay_rst_stream));
|
||||||
|
frame->hd.version = 2;
|
||||||
|
frame->hd.type = SPDYLAY_RST_STREAM;
|
||||||
|
frame->hd.flags = 0;
|
||||||
|
frame->hd.length = 8;
|
||||||
|
frame->stream_id = stream_id;
|
||||||
|
frame->status_code = status_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame)
|
||||||
|
{}
|
||||||
|
|
||||||
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
|
ssize_t spdylay_frame_pack_syn_stream(uint8_t **buf_ptr,
|
||||||
spdylay_syn_stream *frame,
|
spdylay_syn_stream *frame,
|
||||||
spdylay_zlib *deflater)
|
spdylay_zlib *deflater)
|
||||||
|
@ -371,15 +399,36 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
|
||||||
spdylay_zlib *inflater)
|
spdylay_zlib *inflater)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
if(payloadlen < 12) {
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
}
|
||||||
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||||
frame->stream_id = spdylay_get_uint32(payload);
|
frame->stream_id = spdylay_get_uint32(payload) & 0x7fffffff;
|
||||||
frame->assoc_stream_id = spdylay_get_uint32(payload+4);
|
frame->assoc_stream_id = spdylay_get_uint32(payload+4) & 0x7fffffff;
|
||||||
frame->pri = spdylay_unpack_pri(payload+8);
|
frame->pri = spdylay_unpack_pri(payload+8);
|
||||||
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+10, payloadlen-10,
|
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+10, payloadlen-10,
|
||||||
inflater);
|
inflater);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
|
||||||
|
spdylay_syn_reply *frame,
|
||||||
|
spdylay_zlib *deflater)
|
||||||
|
{
|
||||||
|
uint8_t *framebuf = NULL;
|
||||||
|
size_t framelen;
|
||||||
|
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 14, deflater);
|
||||||
|
if(framelen < 0) {
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
frame->hd.length = framelen-8;
|
||||||
|
memset(framebuf, 0, 14);
|
||||||
|
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
|
||||||
|
spdylay_put_uint32be(&framebuf[8], frame->stream_id);
|
||||||
|
*buf_ptr = framebuf;
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
|
||||||
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
||||||
const uint8_t *head, size_t headlen,
|
const uint8_t *head, size_t headlen,
|
||||||
const uint8_t *payload, size_t payloadlen,
|
const uint8_t *payload, size_t payloadlen,
|
||||||
|
@ -387,9 +436,38 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||||
frame->stream_id = spdylay_get_uint32(payload);
|
frame->stream_id = spdylay_get_uint32(payload) &0x7fffffff;
|
||||||
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+6, payloadlen-6,
|
r = spdylay_frame_alloc_unpack_nv(&frame->nv, payload+6, payloadlen-6,
|
||||||
inflater);
|
inflater);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr,
|
||||||
|
spdylay_rst_stream *frame)
|
||||||
|
{
|
||||||
|
uint8_t *framebuf;
|
||||||
|
size_t framelen = 16;
|
||||||
|
framebuf = malloc(framelen);
|
||||||
|
if(framebuf == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
memset(framebuf, 0, framelen);
|
||||||
|
spdylay_frame_pack_ctrl_hd(framebuf, &frame->hd);
|
||||||
|
spdylay_put_uint32be(&framebuf[8], frame->stream_id);
|
||||||
|
spdylay_put_uint32be(&framebuf[12], frame->status_code);
|
||||||
|
*buf_ptr = framebuf;
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload, size_t payloadlen)
|
||||||
|
{
|
||||||
|
if(payloadlen < 8) {
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||||
|
frame->stream_id = spdylay_get_uint32(payload) & 0x7fffffff;
|
||||||
|
frame->status_code = spdylay_get_uint32(payload+4);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -29,48 +29,10 @@
|
||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <spdylay/spdylay.h>
|
||||||
#include "spdylay_zlib.h"
|
#include "spdylay_zlib.h"
|
||||||
#include "spdylay_buffer.h"
|
#include "spdylay_buffer.h"
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SPDYLAY_SYN_STREAM = 1,
|
|
||||||
SPDYLAY_SYN_REPLY = 2,
|
|
||||||
SPDYLAY_RST_STREAM = 3,
|
|
||||||
SPDYLAY_SETTINGS = 4,
|
|
||||||
SPDYLAY_NOOP = 5,
|
|
||||||
SPDYLAY_PING = 6,
|
|
||||||
SPDYLAY_GOAWAY = 7,
|
|
||||||
} spdylay_frame_type;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SPDYLAY_FLAG_FIN = 1
|
|
||||||
} spdylay_flag;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t version;
|
|
||||||
uint16_t type;
|
|
||||||
uint8_t flags;
|
|
||||||
int32_t length;
|
|
||||||
} spdylay_ctrl_hd;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
spdylay_ctrl_hd hd;
|
|
||||||
int32_t stream_id;
|
|
||||||
int32_t assoc_stream_id;
|
|
||||||
uint8_t pri;
|
|
||||||
char **nv;
|
|
||||||
} spdylay_syn_stream;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
spdylay_ctrl_hd hd;
|
|
||||||
int32_t stream_id;
|
|
||||||
char **nv;
|
|
||||||
} spdylay_syn_reply;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
spdylay_syn_stream syn_stream;
|
|
||||||
} spdylay_frame;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Packs SYN_STREAM frame |frame| in wire frame format and store it in
|
* Packs SYN_STREAM frame |frame| in wire frame format and store it in
|
||||||
* |*buf_ptr|. This function allocates enough memory to store given
|
* |*buf_ptr|. This function allocates enough memory to store given
|
||||||
|
@ -94,6 +56,17 @@ int spdylay_frame_unpack_syn_stream(spdylay_syn_stream *frame,
|
||||||
const uint8_t *payload, size_t payloadlen,
|
const uint8_t *payload, size_t payloadlen,
|
||||||
spdylay_zlib *inflater);
|
spdylay_zlib *inflater);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs SYN_REPLY frame |frame| in wire frame format and store it in
|
||||||
|
* |*buf_ptr|. This function allocates enough memory to store given
|
||||||
|
* frame in |*buf_ptr|. This function returns the size of packed frame
|
||||||
|
* it it succeeds, or returns negative error code. frame->hd.length is
|
||||||
|
* assigned after length is determined during packing process.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
|
||||||
|
spdylay_syn_reply *frame,
|
||||||
|
spdylay_zlib *deflater);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unpacks SYN_REPLY frame byte sequence into |frame|. This function
|
* Unpacks SYN_REPLY frame byte sequence into |frame|. This function
|
||||||
* returns 0 if it succeeds or negative error code.
|
* returns 0 if it succeeds or negative error code.
|
||||||
|
@ -103,6 +76,24 @@ int spdylay_frame_unpack_syn_reply(spdylay_syn_reply *frame,
|
||||||
const uint8_t *payload, size_t payloadlen,
|
const uint8_t *payload, size_t payloadlen,
|
||||||
spdylay_zlib *inflater);
|
spdylay_zlib *inflater);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs RST_STREAM frame |frame| in wire frame format and store it in
|
||||||
|
* |*buf_ptr|. This function allocates enough memory to store given
|
||||||
|
* frame in |*buf_ptr|. In spdy/2 spc, RST_STREAM wire format is
|
||||||
|
* always 16 bytes long. This function returns the size of packed
|
||||||
|
* frame if it succeeds, or negative error code.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr,
|
||||||
|
spdylay_rst_stream *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks RST_STREAM frame byte sequence into |frame|. This function
|
||||||
|
* returns 0 if it succeeds, or negative error code.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_unpack_rst_stream(spdylay_rst_stream *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload, size_t payloadlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns number of bytes to pack name/value pairs |nv|. This
|
* Returns number of bytes to pack name/value pairs |nv|. This
|
||||||
* function expects |nv| is sorted in ascending order of key. This
|
* function expects |nv| is sorted in ascending order of key. This
|
||||||
|
@ -136,8 +127,16 @@ void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags,
|
||||||
|
|
||||||
void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame);
|
void spdylay_frame_syn_stream_free(spdylay_syn_stream *frame);
|
||||||
|
|
||||||
|
void spdylay_frame_syn_reply_init(spdylay_syn_reply *frame, uint8_t flags,
|
||||||
|
int32_t stream_id, char **nv);
|
||||||
|
|
||||||
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame);
|
void spdylay_frame_syn_reply_free(spdylay_syn_reply *frame);
|
||||||
|
|
||||||
|
void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame,
|
||||||
|
int32_t stream_id, uint32_t status_code);
|
||||||
|
|
||||||
|
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if the first byte of this frame indicates it is a control
|
* Returns 1 if the first byte of this frame indicates it is a control
|
||||||
* frame.
|
* frame.
|
||||||
|
|
|
@ -52,7 +52,7 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
|
||||||
}
|
}
|
||||||
memset(*session_ptr, 0, sizeof(spdylay_session));
|
memset(*session_ptr, 0, sizeof(spdylay_session));
|
||||||
(*session_ptr)->next_stream_id = 1;
|
(*session_ptr)->next_stream_id = 1;
|
||||||
(*session_ptr)->last_accepted_stream_id = 0;
|
(*session_ptr)->last_recv_stream_id = 0;
|
||||||
|
|
||||||
r = spdylay_zlib_deflate_hd_init(&(*session_ptr)->hd_deflater);
|
r = spdylay_zlib_deflate_hd_init(&(*session_ptr)->hd_deflater);
|
||||||
if(r != 0) {
|
if(r != 0) {
|
||||||
|
@ -157,6 +157,25 @@ int spdylay_session_add_frame(spdylay_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spdylay_session_add_rst_stream(spdylay_session *session,
|
||||||
|
int32_t stream_id, uint32_t status_code)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_frame *frame;
|
||||||
|
frame = malloc(sizeof(spdylay_frame));
|
||||||
|
if(frame == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
spdylay_frame_rst_stream_init(&frame->rst_stream, stream_id, status_code);
|
||||||
|
r = spdylay_session_add_frame(session, SPDYLAY_RST_STREAM, frame);
|
||||||
|
if(r != 0) {
|
||||||
|
spdylay_frame_rst_stream_free(&frame->rst_stream);
|
||||||
|
free(frame);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id)
|
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@ -318,45 +337,143 @@ static void spdylay_debug_print_nv(char **nv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdylay_session_process_ctrl_frame(spdylay_session *session)
|
static void spdylay_session_call_on_ctrl_frame_received
|
||||||
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame)
|
||||||
|
{
|
||||||
|
if(session->callbacks.on_ctrl_recv_callback) {
|
||||||
|
session->callbacks.on_ctrl_recv_callback
|
||||||
|
(session, type, frame, session->user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks whether received stream_id is valid.
|
||||||
|
* This function returns 1 if it succeeds, or 0.
|
||||||
|
*/
|
||||||
|
static int spdylay_session_is_new_peer_stream_id(spdylay_session *session,
|
||||||
|
int32_t stream_id)
|
||||||
|
{
|
||||||
|
if(stream_id == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(session->server) {
|
||||||
|
return stream_id % 2 == 1 && session->last_recv_stream_id < stream_id;
|
||||||
|
} else {
|
||||||
|
return stream_id % 2 == 0 && session->last_recv_stream_id < stream_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validates SYN_STREAM frame |frame|. This function returns 0 if it
|
||||||
|
* succeeds, or -1.
|
||||||
|
*/
|
||||||
|
static int spdylay_session_validate_syn_stream(spdylay_session *session,
|
||||||
|
spdylay_syn_stream *frame)
|
||||||
|
{
|
||||||
|
/* TODO Check assoc_stream_id */
|
||||||
|
if(spdylay_session_is_new_peer_stream_id(session, frame->stream_id)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
|
||||||
|
int32_t stream_id)
|
||||||
|
{
|
||||||
|
return (spdylay_stream*)spdylay_map_find(&session->streams, stream_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validates SYN_REPLY frame |frame|. This function returns 0 if it
|
||||||
|
* succeeds, or -1.
|
||||||
|
*/
|
||||||
|
static int spdylay_session_validate_syn_reply(spdylay_session *session,
|
||||||
|
spdylay_syn_reply *frame)
|
||||||
|
{
|
||||||
|
spdylay_stream *stream;
|
||||||
|
stream = spdylay_session_get_stream(session, frame->stream_id);
|
||||||
|
if(stream && stream->state == SPDYLAY_STREAM_OPENING) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spdylay_session_handle_invalid_ctrl_frame(spdylay_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
spdylay_frame_type type,
|
||||||
|
spdylay_frame *frame)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
r = spdylay_session_add_rst_stream(session, stream_id,
|
||||||
|
SPDYLAY_PROTOCOL_ERROR);
|
||||||
|
if(r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if(session->callbacks.on_invalid_ctrl_recv_callback) {
|
||||||
|
session->callbacks.on_invalid_ctrl_recv_callback
|
||||||
|
(session, type, frame, session->user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_process_ctrl_frame(spdylay_session *session)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
|
spdylay_frame frame;
|
||||||
memcpy(&type, &session->iframe.headbuf[2], sizeof(uint16_t));
|
memcpy(&type, &session->iframe.headbuf[2], sizeof(uint16_t));
|
||||||
type = ntohs(type);
|
type = ntohs(type);
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SPDYLAY_SYN_STREAM: {
|
case SPDYLAY_SYN_STREAM:
|
||||||
spdylay_syn_stream frame;
|
|
||||||
printf("SYN_STREAM\n");
|
printf("SYN_STREAM\n");
|
||||||
r = spdylay_frame_unpack_syn_stream(&frame, session->iframe.headbuf,
|
r = spdylay_frame_unpack_syn_stream(&frame.syn_stream,
|
||||||
|
session->iframe.headbuf,
|
||||||
sizeof(session->iframe.headbuf),
|
sizeof(session->iframe.headbuf),
|
||||||
session->iframe.buf,
|
session->iframe.buf,
|
||||||
session->iframe.len,
|
session->iframe.len,
|
||||||
&session->hd_inflater);
|
&session->hd_inflater);
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
spdylay_debug_print_nv(frame.nv);
|
r = spdylay_session_validate_syn_stream(session, &frame.syn_stream);
|
||||||
spdylay_frame_syn_stream_free(&frame);
|
if(r == 0) {
|
||||||
|
spdylay_session_call_on_ctrl_frame_received(session, type, &frame);
|
||||||
|
} else {
|
||||||
|
r = spdylay_session_handle_invalid_ctrl_frame
|
||||||
|
(session, frame.syn_stream.stream_id, type, &frame);
|
||||||
|
}
|
||||||
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
} else {
|
||||||
|
/* TODO if r indicates mulformed NV pairs (multiple nulls) or
|
||||||
|
invalid frame, send RST_STREAM with PROTOCOL_ERROR. Same for
|
||||||
|
other control frames. */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case SPDYLAY_SYN_REPLY:
|
||||||
case SPDYLAY_SYN_REPLY: {
|
|
||||||
spdylay_syn_reply frame;
|
|
||||||
printf("SYN_REPLY\n");
|
printf("SYN_REPLY\n");
|
||||||
r = spdylay_frame_unpack_syn_reply(&frame, session->iframe.headbuf,
|
r = spdylay_frame_unpack_syn_reply(&frame.syn_reply,
|
||||||
|
session->iframe.headbuf,
|
||||||
sizeof(session->iframe.headbuf),
|
sizeof(session->iframe.headbuf),
|
||||||
session->iframe.buf,
|
session->iframe.buf,
|
||||||
session->iframe.len,
|
session->iframe.len,
|
||||||
&session->hd_inflater);
|
&session->hd_inflater);
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
spdylay_debug_print_nv(frame.nv);
|
r = spdylay_session_validate_syn_reply(session, &frame.syn_reply);
|
||||||
spdylay_frame_syn_reply_free(&frame);
|
if(r == 0) {
|
||||||
|
spdylay_session_call_on_ctrl_frame_received(session, type, &frame);
|
||||||
|
} else {
|
||||||
|
r = spdylay_session_handle_invalid_ctrl_frame
|
||||||
|
(session, frame.syn_reply.stream_id, type, &frame);
|
||||||
|
}
|
||||||
|
spdylay_frame_syn_reply_free(&frame.syn_reply);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
/* ignore */
|
/* ignore */
|
||||||
printf("Received control frame type %x\n", type);
|
printf("Received control frame type %x\n", type);
|
||||||
}
|
}
|
||||||
|
if(r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ typedef struct {
|
||||||
typedef struct spdylay_session {
|
typedef struct spdylay_session {
|
||||||
uint8_t server;
|
uint8_t server;
|
||||||
int32_t next_stream_id;
|
int32_t next_stream_id;
|
||||||
int32_t last_accepted_stream_id;
|
int32_t last_recv_stream_id;
|
||||||
|
|
||||||
spdylay_map /* <spdylay_stream*> */ streams;
|
spdylay_map /* <spdylay_stream*> */ streams;
|
||||||
spdylay_pq /* <spdylay_outbound_item*> */ ob_pq;
|
spdylay_pq /* <spdylay_outbound_item*> */ ob_pq;
|
||||||
|
@ -98,6 +98,9 @@ int spdylay_session_add_frame(spdylay_session *session,
|
||||||
spdylay_frame_type frame_type,
|
spdylay_frame_type frame_type,
|
||||||
spdylay_frame *frame);
|
spdylay_frame *frame);
|
||||||
|
|
||||||
|
int spdylay_session_add_rst_stream(spdylay_session *session,
|
||||||
|
int32_t stream_id, uint32_t status_code);
|
||||||
|
|
||||||
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id);
|
int spdylay_session_open_stream(spdylay_session *session, int32_t stream_id);
|
||||||
|
|
||||||
int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id);
|
int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id);
|
||||||
|
|
|
@ -32,8 +32,15 @@
|
||||||
#include <spdylay/spdylay.h>
|
#include <spdylay/spdylay.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
/* For stream initiator: SYN_STREAM has been sent, but SYN_REPLY is
|
||||||
|
not received yet. For receiver: SYN_STREAM has been received,
|
||||||
|
but it does not send SYN_REPLY yet. */
|
||||||
SPDYLAY_STREAM_OPENING,
|
SPDYLAY_STREAM_OPENING,
|
||||||
|
/* For stream initiator: SYN_REPLY is received. For receiver:
|
||||||
|
SYN_REPLY is sent. */
|
||||||
SPDYLAY_STREAM_OPENED,
|
SPDYLAY_STREAM_OPENED,
|
||||||
|
/* RST_STREAM is received, but somehow we need to keep stream in
|
||||||
|
memory. */
|
||||||
SPDYLAY_STREAM_CLOSING
|
SPDYLAY_STREAM_CLOSING
|
||||||
} spdylay_stream_state;
|
} spdylay_stream_state;
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ ssize_t spdylay_zlib_inflate_hd(spdylay_zlib *inflater,
|
||||||
inflater->zst.avail_out = spdylay_buffer_avail(buf);
|
inflater->zst.avail_out = spdylay_buffer_avail(buf);
|
||||||
inflater->zst.next_out = spdylay_buffer_get(buf);
|
inflater->zst.next_out = spdylay_buffer_get(buf);
|
||||||
r = inflate(&inflater->zst, Z_NO_FLUSH);
|
r = inflate(&inflater->zst, Z_NO_FLUSH);
|
||||||
if(r == Z_STREAM_ERROR || r == Z_STREAM_END) {
|
if(r == Z_STREAM_ERROR || r == Z_STREAM_END || r == Z_DATA_ERROR) {
|
||||||
return SPDYLAY_ERR_ZLIB;
|
return SPDYLAY_ERR_ZLIB;
|
||||||
} else if(r == Z_NEED_DICT) {
|
} else if(r == Z_NEED_DICT) {
|
||||||
if(Z_OK != inflateSetDictionary(&inflater->zst, (uint8_t*)hd_dict,
|
if(Z_OK != inflateSetDictionary(&inflater->zst, (uint8_t*)hd_dict,
|
||||||
|
|
|
@ -67,6 +67,8 @@ int main()
|
||||||
!CU_add_test(pSuite, "buffer", test_spdylay_buffer) ||
|
!CU_add_test(pSuite, "buffer", test_spdylay_buffer) ||
|
||||||
!CU_add_test(pSuite, "zlib", test_spdylay_zlib) ||
|
!CU_add_test(pSuite, "zlib", test_spdylay_zlib) ||
|
||||||
!CU_add_test(pSuite, "session_recv", test_spdylay_session_recv) ||
|
!CU_add_test(pSuite, "session_recv", test_spdylay_session_recv) ||
|
||||||
|
!CU_add_test(pSuite, "session_recv_invalid_stream_id",
|
||||||
|
test_spdylay_session_recv_invalid_stream_id) ||
|
||||||
!CU_add_test(pSuite, "session_add_frame",
|
!CU_add_test(pSuite, "session_add_frame",
|
||||||
test_spdylay_session_add_frame) ||
|
test_spdylay_session_add_frame) ||
|
||||||
!CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) ||
|
!CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) ||
|
||||||
|
|
|
@ -48,6 +48,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
accumulator *acc;
|
accumulator *acc;
|
||||||
scripted_data_feed *df;
|
scripted_data_feed *df;
|
||||||
|
int flags;
|
||||||
} my_user_data;
|
} my_user_data;
|
||||||
|
|
||||||
static void scripted_data_feed_init(scripted_data_feed *df,
|
static void scripted_data_feed_init(scripted_data_feed *df,
|
||||||
|
@ -87,6 +88,15 @@ static ssize_t accumulator_send_callback(spdylay_session *session,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void on_invalid_ctrl_recv_callback(spdylay_session *session,
|
||||||
|
spdylay_frame_type type,
|
||||||
|
spdylay_frame *frame,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
my_user_data *ud = (my_user_data*)user_data;
|
||||||
|
++ud->flags;
|
||||||
|
}
|
||||||
|
|
||||||
static char** dup_nv(const char **src)
|
static char** dup_nv(const char **src)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -175,3 +185,46 @@ void test_spdylay_session_add_frame()
|
||||||
|
|
||||||
spdylay_session_del(session);
|
spdylay_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_spdylay_session_recv_invalid_stream_id()
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks = {
|
||||||
|
NULL,
|
||||||
|
scripted_recv_callback,
|
||||||
|
NULL,
|
||||||
|
on_invalid_ctrl_recv_callback
|
||||||
|
};
|
||||||
|
scripted_data_feed df;
|
||||||
|
my_user_data user_data;
|
||||||
|
const char *nv[] = { NULL };
|
||||||
|
uint8_t *framedata;
|
||||||
|
size_t framelen;
|
||||||
|
spdylay_frame frame;
|
||||||
|
|
||||||
|
user_data.df = &df;
|
||||||
|
user_data.flags = 0;
|
||||||
|
spdylay_session_client_new(&session, &callbacks, &user_data);
|
||||||
|
spdylay_frame_syn_stream_init(&frame.syn_stream, 0, 1, 0, 3, dup_nv(nv));
|
||||||
|
framelen = spdylay_frame_pack_syn_stream(&framedata, &frame.syn_stream,
|
||||||
|
&session->hd_deflater);
|
||||||
|
scripted_data_feed_init(&df, framedata, framelen);
|
||||||
|
free(framedata);
|
||||||
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_session_recv(session));
|
||||||
|
CU_ASSERT(1 == user_data.flags);
|
||||||
|
|
||||||
|
spdylay_frame_syn_reply_init(&frame.syn_reply, 0, 100, dup_nv(nv));
|
||||||
|
framelen = spdylay_frame_pack_syn_reply(&framedata, &frame.syn_reply,
|
||||||
|
&session->hd_deflater);
|
||||||
|
scripted_data_feed_init(&df, framedata, framelen);
|
||||||
|
free(framedata);
|
||||||
|
spdylay_frame_syn_reply_free(&frame.syn_reply);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_session_recv(session));
|
||||||
|
CU_ASSERT(2 == user_data.flags);
|
||||||
|
|
||||||
|
spdylay_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define SPDYLAY_SESSION_TEST_H
|
#define SPDYLAY_SESSION_TEST_H
|
||||||
|
|
||||||
void test_spdylay_session_recv();
|
void test_spdylay_session_recv();
|
||||||
|
void test_spdylay_session_recv_invalid_stream_id();
|
||||||
void test_spdylay_session_add_frame();
|
void test_spdylay_session_add_frame();
|
||||||
|
|
||||||
#endif // SPDYLAY_SESSION_TEST_H
|
#endif // SPDYLAY_SESSION_TEST_H
|
||||||
|
|
Loading…
Reference in New Issue