From 4630dfb4fe0810472bd1efe7b40f5bbc21202dc2 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 8 Feb 2012 00:10:23 +0900 Subject: [PATCH] Added spdylay_on_request_recv_callback function. This function invoked when request from remote peer is received. In other words, frame with FIN flag set is received. In HTTP, this means HTTP request, including request body, is fully received. --- lib/includes/spdylay/spdylay.h | 10 +++++ lib/spdylay_session.c | 35 ++++++++++++---- tests/main.c | 2 + tests/spdylay_session_test.c | 75 +++++++++++++++++++++++++++++++--- tests/spdylay_session_test.h | 1 + 5 files changed, 110 insertions(+), 13 deletions(-) diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index f0ebbe56..24748f96 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -304,6 +304,15 @@ typedef void (*spdylay_on_stream_close_callback) (spdylay_session *session, int32_t stream_id, spdylay_status_code status_code, void *user_data); +/* + * Callback function invoked when request from remote peer is + * received. In other words, frame with FIN flag set is received. In + * HTTP, this means HTTP request, including request body, is fully + * received. + */ +typedef void (*spdylay_on_request_recv_callback) +(spdylay_session *session, int32_t stream_id, void *user_data); + typedef struct { spdylay_send_callback send_callback; spdylay_recv_callback recv_callback; @@ -315,6 +324,7 @@ typedef struct { spdylay_on_ctrl_send_callback on_ctrl_send_callback; spdylay_on_data_send_callback on_data_send_callback; spdylay_on_stream_close_callback on_stream_close_callback; + spdylay_on_request_recv_callback on_request_recv_callback; } spdylay_session_callbacks; /* diff --git a/lib/spdylay_session.c b/lib/spdylay_session.c index f0b22e2a..30219951 100644 --- a/lib/spdylay_session.c +++ b/lib/spdylay_session.c @@ -903,6 +903,15 @@ static void spdylay_debug_print_nv(char **nv) } } +static void spdylay_session_call_on_request_recv +(spdylay_session *session, int32_t stream_id) +{ + if(session->callbacks.on_request_recv_callback) { + session->callbacks.on_request_recv_callback(session, stream_id, + session->user_data); + } +} + static void spdylay_session_call_on_ctrl_frame_received (spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame) { @@ -1022,6 +1031,10 @@ int spdylay_session_on_syn_stream_received(spdylay_session *session, session->last_recv_stream_id = frame->syn_stream.stream_id; spdylay_session_call_on_ctrl_frame_received(session, SPDYLAY_SYN_STREAM, frame); + if(flags & SPDYLAY_FLAG_FIN) { + spdylay_session_call_on_request_recv(session, + frame->syn_stream.stream_id); + } } } else { r = spdylay_session_handle_invalid_stream @@ -1152,6 +1165,8 @@ int spdylay_session_on_headers_received(spdylay_session *session, spdylay_session_call_on_ctrl_frame_received(session, SPDYLAY_HEADERS, frame); if(frame->headers.hd.flags & SPDYLAY_FLAG_FIN) { + spdylay_session_call_on_request_recv(session, + frame->headers.stream_id); spdylay_stream_shutdown(stream, SPDYLAY_SHUT_RD); spdylay_session_close_stream_if_shut_rdwr(session, stream); } @@ -1272,16 +1287,20 @@ int spdylay_session_on_data_received(spdylay_session *session, uint8_t flags, int32_t length, int32_t stream_id) { - int valid = 0; int r = 0; spdylay_status_code status_code = 0; spdylay_stream *stream; stream = spdylay_session_get_stream(session, stream_id); if(stream) { if((stream->shut_flags & SPDYLAY_SHUT_RD) == 0) { + int valid = 0; if(spdylay_session_is_my_stream_id(session, stream_id)) { if(stream->state == SPDYLAY_STREAM_OPENED) { valid = 1; + if(session->callbacks.on_data_recv_callback) { + session->callbacks.on_data_recv_callback + (session, flags, stream_id, length, session->user_data); + } } else if(stream->state != SPDYLAY_STREAM_CLOSING) { status_code = SPDYLAY_PROTOCOL_ERROR; } @@ -1290,6 +1309,13 @@ int spdylay_session_on_data_received(spdylay_session *session, not receive FIN unless stream is in SPDYLAY_STREAM_CLOSING state. This is a race condition. */ valid = 1; + if(session->callbacks.on_data_recv_callback) { + session->callbacks.on_data_recv_callback + (session, flags, stream_id, length, session->user_data); + } + if(flags & SPDYLAY_FLAG_FIN) { + spdylay_session_call_on_request_recv(session, stream_id); + } } if(valid) { if(flags & SPDYLAY_FLAG_FIN) { @@ -1303,12 +1329,7 @@ int spdylay_session_on_data_received(spdylay_session *session, } else { status_code = SPDYLAY_INVALID_STREAM; } - if(valid) { - if(session->callbacks.on_data_recv_callback) { - session->callbacks.on_data_recv_callback - (session, flags, stream_id, length, session->user_data); - } - } else if(status_code != 0) { + if(status_code != 0) { r = spdylay_session_add_rst_stream(session, stream_id, status_code); } return r; diff --git a/tests/main.c b/tests/main.c index 006f24d9..a5adfafa 100644 --- a/tests/main.c +++ b/tests/main.c @@ -107,6 +107,8 @@ int main(int argc, char* argv[]) test_spdylay_session_get_next_ob_item) || !CU_add_test(pSuite, "session_pop_next_ob_item", test_spdylay_session_pop_next_ob_item) || + !CU_add_test(pSuite, "session_on_request_recv_callback", + test_spdylay_session_on_request_recv_callback) || !CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) || !CU_add_test(pSuite, "frame_count_nv_space", test_spdylay_frame_count_nv_space) || diff --git a/tests/spdylay_session_test.c b/tests/spdylay_session_test.c index a67a9003..fb18fb71 100644 --- a/tests/spdylay_session_test.c +++ b/tests/spdylay_session_test.c @@ -51,6 +51,7 @@ typedef struct { scripted_data_feed *df; int valid, invalid; size_t data_source_length; + int32_t stream_id; } my_user_data; static void scripted_data_feed_init(scripted_data_feed *df, @@ -140,6 +141,14 @@ static ssize_t fixed_length_data_source_read_callback 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 char** dup_nv(const char **src) { return spdylay_frame_nv_copy(src); @@ -536,15 +545,13 @@ void test_spdylay_session_reply_fail() void test_spdylay_session_on_headers_received() { spdylay_session *session; - spdylay_session_callbacks callbacks = { - NULL, - NULL, - on_ctrl_recv_callback, - on_invalid_ctrl_recv_callback - }; + 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_ctrl_recv_callback = on_ctrl_recv_callback; + callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback; user_data.valid = 0; user_data.invalid = 0; @@ -883,3 +890,59 @@ void test_spdylay_session_pop_next_ob_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, &callbacks, &user_data); + spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_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_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_FLAG_NONE, 0, + SPDYLAY_STREAM_OPENING, NULL); + spdylay_frame_headers_init(&frame.headers, SPDYLAY_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_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); +} diff --git a/tests/spdylay_session_test.h b/tests/spdylay_session_test.h index 66efd7bb..f0edb697 100644 --- a/tests/spdylay_session_test.h +++ b/tests/spdylay_session_test.h @@ -45,5 +45,6 @@ void test_spdylay_session_is_my_stream_id(); void test_spdylay_session_send_rst_stream(); void test_spdylay_session_get_next_ob_item(); void test_spdylay_session_pop_next_ob_item(); +void test_spdylay_session_on_request_recv_callback(); #endif // SPDYLAY_SESSION_TEST_H