Added data_prd arugment to spdylay_submit_request() and supported POST request.

This commit is contained in:
Tatsuhiro Tsujikawa 2012-01-29 19:07:31 +09:00
parent c6a0fd06c1
commit 3d4cf8aec3
6 changed files with 118 additions and 32 deletions

View File

@ -318,10 +318,24 @@ int spdylay_session_want_write(spdylay_session *session);
*
* 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. In this case, "POST" must be specified with
* "method" key in |nv|. If |data_prd| is NULL, SYN_STREAM have
* FLAG_FIN.
*
* This function returns 0 if it succeeds, or negative error code.
*/
int spdylay_submit_request(spdylay_session *session, uint8_t pri,
const char **nv);
const char **nv,
spdylay_data_provider *data_prd);
/*
* Submits DATA frame to stream |stream_id|.
*
* This function returns 0 if it succeeds, or negative error code.
*/
int spdylay_submit_data(spdylay_session *session, int32_t stream_id,
spdylay_data_provider *data_prd);
/*
* Submits SYN_REPLY frame against stream |stream_id|. |nv| must

View File

@ -158,6 +158,7 @@ static void spdylay_outbound_item_free(spdylay_outbound_item *item)
break;
}
free(item->frame);
free(item->aux_data);
}
void spdylay_session_del(spdylay_session *session)
@ -180,7 +181,8 @@ void spdylay_session_del(spdylay_session *session)
int spdylay_session_add_frame(spdylay_session *session,
spdylay_frame_type frame_type,
spdylay_frame *frame)
spdylay_frame *frame,
void *aux_data)
{
int r;
spdylay_outbound_item *item;
@ -190,6 +192,7 @@ int spdylay_session_add_frame(spdylay_session *session,
}
item->frame_type = frame_type;
item->frame = frame;
item->aux_data = aux_data;
/* Set priority lowest at the moment. */
item->pri = 3;
switch(frame_type) {
@ -255,7 +258,7 @@ int spdylay_session_add_rst_stream(spdylay_session *session,
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);
r = spdylay_session_add_frame(session, SPDYLAY_RST_STREAM, frame, NULL);
if(r != 0) {
spdylay_frame_rst_stream_free(&frame->rst_stream);
free(frame);
@ -349,12 +352,14 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
ssize_t framebuflen;
switch(item->frame_type) {
case SPDYLAY_SYN_STREAM: {
uint32_t stream_id;
if(session->goaway_flags) {
/* When GOAWAY is sent or received, peer must not send new
SYN_STREAM. */
return SPDYLAY_ERR_INVALID_FRAME;
}
item->frame->syn_stream.stream_id = session->next_stream_id;
stream_id = session->next_stream_id;
item->frame->syn_stream.stream_id = stream_id;
session->next_stream_id += 2;
framebuflen = spdylay_frame_pack_syn_stream(&framebuf,
&item->frame->syn_stream,
@ -362,13 +367,24 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
if(framebuflen < 0) {
return framebuflen;
}
if(spdylay_session_open_stream(session, item->frame->syn_stream.stream_id,
if(spdylay_session_open_stream(session, stream_id,
item->frame->syn_stream.hd.flags,
item->frame->syn_stream.pri,
SPDYLAY_STREAM_INITIAL) == NULL) {
free(framebuf);
return SPDYLAY_ERR_NOMEM;
}
if(item->aux_data) {
/* We assume aux_data is a pointer to spdylay_data_provider */
spdylay_data_provider *data_prd = (spdylay_data_provider*)item->aux_data;
int r;
r = spdylay_submit_data(session, stream_id, data_prd);
if(r != 0) {
free(framebuf);
spdylay_session_close_stream(session, stream_id);
return r;
}
}
break;
}
case SPDYLAY_SYN_REPLY: {
@ -1188,7 +1204,7 @@ int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id)
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_ping_init(&frame->ping, unique_id);
r = spdylay_session_add_frame(session, SPDYLAY_PING, frame);
r = spdylay_session_add_frame(session, SPDYLAY_PING, frame, NULL);
if(r != 0) {
spdylay_frame_ping_free(&frame->ping);
free(frame);
@ -1206,7 +1222,7 @@ int spdylay_session_add_goaway(spdylay_session *session,
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_goaway_init(&frame->goaway, last_good_stream_id);
r = spdylay_session_add_frame(session, SPDYLAY_GOAWAY, frame);
r = spdylay_session_add_frame(session, SPDYLAY_GOAWAY, frame, NULL);
if(r != 0) {
spdylay_frame_goaway_free(&frame->goaway);
free(frame);
@ -1248,60 +1264,76 @@ int spdylay_submit_response(spdylay_session *session,
}
spdylay_frame_syn_reply_init(&frame->syn_reply, flags, stream_id,
nv_copy);
r = spdylay_session_add_frame(session, SPDYLAY_SYN_REPLY, frame);
r = spdylay_session_add_frame(session, SPDYLAY_SYN_REPLY, frame, NULL);
if(r != 0) {
spdylay_frame_syn_reply_free(&frame->syn_reply);
free(frame);
return r;
}
if(data_prd != NULL) {
spdylay_frame *data_frame;
r = spdylay_submit_data(session, stream_id, data_prd);
/* 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;
return r;
}
int spdylay_submit_data(spdylay_session *session, int32_t stream_id,
spdylay_data_provider *data_prd)
{
int r;
spdylay_frame *frame;
frame = malloc(sizeof(spdylay_frame));
if(frame == NULL) {
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_data_init(&frame->data, stream_id, data_prd);
r = spdylay_session_add_frame(session, SPDYLAY_DATA, frame, NULL);
if(r != 0) {
spdylay_frame_data_free(&frame->data);
free(frame);
}
return r;
}
int spdylay_submit_request(spdylay_session *session, uint8_t pri,
const char **nv)
const char **nv, spdylay_data_provider *data_prd)
{
int r;
spdylay_frame *frame;
char **nv_copy;
uint8_t flags = 0;
spdylay_data_provider *data_prd_copy;
if(pri > 3) {
return SPDYLAY_ERR_INVALID_ARGUMENT;
}
data_prd_copy = malloc(sizeof(spdylay_data_provider));
if(data_prd_copy == NULL) {
return SPDYLAY_ERR_NOMEM;
}
*data_prd_copy = *data_prd;
frame = malloc(sizeof(spdylay_frame));
if(frame == NULL) {
free(data_prd_copy);
return SPDYLAY_ERR_NOMEM;
}
nv_copy = spdylay_frame_nv_copy(nv);
if(nv_copy == NULL) {
free(frame);
free(data_prd_copy);
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_nv_sort(nv_copy);
/* When we support POST using spdylay_data_provider, flags should be
0 if data_prd is set. */
flags |= SPDYLAY_FLAG_FIN;
spdylay_frame_syn_stream_init(&frame->syn_stream,
SPDYLAY_FLAG_FIN, 0, 0, pri, nv_copy);
r = spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame);
if(data_prd == NULL) {
flags |= SPDYLAY_FLAG_FIN;
}
spdylay_frame_syn_stream_init(&frame->syn_stream, flags, 0, 0, pri, nv_copy);
r = spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame,
data_prd_copy);
if(r != 0) {
spdylay_frame_syn_stream_free(&frame->syn_stream);
free(frame);
free(data_prd_copy);
}
return r;
}

View File

@ -41,6 +41,7 @@
typedef struct {
spdylay_frame_type frame_type;
spdylay_frame *frame;
void *aux_data;
int pri;
} spdylay_outbound_item;
@ -123,9 +124,17 @@ typedef struct spdylay_session {
/* TODO stream timeout etc */
/*
* Adds frame |frame| of type |frame_type| to tx queue in |session|.
* |aux_data| is a pointer to arbitrary data. Its interpretation is
* defined per |frame_type|. When this function succeeds, it takes
* ownership of |frame| and |aux_data|, so caller must not free them.
* This function returns 0 if it succeeds, or negative error code.
*/
int spdylay_session_add_frame(spdylay_session *session,
spdylay_frame_type frame_type,
spdylay_frame *frame);
spdylay_frame *frame,
void *aux_data);
int spdylay_session_add_rst_stream(spdylay_session *session,
int32_t stream_id, uint32_t status_code);

View File

@ -80,6 +80,8 @@ int main()
!CU_add_test(pSuite, "session_send_syn_reply",
test_spdylay_session_send_syn_reply) ||
!CU_add_test(pSuite, "submit_response", test_spdylay_submit_response) ||
!CU_add_test(pSuite, "submit_request_with_data",
test_spdylay_submit_request_with_data) ||
!CU_add_test(pSuite, "session_reply_fail",
test_spdylay_session_reply_fail) ||
!CU_add_test(pSuite, "session_on_headers_received",

View File

@ -220,7 +220,8 @@ void test_spdylay_session_add_frame()
spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_FLAG_NONE, 0, 0, 3,
dup_nv(nv));
CU_ASSERT(0 == spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame));
CU_ASSERT(0 == spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame,
NULL));
CU_ASSERT(0 == spdylay_pq_empty(&session->ob_pq));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(memcmp(hd_ans1, acc.buf, 4) == 0);
@ -380,7 +381,7 @@ void test_spdylay_session_send_syn_stream()
spdylay_session_client_new(&session, &callbacks, NULL);
spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_FLAG_NONE,
0, 0, 3, dup_nv(nv));
spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame);
spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame, NULL);
CU_ASSERT(0 == spdylay_session_send(session));
stream = spdylay_session_get_stream(session, 1);
CU_ASSERT(SPDYLAY_STREAM_OPENING == stream->state);
@ -406,7 +407,7 @@ void test_spdylay_session_send_syn_reply()
SPDYLAY_STREAM_OPENING);
spdylay_frame_syn_reply_init(&frame->syn_reply, SPDYLAY_FLAG_NONE,
2, dup_nv(nv));
spdylay_session_add_frame(session, SPDYLAY_SYN_REPLY, frame);
spdylay_session_add_frame(session, SPDYLAY_SYN_REPLY, frame, NULL);
CU_ASSERT(0 == spdylay_session_send(session));
stream = spdylay_session_get_stream(session, 2);
CU_ASSERT(SPDYLAY_STREAM_OPENED == stream->state);
@ -442,6 +443,33 @@ void test_spdylay_submit_response()
spdylay_session_del(session);
}
void test_spdylay_submit_request_with_data()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
null_send_callback,
NULL,
NULL,
NULL
};
const char *nv[] = { NULL };
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));
CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == ud.data_source_length);
spdylay_session_del(session);
}
void test_spdylay_session_reply_fail()
{
spdylay_session *session;

View File

@ -33,6 +33,7 @@ void test_spdylay_session_on_syn_reply_received();
void test_spdylay_session_send_syn_stream();
void test_spdylay_session_send_syn_reply();
void test_spdylay_submit_response();
void test_spdylay_submit_request_with_data();
void test_spdylay_session_reply_fail();
void test_spdylay_session_on_headers_received();
void test_spdylay_session_on_ping_received();