1
0
mirror of https://github.com/moparisthebest/spdylay synced 2024-11-11 12:05:07 -05:00
spdylay/tests/spdylay_session_test.c
Tatsuhiro Tsujikawa 82e20192d8 Added functions to process received SETTINGS frame.
Now remote and local settings are stored separately.
The initial window size is included in SETTINGS frame, all active stream's
window sizes are now updated.
Removed the initial_window_size member from spdylay_stream because
it is the same as remote_settings's initial window size.
2012-03-10 00:10:11 +09:00

1901 lines
69 KiB
C

/*
* Spdylay - SPDY Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "spdylay_session_test.h"
#include <CUnit/CUnit.h>
#include <stdio.h>
#include <assert.h>
#include <arpa/inet.h>
#include "spdylay_session.h"
#include "spdylay_stream.h"
typedef struct {
uint8_t buf[4096];
size_t length;
} accumulator;
typedef struct {
uint8_t data[8192];
uint8_t* datamark;
uint8_t* datalimit;
size_t feedseq[8192];
size_t seqidx;
} scripted_data_feed;
typedef struct {
accumulator *acc;
scripted_data_feed *df;
int ctrl_recv_cb_called, invalid_ctrl_recv_cb_called;
int ctrl_send_cb_called;
spdylay_frame_type sent_frame_type;
int ctrl_not_send_cb_called;
spdylay_frame_type not_sent_frame_type;
int not_sent_error;
int stream_close_cb_called;
size_t data_source_length;
int32_t stream_id;
size_t block_count;
} my_user_data;
static void scripted_data_feed_init(scripted_data_feed *df,
uint8_t *data, size_t data_length)
{
memset(df, 0, sizeof(scripted_data_feed));
memcpy(df->data, data, data_length);
df->datamark = df->data;
df->datalimit = df->data+data_length;
df->feedseq[0] = data_length;
}
static ssize_t null_send_callback(spdylay_session *session,
const uint8_t* data, size_t len, int flags,
void *user_data)
{
return len;
}
static ssize_t fail_send_callback(spdylay_session *session,
const uint8_t *data, size_t len, int flags,
void *user_data)
{
return SPDYLAY_ERR_CALLBACK_FAILURE;
}
static ssize_t scripted_recv_callback(spdylay_session *session,
uint8_t* data, size_t len, int flags,
void *user_data)
{
scripted_data_feed *df = ((my_user_data*)user_data)->df;
size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
memcpy(data, df->datamark, wlen);
df->datamark += wlen;
if(wlen <= len) {
++df->seqidx;
} else {
df->feedseq[df->seqidx] -= wlen;
}
return wlen;
}
static ssize_t accumulator_send_callback(spdylay_session *session,
const uint8_t *buf, size_t len,
int flags, void* user_data)
{
accumulator *acc = ((my_user_data*)user_data)->acc;
assert(acc->length+len < sizeof(acc->buf));
memcpy(acc->buf+acc->length, buf, len);
acc->length += len;
return len;
}
static void on_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->ctrl_recv_cb_called;
}
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->invalid_ctrl_recv_cb_called;
}
static void on_ctrl_send_callback(spdylay_session *session,
spdylay_frame_type type,
spdylay_frame *frame,
void *user_data)
{
my_user_data *ud = (my_user_data*)user_data;
++ud->ctrl_send_cb_called;
ud->sent_frame_type = type;
}
static void on_ctrl_not_send_callback(spdylay_session *session,
spdylay_frame_type type,
spdylay_frame *frame,
int error,
void *user_data)
{
my_user_data *ud = (my_user_data*)user_data;
++ud->ctrl_not_send_cb_called;
ud->not_sent_frame_type = type;
ud->not_sent_error = error;
}
static ssize_t fixed_length_data_source_read_callback
(spdylay_session *session, int32_t stream_id,
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 void on_request_recv_callback(spdylay_session *session,
int32_t stream_id,
void *user_data)
{
my_user_data *ud = (my_user_data*)user_data;
ud->stream_id = stream_id;
}
static void no_stream_user_data_stream_close_callback
(spdylay_session *session,
int32_t stream_id,
spdylay_status_code status_code,
void *user_data)
{
my_user_data* my_data = (my_user_data*)user_data;
++my_data->stream_close_cb_called;
}
static char** dup_nv(const char **src)
{
return spdylay_frame_nv_copy(src);
}
static spdylay_settings_entry* dup_iv(const spdylay_settings_entry *iv,
size_t niv)
{
return spdylay_frame_iv_copy(iv, niv);
}
void test_spdylay_session_recv()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
scripted_data_feed df;
my_user_data user_data;
const char *nv[] = {
"url", "/", NULL
};
uint8_t *framedata = NULL, *nvbuf = NULL;
size_t framedatalen = 0, nvbuflen = 0;
ssize_t framelen;
spdylay_frame frame;
int i;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.recv_callback = scripted_recv_callback;
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
user_data.df = &df;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE,
1, 0, 3, dup_nv(nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&frame.syn_stream,
&session->hd_deflater);
scripted_data_feed_init(&df, framedata, framelen);
/* Send 1 byte per each read */
for(i = 0; i < framelen; ++i) {
df.feedseq[i] = 1;
}
free(framedata);
free(nvbuf);
spdylay_frame_syn_stream_free(&frame.syn_stream);
user_data.ctrl_recv_cb_called = 0;
while(df.seqidx < framelen) {
CU_ASSERT(0 == spdylay_session_recv(session));
}
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
spdylay_session_del(session);
}
void test_spdylay_session_add_frame()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
accumulator_send_callback,
NULL,
};
accumulator acc;
my_user_data user_data;
const char *nv[] = {
"method", "GET",
"scheme", "https",
"url", "/",
"version", "HTTP/1.1",
NULL
};
spdylay_frame *frame;
spdylay_syn_stream_aux_data *aux_data =
malloc(sizeof(spdylay_syn_stream_aux_data));
const uint8_t hd_ans1[] = {
0x80, 0x02, 0x00, 0x01
};
uint32_t temp32;
memset(aux_data, 0, sizeof(spdylay_syn_stream_aux_data));
acc.length = 0;
user_data.acc = &acc;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &user_data));
frame = malloc(sizeof(spdylay_frame));
spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 0, 0, 3, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame,
aux_data));
CU_ASSERT(0 == spdylay_pq_empty(&session->ob_ss_pq));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(memcmp(hd_ans1, acc.buf, 4) == 0);
/* check stream id */
memcpy(&temp32, &acc.buf[8], 4);
temp32 = ntohl(temp32);
CU_ASSERT(1 == temp32);
/* check assoc stream id */
memcpy(&temp32, &acc.buf[12], 4);
temp32 = ntohl(temp32);
CU_ASSERT(0 == temp32);
/* check pri */
temp32 = (acc.buf[16] >> 6) & 0x3;
CU_ASSERT(3 == temp32);
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 = NULL, *nvbuf = NULL;
size_t framedatalen = 0, nvbuflen = 0;
ssize_t framelen;
spdylay_frame frame;
user_data.df = &df;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&frame.syn_stream,
&session->hd_deflater);
scripted_data_feed_init(&df, framedata, framelen);
spdylay_frame_syn_stream_free(&frame.syn_stream);
CU_ASSERT(0 == spdylay_session_recv(session));
CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_syn_reply_init(&frame.syn_reply, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 100, dup_nv(nv));
framelen = spdylay_frame_pack_syn_reply(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&frame.syn_reply,
&session->hd_deflater);
scripted_data_feed_init(&df, framedata, framelen);
spdylay_frame_syn_reply_free(&frame.syn_reply);
CU_ASSERT(0 == spdylay_session_recv(session));
CU_ASSERT(2 == user_data.invalid_ctrl_recv_cb_called);
free(framedata);
free(nvbuf);
spdylay_session_del(session);
}
void test_spdylay_session_on_syn_stream_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
const char *nv[] = { NULL };
const char *upcase_nv[] = { "version", "http/1.1", "methoD", "get", NULL };
spdylay_frame frame;
spdylay_stream *stream;
int32_t stream_id = 1;
uint8_t pri = 3;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE,
stream_id, 0, pri, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
stream = spdylay_session_get_stream(session, stream_id);
CU_ASSERT(SPDYLAY_STREAM_OPENING == stream->state);
CU_ASSERT(pri == stream->pri);
/* Same stream ID twice leads stream closing */
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called);
CU_ASSERT(SPDYLAY_STREAM_CLOSING ==
spdylay_session_get_stream(session, stream_id)->state);
/* assoc_stream_id != 0 from client is invalid. */
frame.syn_stream.assoc_stream_id = 1;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(2 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_syn_stream_free(&frame.syn_stream);
/* Upper cased name/value pairs */
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE,
3, 0, 3, dup_nv(upcase_nv));
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(3 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
}
void test_spdylay_session_on_syn_stream_received_with_push()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
const char *nv[] = { NULL };
spdylay_frame frame;
spdylay_stream *stream;
int32_t stream_id = 2;
int32_t assoc_stream_id = 1;
uint8_t pri = 3;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_session_open_stream(session, assoc_stream_id, SPDYLAY_CTRL_FLAG_NONE,
pri, SPDYLAY_STREAM_OPENED, NULL);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_UNIDIRECTIONAL,
stream_id, assoc_stream_id, pri, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
stream = spdylay_session_get_stream(session, stream_id);
CU_ASSERT(SPDYLAY_STREAM_OPENING == stream->state);
/* assoc_stream_id == 0 is invalid */
frame.syn_stream.stream_id = 4;
frame.syn_stream.assoc_stream_id = 0;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called);
/* Push without SPDYLAY_CTRL_FLAG_UNIDIRECTIONAL is invalid */
frame.syn_stream.stream_id = 6;
frame.syn_stream.assoc_stream_id = 1;
frame.syn_stream.hd.flags = SPDYLAY_CTRL_FLAG_FIN;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(2 == user_data.invalid_ctrl_recv_cb_called);
/* Push to non-existent stream is invalid */
frame.syn_stream.stream_id = 8;
frame.syn_stream.assoc_stream_id = 3;
frame.syn_stream.hd.flags = SPDYLAY_CTRL_FLAG_UNIDIRECTIONAL;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(3 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
}
void test_spdylay_session_on_syn_reply_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
NULL,
NULL,
on_ctrl_recv_callback,
on_invalid_ctrl_recv_callback
};
my_user_data user_data;
const char *nv[] = { NULL };
const char *upcase_nv[] = { "version", "http/1.1", "methoD", "get", NULL };
spdylay_frame frame;
spdylay_stream *stream;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_syn_reply_init(&frame.syn_reply, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_syn_reply_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
CU_ASSERT(SPDYLAY_STREAM_OPENED ==
((spdylay_stream*)spdylay_map_find(&session->streams, 1))->state);
CU_ASSERT(0 == spdylay_session_on_syn_reply_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called);
CU_ASSERT(SPDYLAY_STREAM_CLOSING ==
((spdylay_stream*)spdylay_map_find(&session->streams, 1))->state);
/* Check the situation when SYN_REPLY is received after peer sends
FIN */
stream = spdylay_session_open_stream(session, 3, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENED, NULL);
spdylay_stream_shutdown(stream, SPDYLAY_SHUT_RD);
frame.syn_reply.stream_id = 3;
CU_ASSERT(0 == spdylay_session_on_syn_reply_received(session, &frame));
CU_ASSERT(2 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_syn_reply_free(&frame.syn_reply);
/* Upper cased name/value pairs */
spdylay_session_open_stream(session, 5, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_syn_reply_init(&frame.syn_reply, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 5, dup_nv(upcase_nv));
CU_ASSERT(0 == spdylay_session_on_syn_reply_received(session, &frame));
CU_ASSERT(3 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_syn_reply_free(&frame.syn_reply);
spdylay_session_del(session);
}
void test_spdylay_session_send_syn_stream()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
null_send_callback,
NULL,
NULL,
NULL
};
const char *nv[] = { NULL };
spdylay_frame *frame = malloc(sizeof(spdylay_frame));
spdylay_stream *stream;
spdylay_syn_stream_aux_data *aux_data =
malloc(sizeof(spdylay_syn_stream_aux_data));
memset(aux_data, 0, sizeof(spdylay_syn_stream_aux_data));
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
spdylay_frame_syn_stream_init(&frame->syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 0, 0, 3, dup_nv(nv));
spdylay_session_add_frame(session, SPDYLAY_SYN_STREAM, frame, aux_data);
CU_ASSERT(0 == spdylay_session_send(session));
stream = spdylay_session_get_stream(session, 1);
CU_ASSERT(SPDYLAY_STREAM_OPENING == stream->state);
spdylay_session_del(session);
}
void test_spdylay_session_send_syn_reply()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
null_send_callback,
NULL,
NULL,
NULL
};
const char *nv[] = { NULL };
spdylay_frame *frame = malloc(sizeof(spdylay_frame));
spdylay_stream *stream;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
spdylay_session_open_stream(session, 2, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_syn_reply_init(&frame->syn_reply, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 2, dup_nv(nv));
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);
spdylay_session_del(session);
}
void test_spdylay_submit_response()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
null_send_callback,
NULL,
NULL,
NULL
};
const char *nv[] = { "Content-Length", "1024", NULL };
int32_t stream_id = 2;
spdylay_data_provider data_prd;
my_user_data ud;
spdylay_outbound_item *item;
data_prd.read_callback = fixed_length_data_source_read_callback;
ud.data_source_length = 64*1024;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
spdylay_session_open_stream(session, stream_id, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_submit_response(session, stream_id, nv, &data_prd));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("content-length", item->frame->syn_reply.nv[0]));
CU_ASSERT(0 == spdylay_session_send(session));
spdylay_session_del(session);
}
void test_spdylay_submit_response_with_null_data_read_callback()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
accumulator acc;
const char *nv[] = { ":Version", "HTTP/1.1", NULL };
spdylay_data_provider data_prd = {{-1}, NULL};
spdylay_outbound_item *item;
my_user_data ud;
spdylay_frame frame;
acc.length = 0;
ud.acc = &acc;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_FIN, 3,
SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_submit_response(session, 1, nv, &data_prd));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp(":version", item->frame->syn_reply.nv[0]));
CU_ASSERT(item->frame->syn_reply.hd.flags & SPDYLAY_CTRL_FLAG_FIN);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == spdylay_frame_unpack_syn_reply(&frame.syn_reply,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == strcmp("version", frame.syn_reply.nv[0]));
spdylay_frame_syn_reply_free(&frame.syn_reply);
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[] = { "Version", "HTTP/1.1", NULL };
spdylay_data_provider data_prd;
my_user_data ud;
spdylay_outbound_item *item;
data_prd.read_callback = fixed_length_data_source_read_callback;
ud.data_source_length = 64*1024;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd, NULL));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0]));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == ud.data_source_length);
spdylay_session_del(session);
}
void test_spdylay_submit_request_with_null_data_read_callback()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
accumulator acc;
const char *nv[] = { ":Version", "HTTP/1.1", NULL };
spdylay_data_provider data_prd = {{-1}, NULL};
spdylay_outbound_item *item;
my_user_data ud;
spdylay_frame frame;
acc.length = 0;
ud.acc = &acc;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd, NULL));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp(":version", item->frame->syn_stream.nv[0]));
CU_ASSERT(item->frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == spdylay_frame_unpack_syn_stream(&frame.syn_stream,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == strcmp("version", frame.syn_stream.nv[0]));
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
}
void test_spdylay_submit_syn_stream()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { "version", "HTTP/1.1", NULL };
spdylay_outbound_item *item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 1, 3,
nv, NULL));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0]));
CU_ASSERT(SPDYLAY_CTRL_FLAG_FIN == item->frame->syn_stream.hd.flags);
/* See assoc-stream-ID is ignored */
CU_ASSERT(0 == item->frame->syn_stream.assoc_stream_id);
CU_ASSERT(3 == item->frame->syn_stream.pri);
spdylay_session_del(session);
CU_ASSERT(0 == spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 1, 3,
nv, NULL));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0]));
CU_ASSERT(SPDYLAY_CTRL_FLAG_FIN == item->frame->syn_stream.hd.flags);
CU_ASSERT(1 == item->frame->syn_stream.assoc_stream_id);
CU_ASSERT(3 == item->frame->syn_stream.pri);
spdylay_session_del(session);
}
void test_spdylay_submit_syn_reply()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { "version", "HTTP/1.1", NULL };
my_user_data ud;
spdylay_outbound_item *item;
spdylay_stream *stream;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
CU_ASSERT(0 == spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_syn_reply(session, SPDYLAY_CTRL_FLAG_FIN, 1,
nv));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_reply.nv[0]));
CU_ASSERT(SPDYLAY_CTRL_FLAG_FIN == item->frame->syn_reply.hd.flags);
ud.ctrl_send_cb_called = 0;
ud.sent_frame_type = 0;
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == ud.ctrl_send_cb_called);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_submit_syn_reply(session, SPDYLAY_CTRL_FLAG_FIN, 1,
nv));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == ud.ctrl_send_cb_called);
CU_ASSERT(SPDYLAY_SYN_REPLY == ud.sent_frame_type);
CU_ASSERT(stream->shut_flags & SPDYLAY_SHUT_WR);
spdylay_session_del(session);
}
void test_spdylay_submit_headers()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { ":Version", "HTTP/1.1", NULL };
my_user_data ud;
spdylay_outbound_item *item;
spdylay_stream *stream;
accumulator acc;
spdylay_frame frame;
acc.length = 0;
ud.acc = &acc;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = accumulator_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_headers(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp(":version", item->frame->headers.nv[0]));
CU_ASSERT(SPDYLAY_CTRL_FLAG_FIN == item->frame->headers.hd.flags);
ud.ctrl_send_cb_called = 0;
ud.sent_frame_type = 0;
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == ud.ctrl_send_cb_called);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_submit_headers(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == ud.ctrl_send_cb_called);
CU_ASSERT(SPDYLAY_HEADERS == ud.sent_frame_type);
CU_ASSERT(stream->shut_flags & SPDYLAY_SHUT_WR);
CU_ASSERT(0 == spdylay_frame_unpack_headers(&frame.headers,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == strcmp("version", frame.headers.nv[0]));
spdylay_frame_headers_free(&frame.headers);
spdylay_session_del(session);
}
void test_spdylay_session_reply_fail()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
fail_send_callback,
NULL,
NULL,
NULL
};
const char *nv[] = { NULL };
int32_t stream_id = 2;
spdylay_data_provider data_prd;
my_user_data ud;
data_prd.read_callback = fixed_length_data_source_read_callback;
ud.data_source_length = 4*1024;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_response(session, stream_id, nv, &data_prd));
CU_ASSERT(0 == spdylay_session_send(session));
spdylay_session_del(session);
}
void test_spdylay_session_on_headers_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
const char *nv[] = { NULL };
const char *upcase_nv[] = { "version", "http/1.1", "methoD", "get", NULL };
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENED, NULL);
spdylay_stream_shutdown(spdylay_session_get_stream(session, 1),
SPDYLAY_SHUT_WR);
spdylay_frame_headers_init(&frame.headers, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
CU_ASSERT(SPDYLAY_STREAM_OPENED ==
spdylay_session_get_stream(session, 1)->state);
frame.headers.hd.flags |= SPDYLAY_CTRL_FLAG_FIN;
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(2 == user_data.ctrl_recv_cb_called);
CU_ASSERT(NULL == spdylay_session_get_stream(session, 1));
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called);
/* Check to see when SPDYLAY_STREAM_CLOSING, incoming HEADERS is
discarded. */
spdylay_session_open_stream(session, 3, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_CLOSING, NULL);
frame.headers.stream_id = 3;
frame.headers.hd.flags = SPDYLAY_CTRL_FLAG_NONE;
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(2 == user_data.ctrl_recv_cb_called);
CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called);
/* Server initiated stream */
spdylay_session_open_stream(session, 2, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENING, NULL);
frame.headers.hd.flags = SPDYLAY_CTRL_FLAG_FIN;
frame.headers.stream_id = 2;
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(3 == user_data.ctrl_recv_cb_called);
CU_ASSERT(SPDYLAY_STREAM_OPENING ==
spdylay_session_get_stream(session, 2)->state);
CU_ASSERT(spdylay_session_get_stream(session, 2)->shut_flags &
SPDYLAY_SHUT_RD);
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(2 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_headers_free(&frame.headers);
/* Upper cased name/value pairs */
spdylay_session_open_stream(session, 5, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENED, NULL);
spdylay_frame_headers_init(&frame.headers, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 5, dup_nv(upcase_nv));
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(3 == user_data.invalid_ctrl_recv_cb_called);
spdylay_frame_headers_free(&frame.headers);
spdylay_session_del(session);
}
void test_spdylay_session_on_window_update_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_frame frame;
spdylay_stream *stream;
spdylay_outbound_item *data_item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENED, NULL);
spdylay_frame_window_update_init(&frame.window_update, SPDYLAY_PROTO_SPDY3,
1, 16*1024);
CU_ASSERT(0 == spdylay_session_on_window_update_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
CU_ASSERT(64*1024+16*1024 == stream->window_size);
data_item = malloc(sizeof(spdylay_outbound_item));
memset(data_item, 0, sizeof(spdylay_outbound_item));
spdylay_stream_defer_data(stream, data_item, SPDYLAY_DEFERRED_FLOW_CONTROL);
CU_ASSERT(0 == spdylay_session_on_window_update_received(session, &frame));
CU_ASSERT(2 == user_data.ctrl_recv_cb_called);
CU_ASSERT(64*1024+16*1024*2 == stream->window_size);
CU_ASSERT(NULL == stream->deferred_data);
spdylay_frame_window_update_free(&frame.window_update);
spdylay_session_del(session);
}
void test_spdylay_session_on_ping_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
NULL,
NULL,
on_ctrl_recv_callback,
on_invalid_ctrl_recv_callback
};
my_user_data user_data;
spdylay_frame frame;
spdylay_outbound_item *top;
uint32_t unique_id;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
unique_id = 2;
spdylay_frame_ping_init(&frame.ping, SPDYLAY_PROTO_SPDY2, unique_id);
CU_ASSERT(0 == spdylay_session_on_ping_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
top = spdylay_session_get_ob_pq_top(session);
CU_ASSERT(SPDYLAY_PING == top->frame_type);
CU_ASSERT(unique_id == top->frame->ping.unique_id);
session->last_ping_unique_id = 1;
frame.ping.unique_id = 1;
CU_ASSERT(0 == spdylay_session_on_ping_received(session, &frame));
CU_ASSERT(2 == user_data.ctrl_recv_cb_called);
spdylay_frame_ping_free(&frame.ping);
spdylay_session_del(session);
}
void test_spdylay_session_on_goaway_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
NULL,
NULL,
on_ctrl_recv_callback,
on_invalid_ctrl_recv_callback,
};
my_user_data user_data;
spdylay_frame frame;
int32_t stream_id = 1000000007;
user_data.ctrl_recv_cb_called = 0;
user_data.invalid_ctrl_recv_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_goaway_init(&frame.goaway, SPDYLAY_PROTO_SPDY2, stream_id,
SPDYLAY_GOAWAY_OK);
CU_ASSERT(0 == spdylay_session_on_goaway_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);
CU_ASSERT(session->goaway_flags == SPDYLAY_GOAWAY_RECV);
spdylay_frame_goaway_free(&frame.goaway);
spdylay_session_del(session);
}
void test_spdylay_session_on_data_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
my_user_data user_data;
spdylay_outbound_item *top;
int32_t stream_id = 2;
spdylay_stream *stream;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, stream_id,
SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_session_on_data_received(session,
SPDYLAY_DATA_FLAG_NONE,
4096, stream_id));
CU_ASSERT(0 == stream->shut_flags);
CU_ASSERT(0 == spdylay_session_on_data_received(session,
SPDYLAY_DATA_FLAG_FIN,
4096, stream_id));
CU_ASSERT(SPDYLAY_SHUT_RD == stream->shut_flags);
/* If SPDYLAY_STREAM_CLOSING state, DATA frame is discarded. */
stream_id = 4;
spdylay_session_open_stream(session, stream_id, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_CLOSING, NULL);
CU_ASSERT(0 == spdylay_session_on_data_received(session,
SPDYLAY_DATA_FLAG_NONE,
4096, stream_id));
CU_ASSERT(NULL == spdylay_session_get_ob_pq_top(session));
/* Check INVALID_STREAM case: DATA frame with stream ID which does
not exist. */
stream_id = 6;
CU_ASSERT(0 == spdylay_session_on_data_received(session,
SPDYLAY_DATA_FLAG_NONE,
4096, stream_id));
top = spdylay_session_get_ob_pq_top(session);
CU_ASSERT(SPDYLAY_RST_STREAM == top->frame_type);
CU_ASSERT(SPDYLAY_INVALID_STREAM == top->frame->rst_stream.status_code);
spdylay_session_del(session);
}
void test_spdylay_session_is_my_stream_id()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0));
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 1));
CU_ASSERT(1 == spdylay_session_is_my_stream_id(session, 2));
spdylay_session_del(session);
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0));
CU_ASSERT(1 == spdylay_session_is_my_stream_id(session, 1));
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 2));
spdylay_session_del(session);
}
void test_spdylay_session_on_rst_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_stream *stream;
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
/* server push */
spdylay_session_open_stream(session, 2, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
spdylay_stream_add_pushed_stream(stream, 2);
spdylay_session_open_stream(session, 4, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
spdylay_stream_add_pushed_stream(stream, 4);
spdylay_frame_rst_stream_init(&frame.rst_stream, SPDYLAY_PROTO_SPDY2, 1,
SPDYLAY_CANCEL);
CU_ASSERT(0 == spdylay_session_on_rst_stream_received(session, &frame));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 1));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 2));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 4));
spdylay_frame_rst_stream_free(&frame.rst_stream);
spdylay_session_del(session);
}
void test_spdylay_session_send_rst_stream()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_stream *stream;
spdylay_frame *frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
/* server push */
spdylay_session_open_stream(session, 2, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
spdylay_stream_add_pushed_stream(stream, 2);
spdylay_session_open_stream(session, 4, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
spdylay_stream_add_pushed_stream(stream, 4);
frame = malloc(sizeof(spdylay_frame));
spdylay_frame_rst_stream_init(&frame->rst_stream, SPDYLAY_PROTO_SPDY2, 1,
SPDYLAY_CANCEL);
spdylay_session_add_frame(session, SPDYLAY_RST_STREAM, frame, NULL);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 1));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 2));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 4));
spdylay_session_del(session);
}
void test_spdylay_session_get_next_ob_item()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
spdylay_submit_ping(session);
CU_ASSERT(SPDYLAY_PING ==
spdylay_session_get_next_ob_item(session)->frame_type);
spdylay_submit_request(session, 0, nv, NULL, NULL);
CU_ASSERT(SPDYLAY_PING ==
spdylay_session_get_next_ob_item(session)->frame_type);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
spdylay_submit_request(session, 0, nv, NULL, NULL);
CU_ASSERT(NULL == spdylay_session_get_next_ob_item(session));
spdylay_submit_response(session, 1, nv, NULL);
CU_ASSERT(SPDYLAY_SYN_REPLY ==
spdylay_session_get_next_ob_item(session)->frame_type);
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 3;
CU_ASSERT(SPDYLAY_SYN_STREAM ==
spdylay_session_get_next_ob_item(session)->frame_type);
spdylay_session_del(session);
}
void test_spdylay_session_pop_next_ob_item()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
spdylay_outbound_item *item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
spdylay_submit_ping(session);
spdylay_submit_request(session, 0, nv, NULL, NULL);
item = spdylay_session_pop_next_ob_item(session);
CU_ASSERT(SPDYLAY_PING == item->frame_type);
spdylay_outbound_item_free(item);
free(item);
item = spdylay_session_pop_next_ob_item(session);
CU_ASSERT(SPDYLAY_SYN_STREAM == item->frame_type);
spdylay_outbound_item_free(item);
free(item);
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
spdylay_submit_request(session, 0, nv, NULL, NULL);
spdylay_submit_response(session, 1, nv, NULL);
item = spdylay_session_pop_next_ob_item(session);
CU_ASSERT(SPDYLAY_SYN_REPLY == item->frame_type);
spdylay_outbound_item_free(item);
free(item);
CU_ASSERT(NULL == spdylay_session_pop_next_ob_item(session));
spdylay_submit_response(session, 1, nv, NULL);
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 2;
item = spdylay_session_pop_next_ob_item(session);
CU_ASSERT(SPDYLAY_SYN_STREAM == item->frame_type);
spdylay_outbound_item_free(item);
free(item);
spdylay_session_del(session);
}
void test_spdylay_session_on_request_recv_callback()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
const char *nv[] = { NULL };
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_request_recv_callback = on_request_recv_callback;
user_data.stream_id = 0;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(0 == user_data.stream_id);
frame.syn_stream.stream_id = 3;
frame.syn_stream.hd.flags |= SPDYLAY_CTRL_FLAG_FIN;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(3 == user_data.stream_id);
user_data.stream_id = 0;
frame.syn_stream.stream_id = 0;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(0 == user_data.stream_id);
spdylay_frame_syn_stream_free(&frame.syn_stream);
user_data.stream_id = 0;
spdylay_session_open_stream(session, 5, SPDYLAY_CTRL_FLAG_NONE, 0,
SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_headers_init(&frame.headers, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 5, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(0 == user_data.stream_id);
frame.headers.hd.flags |= SPDYLAY_CTRL_FLAG_FIN;
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(5 == user_data.stream_id);
user_data.stream_id = 0;
CU_ASSERT(0 == spdylay_session_on_headers_received(session, &frame));
CU_ASSERT(0 == user_data.stream_id);
spdylay_frame_headers_free(&frame.headers);
spdylay_session_del(session);
}
static void stream_close_callback(spdylay_session *session, int32_t stream_id,
spdylay_status_code status_code,
void *user_data)
{
my_user_data* my_data = (my_user_data*)user_data;
void *stream_data = spdylay_session_get_stream_user_data(session, stream_id);
++my_data->stream_close_cb_called;
CU_ASSERT(stream_data != NULL);
}
void test_spdylay_session_on_stream_close()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_stream *stream;
int32_t stream_id = 1;
uint8_t pri = 3;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_stream_close_callback = stream_close_callback;
user_data.stream_close_cb_called = 0;
CU_ASSERT(spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &user_data) == 0);
stream = spdylay_session_open_stream(session, stream_id,
SPDYLAY_CTRL_FLAG_NONE,
pri, SPDYLAY_STREAM_OPENED, &user_data);
CU_ASSERT(stream != NULL);
CU_ASSERT(spdylay_session_close_stream(session, stream_id, SPDYLAY_OK) == 0);
CU_ASSERT(user_data.stream_close_cb_called == 1);
spdylay_session_del(session);
}
void test_spdylay_session_max_concurrent_streams()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
spdylay_frame frame;
const char *nv[] = { NULL };
spdylay_outbound_item *item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, NULL);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENED, NULL);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 3, 0, 3, dup_nv(nv));
session->local_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
item = spdylay_session_get_ob_pq_top(session);
CU_ASSERT(SPDYLAY_RST_STREAM == item->frame_type);
CU_ASSERT(SPDYLAY_REFUSED_STREAM == item->frame->rst_stream.status_code)
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
}
static ssize_t block_count_send_callback(spdylay_session* session,
const uint8_t *data, size_t len,
int flags,
void *user_data)
{
my_user_data *ud = (my_user_data*)user_data;
int r;
if(ud->block_count == 0) {
r = SPDYLAY_ERR_WOULDBLOCK;
} else {
--ud->block_count;
r = len;
}
return r;
}
void test_spdylay_session_data_backoff_by_high_pri_frame()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
my_user_data ud;
spdylay_data_provider data_prd;
spdylay_stream *stream;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = block_count_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
data_prd.read_callback = fixed_length_data_source_read_callback;
ud.ctrl_send_cb_called = 0;
ud.data_source_length = 16*1024;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_submit_request(session, 3, nv, &data_prd, NULL);
ud.block_count = 2;
/* Sends SYN_STREAM + DATA[0] */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(SPDYLAY_SYN_STREAM == ud.sent_frame_type);
/* data for DATA[1] is read from data_prd but it is not sent */
CU_ASSERT(ud.data_source_length == 8*1024);
spdylay_submit_ping(session);
ud.block_count = 2;
/* Sends DATA[1] + PING, PING is interleaved in DATA sequence */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(SPDYLAY_PING == ud.sent_frame_type);
/* data for DATA[2] is read from data_prd but it is not sent */
CU_ASSERT(ud.data_source_length == 4*1024);
ud.block_count = 2;
/* Sends DATA[2..3] */
CU_ASSERT(0 == spdylay_session_send(session));
stream = spdylay_session_get_stream(session, 1);
CU_ASSERT(stream->shut_flags & SPDYLAY_SHUT_WR);
spdylay_session_del(session);
}
void test_spdylay_session_stop_data_with_rst_stream()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
my_user_data ud;
spdylay_data_provider data_prd;
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
callbacks.send_callback = block_count_send_callback;
data_prd.read_callback = fixed_length_data_source_read_callback;
ud.ctrl_send_cb_called = 0;
ud.data_source_length = 16*1024;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL);
spdylay_submit_response(session, 1, nv, &data_prd);
ud.block_count = 2;
/* Sends SYN_REPLY + DATA[0] */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(SPDYLAY_SYN_REPLY == ud.sent_frame_type);
/* data for DATA[1] is read from data_prd but it is not sent */
CU_ASSERT(ud.data_source_length == 8*1024);
spdylay_frame_rst_stream_init(&frame.rst_stream, SPDYLAY_PROTO_SPDY2, 1,
SPDYLAY_CANCEL);
CU_ASSERT(0 == spdylay_session_on_rst_stream_received(session, &frame));
spdylay_frame_rst_stream_free(&frame.rst_stream);
/* Big enough number to send all DATA frames potentially. */
ud.block_count = 100;
/* Nothing will be sent in the following call. */
CU_ASSERT(0 == spdylay_session_send(session));
/* With RST_STREAM, stream is canceled and further DATA on that
stream are not sent. */
CU_ASSERT(ud.data_source_length == 8*1024);
CU_ASSERT(NULL == spdylay_session_get_stream(session, 1));
spdylay_session_del(session);
}
/*
* Check that on_stream_close_callback is called when server pushed
* SYN_STREAM have SPDYLAY_CTRL_FLAG_FIN.
*/
void test_spdylay_session_stream_close_on_syn_stream()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
my_user_data ud;
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_stream_close_callback =
no_stream_user_data_stream_close_callback;
ud.stream_close_cb_called = 0;
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_FIN |
SPDYLAY_CTRL_FLAG_UNIDIRECTIONAL,
2, 1, 3, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
}
void test_spdylay_session_recv_invalid_frame()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
scripted_data_feed df;
my_user_data user_data;
const char *nv[] = {
"url", "/", NULL
};
uint8_t *framedata = NULL, *nvbuf = NULL;
size_t framedatalen = 0, nvbuflen = 0;
ssize_t framelen;
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.recv_callback = scripted_recv_callback;
callbacks.send_callback = null_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
user_data.df = &df;
user_data.ctrl_send_cb_called = 0;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_PROTO_SPDY2,
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 3, dup_nv(nv));
framelen = spdylay_frame_pack_syn_stream(&framedata, &framedatalen,
&nvbuf, &nvbuflen,
&frame.syn_stream,
&session->hd_deflater);
scripted_data_feed_init(&df, framedata, framelen);
CU_ASSERT(0 == spdylay_session_recv(session));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == user_data.ctrl_send_cb_called);
/* Receive exactly same bytes of SYN_STREAM causes error */
scripted_data_feed_init(&df, framedata, framelen);
CU_ASSERT(0 == spdylay_session_recv(session));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_send_cb_called);
CU_ASSERT(SPDYLAY_GOAWAY == user_data.sent_frame_type);
free(framedata);
free(nvbuf);
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
}
static ssize_t defer_data_source_read_callback
(spdylay_session *session, int32_t stream_id,
uint8_t *buf, size_t len, int *eof,
spdylay_data_source *source, void *user_data)
{
return SPDYLAY_ERR_DEFERRED;
}
void test_spdylay_session_defer_data()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
my_user_data ud;
spdylay_data_provider data_prd;
spdylay_outbound_item *item;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
callbacks.send_callback = block_count_send_callback;
data_prd.read_callback = defer_data_source_read_callback;
ud.ctrl_send_cb_called = 0;
ud.data_source_length = 16*1024;
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &ud);
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 3,
SPDYLAY_STREAM_OPENING, NULL);
spdylay_submit_response(session, 1, nv, &data_prd);
ud.block_count = 1;
/* Sends SYN_REPLY */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(SPDYLAY_SYN_REPLY == ud.sent_frame_type);
/* No data is read */
CU_ASSERT(ud.data_source_length == 16*1024);
ud.block_count = 1;
spdylay_submit_ping(session);
/* Sends PING */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(SPDYLAY_PING == ud.sent_frame_type);
/* Resume deferred DATA */
CU_ASSERT(0 == spdylay_session_resume_data(session, 1));
item = spdylay_session_get_ob_pq_top(session);
item->frame->data.data_prd.read_callback =
fixed_length_data_source_read_callback;
ud.block_count = 1;
/* Reads 2 4KiB blocks */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(ud.data_source_length == 8*1024);
/* Deferred again */
item->frame->data.data_prd.read_callback = defer_data_source_read_callback;
/* This is needed since 4KiB block is already read and waiting to be
sent. No read_callback invocation. */
ud.block_count = 1;
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(ud.data_source_length == 8*1024);
/* Resume deferred DATA */
CU_ASSERT(0 == spdylay_session_resume_data(session, 1));
item = spdylay_session_get_ob_pq_top(session);
item->frame->data.data_prd.read_callback =
fixed_length_data_source_read_callback;
ud.block_count = 1;
/* Reads 2 4KiB blocks */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(ud.data_source_length == 0);
spdylay_session_del(session);
}
void test_spdylay_session_flow_control()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { NULL };
my_user_data ud;
spdylay_data_provider data_prd;
spdylay_frame frame;
spdylay_stream *stream;
int32_t new_initial_window_size;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
data_prd.read_callback = fixed_length_data_source_read_callback;
ud.ctrl_send_cb_called = 0;
ud.data_source_length = 128*1024;
/* Initial window size is 64KiB */
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks, &ud);
spdylay_submit_request(session, 3, nv, &data_prd, NULL);
/* Sends 64KiB data */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(64*1024 == ud.data_source_length);
/* Back 32KiB */
spdylay_frame_window_update_init(&frame.window_update, SPDYLAY_PROTO_SPDY3,
1, 32*1024);
spdylay_session_on_window_update_received(session, &frame);
/* Sends another 32KiB data */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(32*1024 == ud.data_source_length);
stream = spdylay_session_get_stream(session, 1);
/* Change initial window size to 16KiB. The window_size becomes
negative. */
new_initial_window_size = 16*1024;
stream->window_size = new_initial_window_size-
(session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]
-stream->window_size);
CU_ASSERT(-48*1024 == stream->window_size);
/* Back 48KiB */
frame.window_update.delta_window_size = 48*1024;
spdylay_session_on_window_update_received(session, &frame);
/* Nothing is sent because window_size is less than 0 */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(32*1024 == ud.data_source_length);
/* Back 16KiB */
frame.window_update.delta_window_size = 16*1024;
spdylay_session_on_window_update_received(session, &frame);
/* Sends another 16KiB data */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(16*1024 == ud.data_source_length);
/* Back 16KiB */
frame.window_update.delta_window_size = 16*1024;
spdylay_session_on_window_update_received(session, &frame);
/* Sends another 16KiB data */
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == ud.data_source_length);
CU_ASSERT(spdylay_session_get_stream(session, 1)->shut_flags &
SPDYLAY_SHUT_WR);
spdylay_frame_window_update_free(&frame.window_update);
spdylay_session_del(session);
}
void test_spdylay_session_on_ctrl_not_send()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_stream *stream;
const char *nv[] = { NULL };
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_not_send_callback = on_ctrl_not_send_callback;
callbacks.send_callback = null_send_callback;
user_data.ctrl_not_send_cb_called = 0;
user_data.not_sent_frame_type = 0;
user_data.not_sent_error = 0;
CU_ASSERT(spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &user_data) == 0);
stream = spdylay_session_open_stream(session, 1,
SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENED, &user_data);
/* Check SYN_REPLY */
CU_ASSERT(0 ==
spdylay_submit_syn_reply(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_SYN_REPLY == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_INVALID_STREAM_STATE == user_data.not_sent_error);
stream->state = SPDYLAY_STREAM_OPENING;
user_data.ctrl_not_send_cb_called = 0;
/* Send bogus stream ID */
CU_ASSERT(0 ==
spdylay_submit_syn_reply(session, SPDYLAY_CTRL_FLAG_FIN, 3, nv));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_SYN_REPLY == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_STREAM_CLOSED == user_data.not_sent_error);
user_data.ctrl_not_send_cb_called = 0;
/* Shutdown transmission */
stream->shut_flags |= SPDYLAY_SHUT_WR;
CU_ASSERT(0 ==
spdylay_submit_syn_reply(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_SYN_REPLY == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_STREAM_SHUT_WR == user_data.not_sent_error);
stream->shut_flags = SPDYLAY_SHUT_NONE;
user_data.ctrl_not_send_cb_called = 0;
/* Queue RST_STREAM */
CU_ASSERT(0 ==
spdylay_submit_syn_reply(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv));
CU_ASSERT(0 == spdylay_submit_rst_stream(session, 1, SPDYLAY_INTERNAL_ERROR));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_SYN_REPLY == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_STREAM_CLOSING == user_data.not_sent_error);
stream = spdylay_session_open_stream(session, 3,
SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENED, &user_data);
/* Check HEADERS */
user_data.ctrl_not_send_cb_called = 0;
stream->state = SPDYLAY_STREAM_OPENING;
CU_ASSERT(0 ==
spdylay_submit_headers(session, SPDYLAY_CTRL_FLAG_FIN, 3, nv));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_HEADERS == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_INVALID_STREAM_STATE == user_data.not_sent_error);
stream->state = SPDYLAY_STREAM_OPENED;
user_data.ctrl_not_send_cb_called = 0;
/* Queue RST_STREAM */
CU_ASSERT(0 ==
spdylay_submit_headers(session, SPDYLAY_CTRL_FLAG_FIN, 3, nv));
CU_ASSERT(0 == spdylay_submit_rst_stream(session, 3, SPDYLAY_INTERNAL_ERROR));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_HEADERS == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_STREAM_CLOSING == user_data.not_sent_error);
spdylay_session_del(session);
/* Check SYN_STREAM */
user_data.ctrl_not_send_cb_called = 0;
CU_ASSERT(spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &user_data) == 0);
/* Maximum Stream ID is reached */
session->next_stream_id = (1u << 31)+1;
CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 0,
3, nv, NULL));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_SYN_STREAM == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_STREAM_ID_NOT_AVAILABLE == user_data.not_sent_error);
session->next_stream_id = 1;
user_data.ctrl_not_send_cb_called = 0;
/* Send GOAWAY */
CU_ASSERT(0 == spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK));
CU_ASSERT(0 == spdylay_submit_syn_stream(session, SPDYLAY_CTRL_FLAG_FIN, 0,
3, nv, NULL));
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(1 == user_data.ctrl_not_send_cb_called);
CU_ASSERT(SPDYLAY_SYN_STREAM == user_data.not_sent_frame_type);
CU_ASSERT(SPDYLAY_ERR_SYN_STREAM_NOT_ALLOWED == user_data.not_sent_error);
spdylay_session_del(session);
}
void test_spdylay_session_on_settings_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_stream *stream1, *stream2;
spdylay_frame frame;
const size_t niv = 5;
spdylay_settings_entry iv[niv];
iv[0].settings_id = SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = 1000000009;
iv[0].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
iv[1].settings_id = SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[1].value = 50;
iv[1].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
iv[2].settings_id = SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE;
iv[2].value = 64*1024;
iv[2].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
iv[3].settings_id = SPDYLAY_SETTINGS_CURRENT_CWND;
iv[3].value = 512;
iv[3].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
iv[4].settings_id = 999;
iv[4].value = 0;
iv[4].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks,
&user_data);
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE] = 16*1024;
stream1 = spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
stream2 = spdylay_session_open_stream(session, 2, SPDYLAY_CTRL_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING, NULL);
stream1->window_size = 16*1024;
stream2->window_size = -48*1024;
spdylay_frame_settings_init(&frame.settings, SPDYLAY_PROTO_SPDY3,
SPDYLAY_FLAG_SETTINGS_NONE, dup_iv(iv, niv), niv);
CU_ASSERT(0 == spdylay_session_on_settings_received(session, &frame));
CU_ASSERT(1000000009 ==
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]);
CU_ASSERT(64*1024 ==
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]);
CU_ASSERT(512 ==
session->remote_settings[SPDYLAY_SETTINGS_CURRENT_CWND]);
CU_ASSERT(64*1024 == stream1->window_size);
CU_ASSERT(0 == stream2->window_size);
frame.settings.iv[2].value = 16*1024;
CU_ASSERT(0 == spdylay_session_on_settings_received(session, &frame));
CU_ASSERT(16*1024 == stream1->window_size);
CU_ASSERT(-48*1024 == stream2->window_size);
spdylay_frame_settings_free(&frame.settings);
spdylay_session_del(session);
}