mirror of
https://github.com/moparisthebest/spdylay
synced 2024-11-15 05:55:04 -05:00
Added spdylay_reply_submit() and DATA frame handling after SYN_REPLY.
This commit is contained in:
parent
f642bb98c7
commit
21e165f1f8
@ -32,6 +32,9 @@ extern "C" {
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct spdylay_session;
|
||||||
|
typedef struct spdylay_session spdylay_session;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPDYLAY_ERR_INVALID_ARGUMENT = -501,
|
SPDYLAY_ERR_INVALID_ARGUMENT = -501,
|
||||||
SPDYLAY_ERR_ZLIB = -502,
|
SPDYLAY_ERR_ZLIB = -502,
|
||||||
@ -60,6 +63,7 @@ typedef enum {
|
|||||||
SPDYLAY_NOOP = 5,
|
SPDYLAY_NOOP = 5,
|
||||||
SPDYLAY_PING = 6,
|
SPDYLAY_PING = 6,
|
||||||
SPDYLAY_GOAWAY = 7,
|
SPDYLAY_GOAWAY = 7,
|
||||||
|
SPDYLAY_DATA = 100,
|
||||||
} spdylay_frame_type;
|
} spdylay_frame_type;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -106,15 +110,33 @@ typedef struct {
|
|||||||
uint32_t status_code;
|
uint32_t status_code;
|
||||||
} spdylay_rst_stream;
|
} spdylay_rst_stream;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
int fd;
|
||||||
|
void *ptr;
|
||||||
|
} spdylay_data_source;
|
||||||
|
|
||||||
|
typedef ssize_t (*spdylay_data_source_read_callback)
|
||||||
|
(spdylay_session *session, uint8_t *buf, size_t length, int *eof,
|
||||||
|
spdylay_data_source *source, void *user_data);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_data_source source;
|
||||||
|
spdylay_data_source_read_callback read_callback;
|
||||||
|
} spdylay_data_provider;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t stream_id;
|
||||||
|
uint8_t flags;
|
||||||
|
spdylay_data_provider data_prd;
|
||||||
|
} spdylay_data;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
spdylay_syn_stream syn_stream;
|
spdylay_syn_stream syn_stream;
|
||||||
spdylay_syn_reply syn_reply;
|
spdylay_syn_reply syn_reply;
|
||||||
spdylay_rst_stream rst_stream;
|
spdylay_rst_stream rst_stream;
|
||||||
|
spdylay_data data;
|
||||||
} spdylay_frame;
|
} spdylay_frame;
|
||||||
|
|
||||||
struct spdylay_session;
|
|
||||||
typedef struct spdylay_session spdylay_session;
|
|
||||||
|
|
||||||
typedef ssize_t (*spdylay_send_callback)
|
typedef ssize_t (*spdylay_send_callback)
|
||||||
(spdylay_session *session,
|
(spdylay_session *session,
|
||||||
const uint8_t *data, size_t length, int flags, void *user_data);
|
const uint8_t *data, size_t length, int flags, void *user_data);
|
||||||
@ -163,6 +185,19 @@ int spdylay_session_want_write(spdylay_session *session);
|
|||||||
|
|
||||||
int spdylay_req_submit(spdylay_session *session, const char *path);
|
int spdylay_req_submit(spdylay_session *session, const char *path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Submits SYN_REPLY frame against stream |stream_id|. |nv| must
|
||||||
|
* include "status" and "version" key. "status" must be status code
|
||||||
|
* (e.g., "200" or "200 OK"). "version" is HTTP response version
|
||||||
|
* (e.g., "HTTP/1.1"). This function creates copies of all name/value
|
||||||
|
* pairs in |nv|. If |data_prd| is not NULL, it provides data which
|
||||||
|
* will be sent in subsequent DATA frames. If |data_prd| is NULL,
|
||||||
|
* SYN_REPLY will have FLAG_FIN.
|
||||||
|
*/
|
||||||
|
int spdylay_reply_submit(spdylay_session *session,
|
||||||
|
int32_t stream_id, const char **nv,
|
||||||
|
spdylay_data_provider *data_prd);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -313,12 +313,32 @@ int spdylay_frame_is_ctrl_frame(uint8_t first_byte)
|
|||||||
void spdylay_frame_nv_free(char **nv)
|
void spdylay_frame_nv_free(char **nv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; nv[i]; i += 2) {
|
for(i = 0; nv[i]; ++i) {
|
||||||
free(nv[i]);
|
free(nv[i]);
|
||||||
free(nv[i+1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char** spdylay_frame_nv_copy(const char **nv)
|
||||||
|
{
|
||||||
|
int n, i;
|
||||||
|
char **nnv;
|
||||||
|
for(n = 0;nv[n]; ++n);
|
||||||
|
nnv = malloc((n+1)*sizeof(char*));
|
||||||
|
if(nnv == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(i = 0; i < n; ++i) {
|
||||||
|
nnv[i] = strdup(nv[i]);
|
||||||
|
if(nnv[i] == NULL) {
|
||||||
|
spdylay_frame_nv_free(nnv[i]);
|
||||||
|
free(nnv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nnv[n] = NULL;
|
||||||
|
return nnv;
|
||||||
|
}
|
||||||
|
|
||||||
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags,
|
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame, uint8_t flags,
|
||||||
int32_t stream_id, int32_t assoc_stream_id,
|
int32_t stream_id, int32_t assoc_stream_id,
|
||||||
uint8_t pri, char **nv)
|
uint8_t pri, char **nv)
|
||||||
@ -371,12 +391,23 @@ void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame,
|
|||||||
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame)
|
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||||
|
spdylay_data_provider *data_prd)
|
||||||
|
{
|
||||||
|
memset(frame, 0, sizeof(spdylay_data));
|
||||||
|
frame->stream_id = stream_id;
|
||||||
|
frame->data_prd = *data_prd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_data_free(spdylay_data *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)
|
||||||
{
|
{
|
||||||
uint8_t *framebuf = NULL;
|
uint8_t *framebuf = NULL;
|
||||||
size_t framelen;
|
ssize_t framelen;
|
||||||
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 18, deflater);
|
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 18, deflater);
|
||||||
if(framelen < 0) {
|
if(framelen < 0) {
|
||||||
return framelen;
|
return framelen;
|
||||||
@ -417,7 +448,7 @@ ssize_t spdylay_frame_pack_syn_reply(uint8_t **buf_ptr,
|
|||||||
spdylay_zlib *deflater)
|
spdylay_zlib *deflater)
|
||||||
{
|
{
|
||||||
uint8_t *framebuf = NULL;
|
uint8_t *framebuf = NULL;
|
||||||
size_t framelen;
|
ssize_t framelen;
|
||||||
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 14, deflater);
|
framelen = spdylay_frame_alloc_pack_nv(&framebuf, frame->nv, 14, deflater);
|
||||||
if(framelen < 0) {
|
if(framelen < 0) {
|
||||||
return framelen;
|
return framelen;
|
||||||
@ -447,7 +478,7 @@ ssize_t spdylay_frame_pack_rst_stream(uint8_t **buf_ptr,
|
|||||||
spdylay_rst_stream *frame)
|
spdylay_rst_stream *frame)
|
||||||
{
|
{
|
||||||
uint8_t *framebuf;
|
uint8_t *framebuf;
|
||||||
size_t framelen = 16;
|
ssize_t framelen = 16;
|
||||||
framebuf = malloc(framelen);
|
framebuf = malloc(framelen);
|
||||||
if(framebuf == NULL) {
|
if(framebuf == NULL) {
|
||||||
return SPDYLAY_ERR_NOMEM;
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#define SPDYLAY_LENGTH_MASK 0xffffff
|
#define SPDYLAY_LENGTH_MASK 0xffffff
|
||||||
#define SPDYLAY_VERSION_MASK 0x7fff
|
#define SPDYLAY_VERSION_MASK 0x7fff
|
||||||
|
|
||||||
|
#define SPDYLAY_DATA_FRAME_LENGTH 4096
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
@ -141,6 +143,11 @@ void spdylay_frame_rst_stream_init(spdylay_rst_stream *frame,
|
|||||||
|
|
||||||
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame);
|
void spdylay_frame_rst_stream_free(spdylay_rst_stream *frame);
|
||||||
|
|
||||||
|
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||||
|
spdylay_data_provider *data_prd);
|
||||||
|
|
||||||
|
void spdylay_frame_data_free(spdylay_data *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.
|
||||||
@ -152,4 +159,10 @@ int spdylay_frame_is_ctrl_frame(uint8_t first_byte);
|
|||||||
*/
|
*/
|
||||||
void spdylay_frame_nv_free(char **nv);
|
void spdylay_frame_nv_free(char **nv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Makes a deep copy of |nv| and returns the copy. This function
|
||||||
|
* returns the pointer to the copy if it succeeds, or NULL.
|
||||||
|
*/
|
||||||
|
char** spdylay_frame_nv_copy(const char **nv);
|
||||||
|
|
||||||
#endif /* SPDYLAY_FRAME_H */
|
#endif /* SPDYLAY_FRAME_H */
|
||||||
|
@ -32,6 +32,21 @@
|
|||||||
|
|
||||||
#include "spdylay_helper.h"
|
#include "spdylay_helper.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns non-zero value if |stream_id| is initiated by local host.
|
||||||
|
* Otherwrise returns 0.
|
||||||
|
*/
|
||||||
|
static int spdylay_session_is_my_stream_id(spdylay_session *session,
|
||||||
|
int32_t stream_id)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
if(stream_id == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
r = stream_id % 2;
|
||||||
|
return (session->server && r == 0) || r == 1;
|
||||||
|
}
|
||||||
|
|
||||||
spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
|
spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
|
||||||
int32_t stream_id)
|
int32_t stream_id)
|
||||||
{
|
{
|
||||||
@ -113,6 +128,12 @@ static void spdylay_outbound_item_free(spdylay_outbound_item *item)
|
|||||||
case SPDYLAY_SYN_REPLY:
|
case SPDYLAY_SYN_REPLY:
|
||||||
spdylay_frame_syn_reply_free(&item->frame->syn_reply);
|
spdylay_frame_syn_reply_free(&item->frame->syn_reply);
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_RST_STREAM:
|
||||||
|
spdylay_frame_rst_stream_free(&item->frame->rst_stream);
|
||||||
|
break;
|
||||||
|
case SPDYLAY_DATA:
|
||||||
|
spdylay_frame_data_free(&item->frame->data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
free(item->frame);
|
free(item->frame);
|
||||||
}
|
}
|
||||||
@ -170,6 +191,14 @@ int spdylay_session_add_frame(spdylay_session *session,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SPDYLAY_DATA: {
|
||||||
|
spdylay_stream *stream = spdylay_session_get_stream
|
||||||
|
(session, frame->data.stream_id);
|
||||||
|
if(stream) {
|
||||||
|
item->pri = stream->pri;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
r = spdylay_pq_push(&session->ob_pq, item);
|
r = spdylay_pq_push(&session->ob_pq, item);
|
||||||
if(r != 0) {
|
if(r != 0) {
|
||||||
@ -232,6 +261,7 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
|||||||
spdylay_outbound_item *item,
|
spdylay_outbound_item *item,
|
||||||
uint8_t **framebuf_ptr)
|
uint8_t **framebuf_ptr)
|
||||||
{
|
{
|
||||||
|
/* TODO Get or validate stream ID here */
|
||||||
uint8_t *framebuf;
|
uint8_t *framebuf;
|
||||||
ssize_t framebuflen;
|
ssize_t framebuflen;
|
||||||
int r;
|
int r;
|
||||||
@ -264,6 +294,14 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SPDYLAY_DATA: {
|
||||||
|
framebuflen = spdylay_session_pack_data(session, &framebuf,
|
||||||
|
&item->frame->data);
|
||||||
|
if(framebuflen < 0) {
|
||||||
|
return framebuflen;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
framebuflen = SPDYLAY_ERR_INVALID_ARGUMENT;
|
framebuflen = SPDYLAY_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@ -280,10 +318,18 @@ static void spdylay_active_outbound_item_reset
|
|||||||
memset(aob, 0, sizeof(spdylay_active_outbound_item));
|
memset(aob, 0, sizeof(spdylay_active_outbound_item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static spdylay_outbound_item* spdylay_session_get_ob_pq_top
|
||||||
|
(spdylay_session *session)
|
||||||
|
{
|
||||||
|
return (spdylay_outbound_item*)spdylay_pq_top(&session->ob_pq);
|
||||||
|
}
|
||||||
|
|
||||||
static int spdylay_session_after_frame_sent(spdylay_session *session)
|
static int spdylay_session_after_frame_sent(spdylay_session *session)
|
||||||
{
|
{
|
||||||
|
/* TODO handle FIN flag. */
|
||||||
spdylay_frame *frame = session->aob.item->frame;
|
spdylay_frame *frame = session->aob.item->frame;
|
||||||
switch(session->aob.item->frame_type) {
|
spdylay_frame_type type = session->aob.item->frame_type;
|
||||||
|
switch(type) {
|
||||||
case SPDYLAY_SYN_STREAM: {
|
case SPDYLAY_SYN_STREAM: {
|
||||||
spdylay_stream *stream =
|
spdylay_stream *stream =
|
||||||
spdylay_session_get_stream(session, frame->syn_stream.stream_id);
|
spdylay_session_get_stream(session, frame->syn_stream.stream_id);
|
||||||
@ -302,14 +348,55 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
|
|||||||
}
|
}
|
||||||
case SPDYLAY_RST_STREAM:
|
case SPDYLAY_RST_STREAM:
|
||||||
spdylay_session_close_stream(session, frame->rst_stream.stream_id);
|
spdylay_session_close_stream(session, frame->rst_stream.stream_id);
|
||||||
|
break;
|
||||||
|
case SPDYLAY_DATA:
|
||||||
|
if((frame->data.flags & SPDYLAY_FLAG_FIN) &&
|
||||||
|
!spdylay_session_is_my_stream_id(session, frame->data.stream_id)) {
|
||||||
|
/* We send all data requested by peer, so close the stream. */
|
||||||
|
spdylay_session_close_stream(session, frame->data.stream_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
/* TODO If frame is data frame, we need to sent all chunk of
|
if(type == SPDYLAY_DATA) {
|
||||||
data.*/
|
int r;
|
||||||
spdylay_active_outbound_item_reset(&session->aob);
|
if(frame->data.flags & SPDYLAY_FLAG_FIN) {
|
||||||
|
spdylay_active_outbound_item_reset(&session->aob);
|
||||||
|
} else if(spdylay_pq_empty(&session->ob_pq) ||
|
||||||
|
session->aob.item->pri <=
|
||||||
|
spdylay_session_get_ob_pq_top(session)->pri) {
|
||||||
|
/* If priority of this stream is higher or equal to other stream
|
||||||
|
waiting at the top of the queue, we continue to send this
|
||||||
|
data. */
|
||||||
|
/* We assume that buffer has at least
|
||||||
|
SPDYLAY_DATA_FRAME_LENGTH. */
|
||||||
|
r = spdylay_session_pack_data_overwrite(session,
|
||||||
|
session->aob.framebuf,
|
||||||
|
SPDYLAY_DATA_FRAME_LENGTH,
|
||||||
|
&frame->data);
|
||||||
|
if(r < 0) {
|
||||||
|
spdylay_active_outbound_item_reset(&session->aob);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
session->aob.framebufoff = 0;
|
||||||
|
} else {
|
||||||
|
r = spdylay_pq_push(&session->ob_pq, session->aob.item);
|
||||||
|
if(r == 0) {
|
||||||
|
session->aob.item = NULL;
|
||||||
|
spdylay_active_outbound_item_reset(&session->aob);
|
||||||
|
} else {
|
||||||
|
spdylay_active_outbound_item_reset(&session->aob);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spdylay_active_outbound_item_reset(&session->aob);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdylay_session_send(spdylay_session *session)
|
int spdylay_session_send(spdylay_session *session)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
printf("session_send\n");
|
printf("session_send\n");
|
||||||
while(session->aob.item || !spdylay_pq_empty(&session->ob_pq)) {
|
while(session->aob.item || !spdylay_pq_empty(&session->ob_pq)) {
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
@ -320,7 +407,6 @@ int spdylay_session_send(spdylay_session *session)
|
|||||||
uint8_t *framebuf;
|
uint8_t *framebuf;
|
||||||
ssize_t framebuflen;
|
ssize_t framebuflen;
|
||||||
spdylay_pq_pop(&session->ob_pq);
|
spdylay_pq_pop(&session->ob_pq);
|
||||||
/* TODO Get or validate stream id here */
|
|
||||||
framebuflen = spdylay_session_prep_frame(session, item, &framebuf);
|
framebuflen = spdylay_session_prep_frame(session, item, &framebuf);
|
||||||
if(framebuflen < 0) {
|
if(framebuflen < 0) {
|
||||||
/* TODO Call error callback? */
|
/* TODO Call error callback? */
|
||||||
@ -331,6 +417,7 @@ int spdylay_session_send(spdylay_session *session)
|
|||||||
session->aob.item = item;
|
session->aob.item = item;
|
||||||
session->aob.framebuf = framebuf;
|
session->aob.framebuf = framebuf;
|
||||||
session->aob.framebuflen = framebuflen;
|
session->aob.framebuflen = framebuflen;
|
||||||
|
/* TODO Call before_send callback */
|
||||||
}
|
}
|
||||||
data = session->aob.framebuf + session->aob.framebufoff;
|
data = session->aob.framebuf + session->aob.framebufoff;
|
||||||
datalen = session->aob.framebuflen - session->aob.framebufoff;
|
datalen = session->aob.framebuflen - session->aob.framebufoff;
|
||||||
@ -343,11 +430,13 @@ int spdylay_session_send(spdylay_session *session)
|
|||||||
return sentlen;
|
return sentlen;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("sent %d bytes\n", sentlen);
|
|
||||||
session->aob.framebufoff += sentlen;
|
session->aob.framebufoff += sentlen;
|
||||||
if(session->aob.framebufoff == session->aob.framebuflen) {
|
if(session->aob.framebufoff == session->aob.framebuflen) {
|
||||||
/* Frame has completely sent */
|
/* Frame has completely sent */
|
||||||
spdylay_session_after_frame_sent(session);
|
r = spdylay_session_after_frame_sent(session);
|
||||||
|
if(r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* partial write */
|
/* partial write */
|
||||||
break;
|
break;
|
||||||
@ -437,17 +526,6 @@ static int spdylay_session_is_new_peer_stream_id(spdylay_session *session,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spdylay_session_is_my_stream_id(spdylay_session *session,
|
|
||||||
int32_t stream_id)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
if(stream_id == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
r = stream_id % 2;
|
|
||||||
return (session->server && r == 0) || r == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validates SYN_STREAM frame |frame|. This function returns 0 if it
|
* Validates SYN_STREAM frame |frame|. This function returns 0 if it
|
||||||
* succeeds, or -1.
|
* succeeds, or -1.
|
||||||
@ -683,6 +761,53 @@ int spdylay_session_want_write(spdylay_session *session)
|
|||||||
return session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq);
|
return session->aob.item != NULL || !spdylay_pq_empty(&session->ob_pq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spdylay_reply_submit(spdylay_session *session,
|
||||||
|
int32_t stream_id, const char **nv,
|
||||||
|
spdylay_data_provider *data_prd)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
spdylay_frame *frame;
|
||||||
|
spdylay_frame *data_frame = NULL;
|
||||||
|
char **nv_copy;
|
||||||
|
uint8_t flags = 0;
|
||||||
|
frame = malloc(sizeof(spdylay_frame));
|
||||||
|
if(frame == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
nv_copy = spdylay_frame_nv_copy(nv);
|
||||||
|
if(nv_copy == NULL) {
|
||||||
|
free(frame);
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
if(data_prd == NULL) {
|
||||||
|
flags |= SPDYLAY_FLAG_FIN;
|
||||||
|
}
|
||||||
|
spdylay_frame_syn_reply_init(&frame->syn_reply, flags, stream_id,
|
||||||
|
nv_copy);
|
||||||
|
r = spdylay_session_add_frame(session, SPDYLAY_SYN_REPLY, frame);
|
||||||
|
if(r != 0) {
|
||||||
|
spdylay_frame_syn_reply_free(&frame->syn_reply);
|
||||||
|
free(frame);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if(data_prd != NULL) {
|
||||||
|
/* TODO If error is not FATAL, we should add RST_STREAM frame to
|
||||||
|
cancel this stream. */
|
||||||
|
data_frame = malloc(sizeof(spdylay_frame));
|
||||||
|
if(data_frame == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
spdylay_frame_data_init(&data_frame->data, stream_id, data_prd);
|
||||||
|
r = spdylay_session_add_frame(session, SPDYLAY_DATA, data_frame);
|
||||||
|
if(r != 0) {
|
||||||
|
spdylay_frame_data_free(&data_frame->data);
|
||||||
|
free(data_frame);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int spdylay_req_submit(spdylay_session *session, const char *path)
|
int spdylay_req_submit(spdylay_session *session, const char *path)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
@ -702,5 +827,48 @@ int spdylay_req_submit(spdylay_session *session, const char *path)
|
|||||||
spdylay_frame_syn_stream_init(&frame->syn_stream,
|
spdylay_frame_syn_stream_init(&frame->syn_stream,
|
||||||
SPDYLAY_FLAG_FIN, 0, 0, 0, nv);
|
SPDYLAY_FLAG_FIN, 0, 0, 0, nv);
|
||||||
r = spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame);
|
r = spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame);
|
||||||
assert(r == 0);
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_session_pack_data(spdylay_session *session,
|
||||||
|
uint8_t **buf_ptr, spdylay_data *frame)
|
||||||
|
{
|
||||||
|
uint8_t *framebuf;
|
||||||
|
ssize_t framelen = SPDYLAY_DATA_FRAME_LENGTH;
|
||||||
|
framebuf = malloc(framelen);
|
||||||
|
if(framebuf == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
framelen = spdylay_session_pack_data_overwrite(session, framebuf, framelen,
|
||||||
|
frame);
|
||||||
|
if(framelen < 0) {
|
||||||
|
free(framebuf);
|
||||||
|
}
|
||||||
|
*buf_ptr = framebuf;
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_session_pack_data_overwrite(spdylay_session *session,
|
||||||
|
uint8_t *buf, size_t len,
|
||||||
|
spdylay_data *frame)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
int eof = 0;
|
||||||
|
uint8_t flags = 0;
|
||||||
|
r = frame->data_prd.read_callback
|
||||||
|
(session, buf+8, len-8, &eof, &frame->data_prd.source, session->user_data);
|
||||||
|
if(r < 0) {
|
||||||
|
return r;
|
||||||
|
} else if(len < r) {
|
||||||
|
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
memset(buf, 0, len);
|
||||||
|
spdylay_put_uint32be(&buf[0], frame->stream_id);
|
||||||
|
spdylay_put_uint32be(&buf[4], 8+r);
|
||||||
|
if(eof) {
|
||||||
|
flags |= SPDYLAY_FLAG_FIN;
|
||||||
|
}
|
||||||
|
buf[4] = flags;
|
||||||
|
frame->flags = flags;
|
||||||
|
return r+8;
|
||||||
}
|
}
|
||||||
|
@ -147,4 +147,25 @@ int spdylay_session_on_syn_reply_received(spdylay_session *session,
|
|||||||
spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
|
spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
|
||||||
int32_t stream_id);
|
int32_t stream_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs DATA frame |frame| in wire frame format and store it in
|
||||||
|
* |*buf_ptr|. This function always allocates
|
||||||
|
* 8+SPDYLAY_DATA_CHUNK_LENGTH bytes. It packs header in first 8
|
||||||
|
* bytes. Remaining bytes are filled using frame->data_prd. This
|
||||||
|
* function returns the size of packed frame if it succeeds, or
|
||||||
|
* negative error code.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_session_pack_data(spdylay_session *session,
|
||||||
|
uint8_t **buf_ptr, spdylay_data *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs DATA frame |frame| in wire frame format and store it in
|
||||||
|
* |buf|. |len| must be greater than or equal to 8. This function
|
||||||
|
* returns the sizeof packed frame if it succeeds, or negative error
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_session_pack_data_overwrite(spdylay_session *session,
|
||||||
|
uint8_t *buf, size_t len,
|
||||||
|
spdylay_data *frame);
|
||||||
|
|
||||||
#endif /* SPDYLAY_SESSION_H */
|
#endif /* SPDYLAY_SESSION_H */
|
||||||
|
@ -79,6 +79,7 @@ int main()
|
|||||||
test_spdylay_session_send_syn_stream) ||
|
test_spdylay_session_send_syn_stream) ||
|
||||||
!CU_add_test(pSuite, "session_send_syn_reply",
|
!CU_add_test(pSuite, "session_send_syn_reply",
|
||||||
test_spdylay_session_send_syn_reply) ||
|
test_spdylay_session_send_syn_reply) ||
|
||||||
|
!CU_add_test(pSuite, "reply_submit", test_spdylay_reply_submit) ||
|
||||||
!CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) ||
|
!CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) ||
|
||||||
!CU_add_test(pSuite, "frame_count_nv_space",
|
!CU_add_test(pSuite, "frame_count_nv_space",
|
||||||
test_spdylay_frame_count_nv_space)) {
|
test_spdylay_frame_count_nv_space)) {
|
||||||
|
@ -50,6 +50,7 @@ typedef struct {
|
|||||||
accumulator *acc;
|
accumulator *acc;
|
||||||
scripted_data_feed *df;
|
scripted_data_feed *df;
|
||||||
int valid, invalid;
|
int valid, invalid;
|
||||||
|
size_t data_source_length;
|
||||||
} 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,
|
||||||
@ -114,6 +115,24 @@ static void on_invalid_ctrl_recv_callback(spdylay_session *session,
|
|||||||
++ud->invalid;
|
++ud->invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t fixed_length_data_source_read_callback
|
||||||
|
(spdylay_session *session, uint8_t *buf, size_t len, int *eof,
|
||||||
|
spdylay_data_source *source, void *user_data)
|
||||||
|
{
|
||||||
|
my_user_data *ud = (my_user_data*)user_data;
|
||||||
|
size_t wlen;
|
||||||
|
if(len < ud->data_source_length) {
|
||||||
|
wlen = len;
|
||||||
|
} else {
|
||||||
|
wlen = ud->data_source_length;
|
||||||
|
}
|
||||||
|
ud->data_source_length -= wlen;
|
||||||
|
if(ud->data_source_length == 0) {
|
||||||
|
*eof = 1;
|
||||||
|
}
|
||||||
|
return wlen;
|
||||||
|
}
|
||||||
|
|
||||||
static char** dup_nv(const char **src)
|
static char** dup_nv(const char **src)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -368,3 +387,33 @@ void test_spdylay_session_send_syn_reply()
|
|||||||
|
|
||||||
spdylay_session_del(session);
|
spdylay_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_spdylay_reply_submit()
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks = {
|
||||||
|
null_send_callback,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char *nv[] = { NULL };
|
||||||
|
spdylay_stream *stream;
|
||||||
|
int32_t stream_id = 2;
|
||||||
|
spdylay_data_source source;
|
||||||
|
spdylay_data_provider data_prd = {
|
||||||
|
source,
|
||||||
|
fixed_length_data_source_read_callback
|
||||||
|
};
|
||||||
|
my_user_data ud;
|
||||||
|
|
||||||
|
ud.data_source_length = 64*1024;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, &ud));
|
||||||
|
spdylay_session_open_stream(session, stream_id, SPDYLAY_FLAG_NONE, 3,
|
||||||
|
SPDYLAY_STREAM_OPENING);
|
||||||
|
CU_ASSERT(0 == spdylay_reply_submit(session, stream_id, nv, &data_prd));
|
||||||
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
|
spdylay_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -32,5 +32,6 @@ void test_spdylay_session_on_syn_stream_received();
|
|||||||
void test_spdylay_session_on_syn_reply_received();
|
void test_spdylay_session_on_syn_reply_received();
|
||||||
void test_spdylay_session_send_syn_stream();
|
void test_spdylay_session_send_syn_stream();
|
||||||
void test_spdylay_session_send_syn_reply();
|
void test_spdylay_session_send_syn_reply();
|
||||||
|
void test_spdylay_reply_submit();
|
||||||
|
|
||||||
#endif // SPDYLAY_SESSION_TEST_H
|
#endif // SPDYLAY_SESSION_TEST_H
|
||||||
|
Loading…
Reference in New Issue
Block a user