aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Uzunov <andrey.uzunov@gmail.com>2013-08-11 20:40:36 +0000
committerAndrey Uzunov <andrey.uzunov@gmail.com>2013-08-11 20:40:36 +0000
commit4b0a8adbcc7d22cc86bb07dc56f7367dc96ad1ed (patch)
treedd2e10eaa6c27b2930060111da677b775b228840
parente421dc4c64105540b24ee732e8887ee26c40276a (diff)
downloadlibmicrohttpd-4b0a8adbcc7d22cc86bb07dc56f7367dc96ad1ed.tar.gz
libmicrohttpd-4b0a8adbcc7d22cc86bb07dc56f7367dc96ad1ed.zip
spdy: WINDOW_UPDATE sent on data receiving to allow big HTTP bodies
-rw-r--r--src/microspdy/internal.h18
-rw-r--r--src/microspdy/session.c111
-rw-r--r--src/microspdy/session.h31
-rw-r--r--src/microspdy/stream.c1
-rw-r--r--src/microspdy/structures.h5
5 files changed, 161 insertions, 5 deletions
diff --git a/src/microspdy/internal.h b/src/microspdy/internal.h
index 74281577..a7aec14f 100644
--- a/src/microspdy/internal.h
+++ b/src/microspdy/internal.h
@@ -28,14 +28,24 @@
28#include "platform.h" 28#include "platform.h"
29#include "microspdy.h" 29#include "microspdy.h"
30 30
31/* size of read buffers for each connection 31/**
32 * must be at least the size of SPDY_MAX_SUPPORTED_FRAME_SIZE */ 32 * size of read buffers for each connection
33 * must be at least the size of SPDY_MAX_SUPPORTED_FRAME_SIZE
34 */
33#define SPDYF_BUFFER_SIZE 8192 35#define SPDYF_BUFFER_SIZE 8192
34 36
35/* number of frames written to the socket at once. After X frames 37/**
38 * initial size of window for each stream (this is for the data
39 * within data frames that can be handled)
40 */
41#define SPDYF_INITIAL_WINDOW_SIZE 65536
42
43/**
44 * number of frames written to the socket at once. After X frames
36 * everything should be run again. In this way the application can 45 * everything should be run again. In this way the application can
37 * response to more important requests while a big file is still 46 * response to more important requests while a big file is still
38 * being transmitted to the client */ 47 * being transmitted to the client
48 */
39#define SPDYF_NUM_SENT_FRAMES_AT_ONCE 10 49#define SPDYF_NUM_SENT_FRAMES_AT_ONCE 10
40 50
41 51
diff --git a/src/microspdy/session.c b/src/microspdy/session.c
index 7edebaba..918b9fdf 100644
--- a/src/microspdy/session.c
+++ b/src/microspdy/session.c
@@ -380,7 +380,9 @@ spdyf_handler_read_data (struct SPDY_Session *session)
380 frame->length, 380 frame->length,
381 0 == (SPDY_DATA_FLAG_FIN & frame->flags)); 381 0 == (SPDY_DATA_FLAG_FIN & frame->flags));
382 382
383 session->read_buffer_beginning += frame->length; 383 session->read_buffer_beginning += frame->length;
384
385 stream->window_size -= frame->length;
384 386
385 //TODO close in and send rst maybe 387 //TODO close in and send rst maybe
386 SPDYF_ASSERT(SPDY_YES == ret, "Cancel POST data is not yet implemented"); 388 SPDYF_ASSERT(SPDY_YES == ret, "Cancel POST data is not yet implemented");
@@ -389,6 +391,20 @@ spdyf_handler_read_data (struct SPDY_Session *session)
389 { 391 {
390 stream->is_in_closed = true; 392 stream->is_in_closed = true;
391 } 393 }
394 else if(stream->window_size < SPDYF_INITIAL_WINDOW_SIZE / 2)
395 {
396 //very simple implementation of flow control
397 //when the window's size is under the half of the initial value,
398 //increase it again up to the initial value
399
400 //prepare WINDOW_UPDATE
401 if(SPDY_YES == SPDYF_prepare_window_update(session, stream,
402 SPDYF_INITIAL_WINDOW_SIZE - stream->window_size))
403 {
404 stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
405 }
406 //else: do it later
407 }
392 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; 408 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
393 free(frame); 409 free(frame);
394 } 410 }
@@ -751,6 +767,47 @@ SPDYF_handler_write_rst_stream (struct SPDY_Session *session)
751 return SPDY_YES; 767 return SPDY_YES;
752} 768}
753 769
770
771int
772SPDYF_handler_write_window_update (struct SPDY_Session *session)
773{
774 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
775 struct SPDYF_Control_Frame control_frame;
776 size_t total_size;
777
778 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
779
780 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
781
782 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
783 + 4 // stream id as "subheader"
784 + 4; // delta-window-size as "subheader"
785
786 if(NULL == (session->write_buffer = malloc(total_size)))
787 {
788 return SPDY_NO;
789 }
790 session->write_buffer_beginning = 0;
791 session->write_buffer_offset = 0;
792 session->write_buffer_size = total_size;
793
794 control_frame.length = 8; // always for WINDOW_UPDATE
795 SPDYF_CONTROL_FRAME_HTON(&control_frame);
796
797 //put frame headers to write buffer
798 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
799 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
800
801 //put stream id and delta-window-size to write buffer
802 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8);
803 session->write_buffer_offset += 8;
804
805 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
806 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
807
808 return SPDY_YES;
809}
810
754 811
755void 812void
756SPDYF_handler_ignore_frame (struct SPDY_Session *session) 813SPDYF_handler_ignore_frame (struct SPDY_Session *session)
@@ -1638,3 +1695,55 @@ SPDYF_prepare_rst_stream (struct SPDY_Session *session,
1638 1695
1639 return SPDY_YES; 1696 return SPDY_YES;
1640} 1697}
1698
1699
1700int
1701SPDYF_prepare_window_update (struct SPDY_Session *session,
1702 struct SPDYF_Stream * stream,
1703 int32_t delta_window_size)
1704{
1705 struct SPDYF_Response_Queue *response_to_queue;
1706 struct SPDYF_Control_Frame *control_frame;
1707 uint32_t *data;
1708
1709 SPDYF_ASSERT(NULL != stream, "stream cannot be NULL");
1710
1711 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
1712 {
1713 return SPDY_NO;
1714 }
1715 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
1716
1717 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1718 {
1719 free(response_to_queue);
1720 return SPDY_NO;
1721 }
1722 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
1723
1724 if(NULL == (data = malloc(8)))
1725 {
1726 free(control_frame);
1727 free(response_to_queue);
1728 return SPDY_NO;
1729 }
1730 *(data) = HTON31(stream->stream_id);
1731 *(data + 1) = HTON31(delta_window_size);
1732
1733 control_frame->control_bit = 1;
1734 control_frame->version = SPDY_VERSION;
1735 control_frame->type = SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE;
1736 control_frame->flags = 0;
1737
1738 response_to_queue->control_frame = control_frame;
1739 response_to_queue->process_response_handler = &SPDYF_handler_write_window_update;
1740 response_to_queue->data = data;
1741 response_to_queue->data_size = 8;
1742 response_to_queue->stream = stream;
1743
1744 SPDYF_queue_response (response_to_queue,
1745 session,
1746 -1);
1747
1748 return SPDY_YES;
1749}
diff --git a/src/microspdy/session.h b/src/microspdy/session.h
index 6af1ad95..e5c22c9b 100644
--- a/src/microspdy/session.h
+++ b/src/microspdy/session.h
@@ -172,6 +172,23 @@ SPDYF_prepare_rst_stream (struct SPDY_Session *session,
172 172
173 173
174/** 174/**
175 * Prepares WINDOW_UPDATE frame to tell the other party that more
176 * data can be sent on the stream. The frame will be put at the head of
177 * the queue.
178 *
179 * @param session SPDY session
180 * @param stream stream to which the changed window will apply
181 * @param delta_window_size how much the window grows
182 * @return SPDY_NO on memory error or
183 * SPDY_YES on success
184 */
185int
186SPDYF_prepare_window_update (struct SPDY_Session *session,
187 struct SPDYF_Stream * stream,
188 int32_t delta_window_size);
189
190
191/**
175 * Handler called by session_write to fill the write buffer according to 192 * Handler called by session_write to fill the write buffer according to
176 * the data frame waiting in the response queue. 193 * the data frame waiting in the response queue.
177 * When response data is given by user callback, the lib does not know 194 * When response data is given by user callback, the lib does not know
@@ -233,6 +250,20 @@ SPDYF_handler_write_rst_stream (struct SPDY_Session *session);
233 250
234 251
235/** 252/**
253 * Handler called by session_write to fill the write buffer based on the
254 * control frame (WINDOW_UPDATE) waiting in the response queue.
255 *
256 * @param session SPDY session
257 * @return SPDY_NO on error (not enough memory). If
258 * the error is unrecoverable the handler changes session's
259 * status.
260 * SPDY_YES on success
261 */
262int
263SPDYF_handler_write_window_update (struct SPDY_Session *session);
264
265
266/**
236 * Carefully ignore the full size of frames which are not yet supported 267 * Carefully ignore the full size of frames which are not yet supported
237 * by the lib. 268 * by the lib.
238 * TODO Ignoring frames containing compressed bodies means that the 269 * TODO Ignoring frames containing compressed bodies means that the
diff --git a/src/microspdy/stream.c b/src/microspdy/stream.c
index 336672ac..42666960 100644
--- a/src/microspdy/stream.c
+++ b/src/microspdy/stream.c
@@ -104,6 +104,7 @@ SPDYF_stream_new (struct SPDY_Session *session)
104 stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0; 104 stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0;
105 stream->is_out_closed = stream->flag_unidirectional; 105 stream->is_out_closed = stream->flag_unidirectional;
106 stream->is_server_initiator = false; 106 stream->is_server_initiator = false;
107 stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
107 108
108 //put the stream to the list of streams for the session 109 //put the stream to the list of streams for the session
109 DLL_insert(session->streams_head, session->streams_tail, stream); 110 DLL_insert(session->streams_head, session->streams_tail, stream);
diff --git a/src/microspdy/structures.h b/src/microspdy/structures.h
index 1c2a0aaf..8a94dcd3 100644
--- a/src/microspdy/structures.h
+++ b/src/microspdy/structures.h
@@ -554,6 +554,11 @@ struct SPDYF_Stream
554 uint32_t assoc_stream_id; 554 uint32_t assoc_stream_id;
555 555
556 /** 556 /**
557 * The window of the data within data frames.
558 */
559 uint32_t window_size;
560
561 /**
557 * Stream priority. 0 is the highest, 7 is the lowest. 562 * Stream priority. 0 is the highest, 7 is the lowest.
558 */ 563 */
559 uint8_t priority; 564 uint8_t priority;