aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--Makefile.am2
-rw-r--r--README127
-rw-r--r--configure.ac44
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/spdy-draft.txt2856
-rw-r--r--libmicrospdy.pc.in13
-rw-r--r--m4/openssl.m469
-rw-r--r--src/Makefile.am11
-rw-r--r--src/datadir/cert-and-key-for-wireshark.pem15
-rw-r--r--src/datadir/cert-and-key.pem34
-rw-r--r--src/examples/Makefile.am58
-rw-r--r--src/examples/spdy_event_loop.c444
-rw-r--r--src/examples/spdy_fileserver.c340
-rw-r--r--src/examples/spdy_response_with_callback.c230
-rw-r--r--src/include/Makefile.am7
-rw-r--r--src/include/microspdy.h1275
-rw-r--r--src/microspdy/EXPORT.sym2
-rw-r--r--src/microspdy/Makefile.am38
-rw-r--r--src/microspdy/alstructures.c41
-rw-r--r--src/microspdy/alstructures.h79
-rw-r--r--src/microspdy/applicationlayer.c679
-rw-r--r--src/microspdy/applicationlayer.h31
-rw-r--r--src/microspdy/compression.c441
-rw-r--r--src/microspdy/compression.h117
-rw-r--r--src/microspdy/daemon.c515
-rw-r--r--src/microspdy/daemon.h121
-rw-r--r--src/microspdy/internal.c38
-rw-r--r--src/microspdy/internal.h189
-rw-r--r--src/microspdy/session.c1554
-rw-r--r--src/microspdy/session.h248
-rw-r--r--src/microspdy/stream.c151
-rw-r--r--src/microspdy/stream.h65
-rw-r--r--src/microspdy/structures.c612
-rw-r--r--src/microspdy/structures.h1128
-rw-r--r--src/microspdy/tls.c255
-rw-r--r--src/microspdy/tls.h171
-rw-r--r--src/spdy2http/Makefile.am35
-rw-r--r--src/spdy2http/proxy.c625
39 files changed, 12615 insertions, 49 deletions
diff --git a/AUTHORS b/AUTHORS
index 4b420c02..32cedfbc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,5 +1,6 @@
1Primary developers: 1Primary developers:
2Christian Grothoff <christian@grothoff.org> (maintainer) 2Christian Grothoff <christian@grothoff.org> (maintainer)
3Andrey Uzunov <andrey.uzunov@gmail.com> (maintainer for libmicrospdy)
3Nils Durner <durner@gnunet.org> (W32 port) 4Nils Durner <durner@gnunet.org> (W32 port)
4Sagie Amir (TLS/SSL support using GNUtls) 5Sagie Amir (TLS/SSL support using GNUtls)
5Richard Alimi <rich@velvetsea.net> (performance) 6Richard Alimi <rich@velvetsea.net> (performance)
diff --git a/Makefile.am b/Makefile.am
index 001dbec0..5a67d875 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
1ACLOCAL_AMFLAGS = -I m4 1ACLOCAL_AMFLAGS = -I m4
2SUBDIRS = contrib src doc m4 . 2SUBDIRS = contrib src doc m4 .
3EXTRA_DIST = acinclude.m4 libmicrohttpd.pc.in 3EXTRA_DIST = acinclude.m4 libmicrohttpd.pc.in libmicrospdy.pc.in
4 4
5pkgconfigdir = $(libdir)/pkgconfig 5pkgconfigdir = $(libdir)/pkgconfig
6pkgconfig_DATA = libmicrohttpd.pc 6pkgconfig_DATA = libmicrohttpd.pc
diff --git a/README b/README
index 179338bf..5beded78 100644
--- a/README
+++ b/README
@@ -7,6 +7,11 @@ is also supported). GNU libmicrohttpd only implements the HTTP 1.1
7protocol. The main application must still provide the application 7protocol. The main application must still provide the application
8logic to generate the content. 8logic to generate the content.
9 9
10Additionally, a second, still very experimental library is provided
11for SPDY/HTTP 2.0 support. libmicrospdy provides a compact API and
12implementation of SPDY server. libmicrospdy currently only implements
13version 3 of SPDY and accepts only TLS connections.
14
10 15
11Installation 16Installation
12============ 17============
@@ -20,6 +25,21 @@ Especially for development, do use the MHD_USE_DEBUG option to get
20error messages. 25error messages.
21 26
22 27
28Requirements for libmicrospdy
29=============================
30
31The following packages are needed to build libmicrospdy:
32
33* zlib
34* OpenSSL >= 1.0.1
35
36To run the test cases, involving requests, version of Spdylay, supporting
37SPDY v3, is required. Spdylay is still under development and can be
38found here:
39
40http://spdylay.sourceforge.net/
41
42
23Configure options 43Configure options
24================= 44=================
25 45
@@ -53,58 +73,93 @@ must call "MHD_init" before using any MHD functions and "MHD_fini"
53after you are done using MHD. 73after you are done using MHD.
54 74
55 75
56Notes on compiling on z/OS:
57---------------------------
58
59After extracting the archive, run
60
61iconv -f UTF-8 -t IBM-1047 contrib/ascebc > /tmp/ascebc.sh
62chmod +x /tmp/ascebc.sh
63for n in `find * -type f`
64do
65 /tmp/ascebc.sh $n
66done
67
68to convert all source files to EBCDIC. Note that you must run
69"configure" from the directory where the configure script is
70located. Otherwise, configure will fail to find the
71"contrib/xcc" script (which is a wrapper around the z/OS c89
72compiler).
73
74
75Development Status 76Development Status
76================== 77==================
77 78
78This is a beta release. Below we list things that should be 79This is a beta release for libmicrohttpd. Before declaring the
79implemented (in order of importance) before we can claim to be 80library stable, we should implement support for HTTP "Upgrade"
80reasonably complete. 81requests and have testcases for the following features:
81
82 82
83Untested features: 83- HTTP/1.1 pipelining (need to figure out how to ensure curl pipelines
84==================
85- add testcases for http/1.1 pipelining (need
86 to figure out how to ensure curl pipelines
87 -- and it seems libcurl has issues with pipelining, 84 -- and it seems libcurl has issues with pipelining,
88 see http://curl.haxx.se/mail/lib-2007-12/0248.html) 85 see http://curl.haxx.se/mail/lib-2007-12/0248.html)
89- add testcases for resource limit enforcement 86- resource limit enforcement
90- add testcases for client queuing early response, 87- client queuing early response, suppressing 100 CONTINUE
91 suppressing 100 CONTINUE 88- chunked encoding to validate handling of footers
92- extend testcase for chunked encoding to validate
93 handling of footers
94- more testing for SSL support 89- more testing for SSL support
95- MHD basic and digest authentication 90- MHD basic and digest authentication
96 91
97 92In particular, the following functions are not covered by 'make check':
98Functions not covered by "make check":
99======================================
100- mhd_panic_std (daemon.c); special case (abort) 93- mhd_panic_std (daemon.c); special case (abort)
101- parse_options (daemon.c) 94- parse_options (daemon.c)
102- MHD_set_panic_func (daemon.c) 95- MHD_set_panic_func (daemon.c)
103- MHD_get_version (daemon.c) 96- MHD_get_version (daemon.c)
104 97
105 98
99This is an early alpha release for libmicrospdy. The following things
100should be implemented (in order of importance) before we can claim to
101be reasonably complete:
102- Change session timeout to use not seconds but something more precise
103- SPDY RST_STREAM sending on each possible error (DONE?)
104- SPDY_close_session
105- Find the best way for closing still opened stream (new call or existing)
106- SPDY_is_stream_opened
107- SPDY PING (used often by browsers)
108- SPDY WINDOW_UPDATE - used often by browsers
109- SPDY Settings
110- SPDY PUSH
111- SPDY HEADERS
112- HTTP POST over SPDY and receiving DATA frames
113- HTTP PUT over SPDY
114- SPDY Credentials
115
116Additional ideas for features include:
117- Individual callbacks for each session
118- Individual timeout for each session
119- Setting number of frames that can be written to the output at once.
120 A big number means faster sending of a big resource, but the other
121 sessions will wait longer.
122
123Unimplemented API functions of libmicrospdy:
124- SPDY_settings_create ();
125- SPDY_settings_add (...);
126- SPDY_settings_lookup (...);
127- SPDY_settings_iterate (...);
128- SPDY_settings_destroy (...);
129- SPDY_close_session(...);
130- SPDY_send_ping(...);
131- SPDY_send_settings (...);
132
133In particular, we should write tests for:
134- Enqueueing responses while considering request priorities.
135
136
137
138
139
106Missing documentation: 140Missing documentation:
107====================== 141======================
108 142
109- manual: 143- libmicrohttpd manual:
110 * document details on porting MHD (plibc, z/OS) 144 * document details on porting MHD (plibc, z/OS)
145- libmicrospdy manual:
146 * missing entirely
147
148
149Notes on compiling on z/OS:
150===========================
151
152After extracting the archive, run
153
154iconv -f UTF-8 -t IBM-1047 contrib/ascebc > /tmp/ascebc.sh
155chmod +x /tmp/ascebc.sh
156for n in `find * -type f`
157do
158 /tmp/ascebc.sh $n
159done
160
161to convert all source files to EBCDIC. Note that you must run
162"configure" from the directory where the configure script is
163located. Otherwise, configure will fail to find the
164"contrib/xcc" script (which is a wrapper around the z/OS c89
165compiler).
diff --git a/configure.ac b/configure.ac
index 91e0a96e..6f2a7851 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,6 +34,14 @@ AC_SUBST(LIB_VERSION_CURRENT)
34AC_SUBST(LIB_VERSION_REVISION) 34AC_SUBST(LIB_VERSION_REVISION)
35AC_SUBST(LIB_VERSION_AGE) 35AC_SUBST(LIB_VERSION_AGE)
36 36
37LIBSPDY_VERSION_CURRENT=0
38LIBSPDY_VERSION_REVISION=0
39LIBSPDY_VERSION_AGE=0
40AC_SUBST(LIBSPDY_VERSION_CURRENT)
41AC_SUBST(LIBSPDY_VERSION_REVISION)
42AC_SUBST(LIBSPDY_VERSION_AGE)
43
44
37if test `uname -s` = "OS/390" 45if test `uname -s` = "OS/390"
38then 46then
39# configure binaries for z/OS 47# configure binaries for z/OS
@@ -263,6 +271,39 @@ AC_CHECK_LIB(magic, magic_open,
263 AM_CONDITIONAL(HAVE_MAGIC, false))], 271 AM_CONDITIONAL(HAVE_MAGIC, false))],
264 AM_CONDITIONAL(HAVE_MAGIC, false)) 272 AM_CONDITIONAL(HAVE_MAGIC, false))
265 273
274
275# optional: libmicrospdy support. Enabled by default
276AC_MSG_CHECKING(whether to support libmicrospdy)
277AC_ARG_ENABLE([spdy],
278 AS_HELP_STRING([--disable-spdy],
279 [disable libmicrospdy]),
280 [enable_spdy=${enableval}],
281 [enable_spdy=yes])
282if test "$enable_spdy" = "yes"
283then
284 AC_DEFINE([SPDY_SUPPORT],[1],[include libmicrospdy support])
285else
286 AC_DEFINE([SPDY_SUPPORT],[0],[disable libmicrospdy support])
287fi
288AC_MSG_RESULT($enable_spdy)
289AM_CONDITIONAL(ENABLE_SPDY, [test "x$enable_spdy" != "xno"])
290
291spdy_OPENSSL
292# for pkg-config
293SPDY_LIBDEPS=""
294
295
296AC_SUBST(SPDY_LIB_LDFLAGS)
297# for pkg-config
298AC_SUBST(SPDY_LIBDEPS)
299
300AM_CONDITIONAL(ENABLE_MINITASN1, [test -n " " ] )
301AM_CONDITIONAL(ENABLE_OPENSSL, [test -n "" ] )
302AM_CONDITIONAL(HAVE_LD_OUTPUT_DEF, [test -n "" ] )
303AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, [test -n "" ] )
304
305
306
266LIBS=$SAVE_LIBS 307LIBS=$SAVE_LIBS
267AM_CONDITIONAL(HAVE_CURL, test x$curl = x1) 308AM_CONDITIONAL(HAVE_CURL, test x$curl = x1)
268 309
@@ -450,9 +491,12 @@ src/Makefile
450src/include/Makefile 491src/include/Makefile
451src/include/plibc/Makefile 492src/include/plibc/Makefile
452src/microhttpd/Makefile 493src/microhttpd/Makefile
494src/microspdy/Makefile
495src/spdy2http/Makefile
453src/examples/Makefile 496src/examples/Makefile
454src/testcurl/Makefile 497src/testcurl/Makefile
455src/testcurl/https/Makefile 498src/testcurl/https/Makefile
499src/testspdy/Makefile
456src/testzzuf/Makefile]) 500src/testzzuf/Makefile])
457AC_OUTPUT 501AC_OUTPUT
458 502
diff --git a/doc/Makefile.am b/doc/Makefile.am
index ed20c875..7db03ce5 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -25,4 +25,5 @@ microhttpd_TEXINFOS = \
25 lgpl.texi \ 25 lgpl.texi \
26 ecos.texi 26 ecos.texi
27 27
28EXTRA_DIST = $(man_MANS) Doxyfile $(microhttpd_TEXINFOS) 28EXTRA_DIST = $(man_MANS) Doxyfile $(microhttpd_TEXINFOS) spdy-draft.txt
29
diff --git a/doc/spdy-draft.txt b/doc/spdy-draft.txt
new file mode 100644
index 00000000..c31648cc
--- /dev/null
+++ b/doc/spdy-draft.txt
@@ -0,0 +1,2856 @@
1
2
3
4Network Working Group M. Belshe
5Internet-Draft Twist
6Expires: August 4, 2012 R. Peon
7 Google, Inc
8 Feb 2012
9
10
11 SPDY Protocol
12 draft-mbelshe-httpbis-spdy-00
13
14Abstract
15
16 This document describes SPDY, a protocol designed for low-latency
17 transport of content over the World Wide Web. SPDY introduces two
18 layers of protocol. The lower layer is a general purpose framing
19 layer which can be used atop a reliable transport (likely TCP) for
20 multiplexed, prioritized, and compressed data communication of many
21 concurrent streams. The upper layer of the protocol provides HTTP-
22 like RFC2616 [RFC2616] semantics for compatibility with existing HTTP
23 application servers.
24
25Status of this Memo
26
27 This Internet-Draft is submitted in full conformance with the
28 provisions of BCP 78 and BCP 79.
29
30 Internet-Drafts are working documents of the Internet Engineering
31 Task Force (IETF). Note that other groups may also distribute
32 working documents as Internet-Drafts. The list of current Internet-
33 Drafts is at http://datatracker.ietf.org/drafts/current/.
34
35 Internet-Drafts are draft documents valid for a maximum of six months
36 and may be updated, replaced, or obsoleted by other documents at any
37 time. It is inappropriate to use Internet-Drafts as reference
38 material or to cite them other than as "work in progress."
39
40 This Internet-Draft will expire on August 4, 2012.
41
42Copyright Notice
43
44 Copyright (c) 2012 IETF Trust and the persons identified as the
45 document authors. All rights reserved.
46
47 This document is subject to BCP 78 and the IETF Trust's Legal
48 Provisions Relating to IETF Documents
49 (http://trustee.ietf.org/license-info) in effect on the date of
50 publication of this document. Please review these documents
51 carefully, as they describe your rights and restrictions with respect
52
53
54
55Belshe & Peon Expires August 4, 2012 [Page 1]
56
57Internet-Draft SPDY Feb 2012
58
59
60 to this document. Code Components extracted from this document must
61 include Simplified BSD License text as described in Section 4.e of
62 the Trust Legal Provisions and are provided without warranty as
63 described in the Simplified BSD License.
64
65
66Table of Contents
67
68 1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
69 1.1. Document Organization . . . . . . . . . . . . . . . . . . 4
70 1.2. Definitions . . . . . . . . . . . . . . . . . . . . . . . 5
71 2. SPDY Framing Layer . . . . . . . . . . . . . . . . . . . . . . 6
72 2.1. Session (Connections) . . . . . . . . . . . . . . . . . . 6
73 2.2. Framing . . . . . . . . . . . . . . . . . . . . . . . . . 6
74 2.2.1. Control frames . . . . . . . . . . . . . . . . . . . . 6
75 2.2.2. Data frames . . . . . . . . . . . . . . . . . . . . . 7
76 2.3. Streams . . . . . . . . . . . . . . . . . . . . . . . . . 8
77 2.3.1. Stream frames . . . . . . . . . . . . . . . . . . . . 9
78 2.3.2. Stream creation . . . . . . . . . . . . . . . . . . . 9
79 2.3.3. Stream priority . . . . . . . . . . . . . . . . . . . 10
80 2.3.4. Stream headers . . . . . . . . . . . . . . . . . . . . 10
81 2.3.5. Stream data exchange . . . . . . . . . . . . . . . . . 10
82 2.3.6. Stream half-close . . . . . . . . . . . . . . . . . . 10
83 2.3.7. Stream close . . . . . . . . . . . . . . . . . . . . . 11
84 2.4. Error Handling . . . . . . . . . . . . . . . . . . . . . . 11
85 2.4.1. Session Error Handling . . . . . . . . . . . . . . . . 11
86 2.4.2. Stream Error Handling . . . . . . . . . . . . . . . . 12
87 2.5. Data flow . . . . . . . . . . . . . . . . . . . . . . . . 12
88 2.6. Control frame types . . . . . . . . . . . . . . . . . . . 12
89 2.6.1. SYN_STREAM . . . . . . . . . . . . . . . . . . . . . . 12
90 2.6.2. SYN_REPLY . . . . . . . . . . . . . . . . . . . . . . 14
91 2.6.3. RST_STREAM . . . . . . . . . . . . . . . . . . . . . . 15
92 2.6.4. SETTINGS . . . . . . . . . . . . . . . . . . . . . . . 16
93 2.6.5. PING . . . . . . . . . . . . . . . . . . . . . . . . . 19
94 2.6.6. GOAWAY . . . . . . . . . . . . . . . . . . . . . . . . 20
95 2.6.7. HEADERS . . . . . . . . . . . . . . . . . . . . . . . 21
96 2.6.8. WINDOW_UPDATE . . . . . . . . . . . . . . . . . . . . 22
97 2.6.9. CREDENTIAL . . . . . . . . . . . . . . . . . . . . . . 24
98 2.6.10. Name/Value Header Block . . . . . . . . . . . . . . . 26
99 3. HTTP Layering over SPDY . . . . . . . . . . . . . . . . . . . 33
100 3.1. Connection Management . . . . . . . . . . . . . . . . . . 33
101 3.1.1. Use of GOAWAY . . . . . . . . . . . . . . . . . . . . 33
102 3.2. HTTP Request/Response . . . . . . . . . . . . . . . . . . 34
103 3.2.1. Request . . . . . . . . . . . . . . . . . . . . . . . 34
104 3.2.2. Response . . . . . . . . . . . . . . . . . . . . . . . 35
105 3.2.3. Authentication . . . . . . . . . . . . . . . . . . . . 36
106 3.3. Server Push Transactions . . . . . . . . . . . . . . . . . 37
107 3.3.1. Server implementation . . . . . . . . . . . . . . . . 38
108
109
110
111Belshe & Peon Expires August 4, 2012 [Page 2]
112
113Internet-Draft SPDY Feb 2012
114
115
116 3.3.2. Client implementation . . . . . . . . . . . . . . . . 39
117 4. Design Rationale and Notes . . . . . . . . . . . . . . . . . . 40
118 4.1. Separation of Framing Layer and Application Layer . . . . 40
119 4.2. Error handling - Framing Layer . . . . . . . . . . . . . . 40
120 4.3. One Connection Per Domain . . . . . . . . . . . . . . . . 40
121 4.4. Fixed vs Variable Length Fields . . . . . . . . . . . . . 41
122 4.5. Compression Context(s) . . . . . . . . . . . . . . . . . . 41
123 4.6. Unidirectional streams . . . . . . . . . . . . . . . . . . 42
124 4.7. Data Compression . . . . . . . . . . . . . . . . . . . . . 42
125 4.8. Server Push . . . . . . . . . . . . . . . . . . . . . . . 42
126 5. Security Considerations . . . . . . . . . . . . . . . . . . . 43
127 5.1. Use of Same-origin constraints . . . . . . . . . . . . . . 43
128 5.2. HTTP Headers and SPDY Headers . . . . . . . . . . . . . . 43
129 5.3. Cross-Protocol Attacks . . . . . . . . . . . . . . . . . . 43
130 5.4. Server Push Implicit Headers . . . . . . . . . . . . . . . 43
131 6. Privacy Considerations . . . . . . . . . . . . . . . . . . . . 44
132 6.1. Long Lived Connections . . . . . . . . . . . . . . . . . . 44
133 6.2. SETTINGS frame . . . . . . . . . . . . . . . . . . . . . . 44
134 7. Incompatibilities with SPDY draft #2 . . . . . . . . . . . . . 45
135 8. Requirements Notation . . . . . . . . . . . . . . . . . . . . 46
136 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 47
137 10. Normative References . . . . . . . . . . . . . . . . . . . . . 48
138 Appendix A. Changes . . . . . . . . . . . . . . . . . . . . . . . 50
139 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 51
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167Belshe & Peon Expires August 4, 2012 [Page 3]
168
169Internet-Draft SPDY Feb 2012
170
171
1721. Overview
173
174 One of the bottlenecks of HTTP implementations is that HTTP relies on
175 multiple connections for concurrency. This causes several problems,
176 including additional round trips for connection setup, slow-start
177 delays, and connection rationing by the client, where it tries to
178 avoid opening too many connections to any single server. HTTP
179 pipelining helps some, but only achieves partial multiplexing. In
180 addition, pipelining has proven non-deployable in existing browsers
181 due to intermediary interference.
182
183 SPDY adds a framing layer for multiplexing multiple, concurrent
184 streams across a single TCP connection (or any reliable transport
185 stream). The framing layer is optimized for HTTP-like request-
186 response streams, such that applications which run over HTTP today
187 can work over SPDY with little or no change on behalf of the web
188 application writer.
189
190 The SPDY session offers four improvements over HTTP:
191
192 Multiplexed requests: There is no limit to the number of requests
193 that can be issued concurrently over a single SPDY connection.
194
195 Prioritized requests: Clients can request certain resources to be
196 delivered first. This avoids the problem of congesting the
197 network channel with non-critical resources when a high-priority
198 request is pending.
199
200 Compressed headers: Clients today send a significant amount of
201 redundant data in the form of HTTP headers. Because a single web
202 page may require 50 or 100 subrequests, this data is significant.
203
204 Server pushed streams: Server Push enables content to be pushed
205 from servers to clients without a request.
206
207 SPDY attempts to preserve the existing semantics of HTTP. All
208 features such as cookies, ETags, Vary headers, Content-Encoding
209 negotiations, etc work as they do with HTTP; SPDY only replaces the
210 way the data is written to the network.
211
2121.1. Document Organization
213
214 The SPDY Specification is split into two parts: a framing layer
215 (Section 2), which multiplexes a TCP connection into independent,
216 length-prefixed frames, and an HTTP layer (Section 3), which
217 specifies the mechanism for overlaying HTTP request/response pairs on
218 top of the framing layer. While some of the framing layer concepts
219 are isolated from the HTTP layer, building a generic framing layer
220
221
222
223Belshe & Peon Expires August 4, 2012 [Page 4]
224
225Internet-Draft SPDY Feb 2012
226
227
228 has not been a goal. The framing layer is tailored to the needs of
229 the HTTP protocol and server push.
230
2311.2. Definitions
232
233 client: The endpoint initiating the SPDY session.
234
235 connection: A transport-level connection between two endpoints.
236
237 endpoint: Either the client or server of a connection.
238
239 frame: A header-prefixed sequence of bytes sent over a SPDY
240 session.
241
242 server: The endpoint which did not initiate the SPDY session.
243
244 session: A synonym for a connection.
245
246 session error: An error on the SPDY session.
247
248 stream: A bi-directional flow of bytes across a virtual channel
249 within a SPDY session.
250
251 stream error: An error on an individual SPDY stream.
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279Belshe & Peon Expires August 4, 2012 [Page 5]
280
281Internet-Draft SPDY Feb 2012
282
283
2842. SPDY Framing Layer
285
2862.1. Session (Connections)
287
288 The SPDY framing layer (or "session") runs atop a reliable transport
289 layer such as TCP [RFC0793]. The client is the TCP connection
290 initiator. SPDY connections are persistent connections.
291
292 For best performance, it is expected that clients will not close open
293 connections until the user navigates away from all web pages
294 referencing a connection, or until the server closes the connection.
295 Servers are encouraged to leave connections open for as long as
296 possible, but can terminate idle connections if necessary. When
297 either endpoint closes the transport-level connection, it MUST first
298 send a GOAWAY (Section 2.6.6) frame so that the endpoints can
299 reliably determine if requests finished before the close.
300
3012.2. Framing
302
303 Once the connection is established, clients and servers exchange
304 framed messages. There are two types of frames: control frames
305 (Section 2.2.1) and data frames (Section 2.2.2). Frames always have
306 a common header which is 8 bytes in length.
307
308 The first bit is a control bit indicating whether a frame is a
309 control frame or data frame. Control frames carry a version number,
310 a frame type, flags, and a length. Data frames contain the stream
311 ID, flags, and the length for the payload carried after the common
312 header. The simple header is designed to make reading and writing of
313 frames easy.
314
315 All integer values, including length, version, and type, are in
316 network byte order. SPDY does not enforce alignment of types in
317 dynamically sized frames.
318
3192.2.1. Control frames
320
321 +----------------------------------+
322 |C| Version(15bits) | Type(16bits) |
323 +----------------------------------+
324 | Flags (8) | Length (24 bits) |
325 +----------------------------------+
326 | Data |
327 +----------------------------------+
328
329 Control bit: The 'C' bit is a single bit indicating if this is a
330 control message. For control frames this value is always 1.
331
332
333
334
335Belshe & Peon Expires August 4, 2012 [Page 6]
336
337Internet-Draft SPDY Feb 2012
338
339
340 Version: The version number of the SPDY protocol. This document
341 describes SPDY version 3.
342
343 Type: The type of control frame. See Control Frames for the complete
344 list of control frames.
345
346 Flags: Flags related to this frame. Flags for control frames and
347 data frames are different.
348
349 Length: An unsigned 24-bit value representing the number of bytes
350 after the length field.
351
352 Data: data associated with this control frame. The format and length
353 of this data is controlled by the control frame type.
354
355 Control frame processing requirements:
356
357 Note that full length control frames (16MB) can be large for
358 implementations running on resource-limited hardware. In such
359 cases, implementations MAY limit the maximum length frame
360 supported. However, all implementations MUST be able to receive
361 control frames of at least 8192 octets in length.
362
3632.2.2. Data frames
364
365 +----------------------------------+
366 |C| Stream-ID (31bits) |
367 +----------------------------------+
368 | Flags (8) | Length (24 bits) |
369 +----------------------------------+
370 | Data |
371 +----------------------------------+
372
373 Control bit: For data frames this value is always 0.
374
375 Stream-ID: A 31-bit value identifying the stream.
376
377 Flags: Flags related to this frame. Valid flags are:
378
379 0x01 = FLAG_FIN - signifies that this frame represents the last
380 frame to be transmitted on this stream. See Stream Close
381 (Section 2.3.7) below.
382
383 0x02 = FLAG_COMPRESS - indicates that the data in this frame has
384 been compressed.
385
386 Length: An unsigned 24-bit value representing the number of bytes
387 after the length field. The total size of a data frame is 8 bytes +
388
389
390
391Belshe & Peon Expires August 4, 2012 [Page 7]
392
393Internet-Draft SPDY Feb 2012
394
395
396 length. It is valid to have a zero-length data frame.
397
398 Data: The variable-length data payload; the length was defined in the
399 length field.
400
401 Data frame processing requirements:
402
403 If an endpoint receives a data frame for a stream-id which is not
404 open and the endpoint has not sent a GOAWAY (Section 2.6.6) frame,
405 it MUST send issue a stream error (Section 2.4.2) with the error
406 code INVALID_STREAM for the stream-id.
407
408 If the endpoint which created the stream receives a data frame
409 before receiving a SYN_REPLY on that stream, it is a protocol
410 error, and the recipient MUST issue a stream error (Section 2.4.2)
411 with the status code PROTOCOL_ERROR for the stream-id.
412
413 Implementors note: If an endpoint receives multiple data frames
414 for invalid stream-ids, it MAY close the session.
415
416 All SPDY endpoints MUST accept compressed data frames.
417 Compression of data frames is always done using zlib compression.
418 Each stream initializes and uses its own compression context
419 dedicated to use within that stream. Endpoints are encouraged to
420 use application level compression rather than SPDY stream level
421 compression.
422
423 Each SPDY stream sending compressed frames creates its own zlib
424 context for that stream, and these compression contexts MUST be
425 distinct from the compression contexts used with SYN_STREAM/
426 SYN_REPLY/HEADER compression. (Thus, if both endpoints of a
427 stream are compressing data on the stream, there will be two zlib
428 contexts, one for sending and one for receiving).
429
4302.3. Streams
431
432 Streams are independent sequences of bi-directional data divided into
433 frames with several properties:
434
435 Streams may be created by either the client or server.
436
437 Streams optionally carry a set of name/value header pairs.
438
439 Streams can concurrently send data interleaved with other streams.
440
441 Streams may be cancelled.
442
443
444
445
446
447Belshe & Peon Expires August 4, 2012 [Page 8]
448
449Internet-Draft SPDY Feb 2012
450
451
4522.3.1. Stream frames
453
454 SPDY defines 3 control frames to manage the lifecycle of a stream:
455
456 SYN_STREAM - Open a new stream
457
458 SYN_REPLY - Remote acknowledgement of a new, open stream
459
460 RST_STREAM - Close a stream
461
4622.3.2. Stream creation
463
464 A stream is created by sending a control frame with the type set to
465 SYN_STREAM (Section 2.6.1). If the server is initiating the stream,
466 the Stream-ID must be even. If the client is initiating the stream,
467 the Stream-ID must be odd. 0 is not a valid Stream-ID. Stream-IDs
468 from each side of the connection must increase monotonically as new
469 streams are created. E.g. Stream 2 may be created after stream 3,
470 but stream 7 must not be created after stream 9. Stream IDs do not
471 wrap: when a client or server cannot create a new stream id without
472 exceeding a 31 bit value, it MUST NOT create a new stream.
473
474 The stream-id MUST increase with each new stream. If an endpoint
475 receives a SYN_STREAM with a stream id which is less than any
476 previously received SYN_STREAM, it MUST issue a session error
477 (Section 2.4.1) with the status PROTOCOL_ERROR.
478
479 It is a protocol error to send two SYN_STREAMs with the same
480 stream-id. If a recipient receives a second SYN_STREAM for the same
481 stream, it MUST issue a stream error (Section 2.4.2) with the status
482 code PROTOCOL_ERROR.
483
484 Upon receipt of a SYN_STREAM, the recipient can reject the stream by
485 sending a stream error (Section 2.4.2) with the error code
486 REFUSED_STREAM. Note, however, that the creating endpoint may have
487 already sent additional frames for that stream which cannot be
488 immediately stopped.
489
490 Once the stream is created, the creator may immediately send HEADERS
491 or DATA frames for that stream, without needing to wait for the
492 recipient to acknowledge.
493
4942.3.2.1. Unidirectional streams
495
496 When an endpoint creates a stream with the FLAG_UNIDIRECTIONAL flag
497 set, it creates a unidirectional stream which the creating endpoint
498 can use to send frames, but the receiving endpoint cannot. The
499 receiving endpoint is implicitly already in the half-closed
500
501
502
503Belshe & Peon Expires August 4, 2012 [Page 9]
504
505Internet-Draft SPDY Feb 2012
506
507
508 (Section 2.3.6) state.
509
5102.3.2.2. Bidirectional streams
511
512 SYN_STREAM frames which do not use the FLAG_UNIDIRECTIONAL flag are
513 bidirectional streams. Both endpoints can send data on a bi-
514 directional stream.
515
5162.3.3. Stream priority
517
518 The creator of a stream assigns a priority for that stream. Priority
519 is represented as an integer from 0 to 7. 0 represents the highest
520 priority and 7 represents the lowest priority.
521
522 The sender and recipient SHOULD use best-effort to process streams in
523 the order of highest priority to lowest priority.
524
5252.3.4. Stream headers
526
527 Streams carry optional sets of name/value pair headers which carry
528 metadata about the stream. After the stream has been created, and as
529 long as the sender is not closed (Section 2.3.7) or half-closed
530 (Section 2.3.6), each side may send HEADERS frame(s) containing the
531 header data. Header data can be sent in multiple HEADERS frames, and
532 HEADERS frames may be interleaved with data frames.
533
5342.3.5. Stream data exchange
535
536 Once a stream is created, it can be used to send arbitrary amounts of
537 data. Generally this means that a series of data frames will be sent
538 on the stream until a frame containing the FLAG_FIN flag is set. The
539 FLAG_FIN can be set on a SYN_STREAM (Section 2.6.1), SYN_REPLY
540 (Section 2.6.2), HEADERS (Section 2.6.7) or a DATA (Section 2.2.2)
541 frame. Once the FLAG_FIN has been sent, the stream is considered to
542 be half-closed.
543
5442.3.6. Stream half-close
545
546 When one side of the stream sends a frame with the FLAG_FIN flag set,
547 the stream is half-closed from that endpoint. The sender of the
548 FLAG_FIN MUST NOT send further frames on that stream. When both
549 sides have half-closed, the stream is closed.
550
551 If an endpoint receives a data frame after the stream is half-closed
552 from the sender (e.g. the endpoint has already received a prior frame
553 for the stream with the FIN flag set), it MUST send a RST_STREAM to
554 the sender with the status STREAM_ALREADY_CLOSED.
555
556
557
558
559Belshe & Peon Expires August 4, 2012 [Page 10]
560
561Internet-Draft SPDY Feb 2012
562
563
5642.3.7. Stream close
565
566 There are 3 ways that streams can be terminated:
567
568 Normal termination: Normal stream termination occurs when both
569 sender and recipient have half-closed the stream by sending a
570 FLAG_FIN.
571
572 Abrupt termination: Either the client or server can send a
573 RST_STREAM control frame at any time. A RST_STREAM contains an
574 error code to indicate the reason for failure. When a RST_STREAM
575 is sent from the stream originator, it indicates a failure to
576 complete the stream and that no further data will be sent on the
577 stream. When a RST_STREAM is sent from the stream recipient, the
578 sender, upon receipt, should stop sending any data on the stream.
579 The stream recipient should be aware that there is a race between
580 data already in transit from the sender and the time the
581 RST_STREAM is received. See Stream Error Handling (Section 2.4.2)
582
583 TCP connection teardown: If the TCP connection is torn down while
584 un-closed streams exist, then the endpoint must assume that the
585 stream was abnormally interrupted and may be incomplete.
586
587 If an endpoint receives a data frame after the stream is closed, it
588 must send a RST_STREAM to the sender with the status PROTOCOL_ERROR.
589
5902.4. Error Handling
591
592 The SPDY framing layer has only two types of errors, and they are
593 always handled consistently. Any reference in this specification to
594 "issue a session error" refers to Section 2.4.1. Any reference to
595 "issue a stream error" refers to Section 2.4.2.
596
5972.4.1. Session Error Handling
598
599 A session error is any error which prevents further processing of the
600 framing layer or which corrupts the session compression state. When
601 a session error occurs, the endpoint encountering the error MUST
602 first send a GOAWAY (Section 2.6.6) frame with the stream id of most
603 recently received stream from the remote endpoint, and the error code
604 for why the session is terminating. After sending the GOAWAY frame,
605 the endpoint MUST close the TCP connection.
606
607 Note that the session compression state is dependent upon both
608 endpoints always processing all compressed data. If an endpoint
609 partially processes a frame containing compressed data without
610 updating compression state properly, future control frames which use
611 compression will be always be errored. Implementations SHOULD always
612
613
614
615Belshe & Peon Expires August 4, 2012 [Page 11]
616
617Internet-Draft SPDY Feb 2012
618
619
620 try to process compressed data so that errors which could be handled
621 as stream errors do not become session errors.
622
623 Note that because this GOAWAY is sent during a session error case, it
624 is possible that the GOAWAY will not be reliably received by the
625 receiving endpoint. It is a best-effort attempt to communicate with
626 the remote about why the session is going down.
627
6282.4.2. Stream Error Handling
629
630 A stream error is an error related to a specific stream-id which does
631 not affect processing of other streams at the framing layer. Upon a
632 stream error, the endpoint MUST send a RST_STREAM (Section 2.6.3)
633 frame which contains the stream id of the stream where the error
634 occurred and the error status which caused the error. After sending
635 the RST_STREAM, the stream is closed to the sending endpoint. After
636 sending the RST_STREAM, if the sender receives any frames other than
637 a RST_STREAM for that stream id, it will result in sending additional
638 RST_STREAM frames. An endpoint MUST NOT send a RST_STREAM in
639 response to an RST_STREAM, as doing so would lead to RST_STREAM
640 loops. Sending a RST_STREAM does not cause the SPDY session to be
641 closed.
642
643 If an endpoint has multiple RST_STREAM frames to send in succession
644 for the same stream-id and the same error code, it MAY coalesce them
645 into a single RST_STREAM frame. (This can happen if a stream is
646 closed, but the remote sends multiple data frames. There is no
647 reason to send a RST_STREAM for each frame in succession).
648
6492.5. Data flow
650
651 Because TCP provides a single stream of data on which SPDY
652 multiplexes multiple logical streams, clients and servers must
653 intelligently interleave data messages for concurrent sessions.
654
6552.6. Control frame types
656
6572.6.1. SYN_STREAM
658
659 The SYN_STREAM control frame allows the sender to asynchronously
660 create a stream between the endpoints. See Stream Creation
661 (Section 2.3.2)
662
663
664
665
666
667
668
669
670
671Belshe & Peon Expires August 4, 2012 [Page 12]
672
673Internet-Draft SPDY Feb 2012
674
675
676+------------------------------------+
677|1| version | 1 |
678+------------------------------------+
679| Flags (8) | Length (24 bits) |
680+------------------------------------+
681|X| Stream-ID (31bits) |
682+------------------------------------+
683|X| Associated-To-Stream-ID (31bits) |
684+------------------------------------+
685| Pri|Unused | Slot | |
686+-------------------+ |
687| Number of Name/Value pairs (int32) | <+
688+------------------------------------+ |
689| Length of name (int32) | | This section is the "Name/Value
690+------------------------------------+ | Header Block", and is compressed.
691| Name (string) | |
692+------------------------------------+ |
693| Length of value (int32) | |
694+------------------------------------+ |
695| Value (string) | |
696+------------------------------------+ |
697| (repeats) | <+
698
699 Flags: Flags related to this frame. Valid flags are:
700
701 0x01 = FLAG_FIN - marks this frame as the last frame to be
702 transmitted on this stream and puts the sender in the half-closed
703 (Section 2.3.6) state.
704
705 0x02 = FLAG_UNIDIRECTIONAL - a stream created with this flag puts
706 the recipient in the half-closed (Section 2.3.6) state.
707
708 Length: The length is the number of bytes which follow the length
709 field in the frame. For SYN_STREAM frames, this is 10 bytes plus the
710 length of the compressed Name/Value block.
711
712 Stream-ID: The 31-bit identifier for this stream. This stream-id
713 will be used in frames which are part of this stream.
714
715 Associated-To-Stream-ID: The 31-bit identifier for a stream which
716 this stream is associated to. If this stream is independent of all
717 other streams, it should be 0.
718
719 Priority: A 3-bit priority (Section 2.3.3) field.
720
721 Unused: 5 bits of unused space, reserved for future use.
722
723 Slot: An 8 bit unsigned integer specifying the index in the server's
724
725
726
727Belshe & Peon Expires August 4, 2012 [Page 13]
728
729Internet-Draft SPDY Feb 2012
730
731
732 CREDENTIAL vector of the client certificate to be used for this
733 request. see CREDENTIAL frame (Section 2.6.9). The value 0 means no
734 client certificate should be associated with this stream.
735
736 Name/Value Header Block: A set of name/value pairs carried as part of
737 the SYN_STREAM. see Name/Value Header Block (Section 2.6.10).
738
739 If an endpoint receives a SYN_STREAM which is larger than the
740 implementation supports, it MAY send a RST_STREAM with error code
741 FRAME_TOO_LARGE. All implementations MUST support the minimum size
742 limits defined in the Control Frames section (Section 2.2.1).
743
7442.6.2. SYN_REPLY
745
746 SYN_REPLY indicates the acceptance of a stream creation by the
747 recipient of a SYN_STREAM frame.
748
749+------------------------------------+
750|1| version | 2 |
751+------------------------------------+
752| Flags (8) | Length (24 bits) |
753+------------------------------------+
754|X| Stream-ID (31bits) |
755+------------------------------------+
756| Number of Name/Value pairs (int32) | <+
757+------------------------------------+ |
758| Length of name (int32) | | This section is the "Name/Value
759+------------------------------------+ | Header Block", and is compressed.
760| Name (string) | |
761+------------------------------------+ |
762| Length of value (int32) | |
763+------------------------------------+ |
764| Value (string) | |
765+------------------------------------+ |
766| (repeats) | <+
767
768 Flags: Flags related to this frame. Valid flags are:
769
770 0x01 = FLAG_FIN - marks this frame as the last frame to be
771 transmitted on this stream and puts the sender in the half-closed
772 (Section 2.3.6) state.
773
774 Length: The length is the number of bytes which follow the length
775 field in the frame. For SYN_REPLY frames, this is 4 bytes plus the
776 length of the compressed Name/Value block.
777
778 Stream-ID: The 31-bit identifier for this stream.
779
780
781
782
783Belshe & Peon Expires August 4, 2012 [Page 14]
784
785Internet-Draft SPDY Feb 2012
786
787
788 If an endpoint receives multiple SYN_REPLY frames for the same active
789 stream ID, it MUST issue a stream error (Section 2.4.2) with the
790 error code STREAM_IN_USE.
791
792 Name/Value Header Block: A set of name/value pairs carried as part of
793 the SYN_STREAM. see Name/Value Header Block (Section 2.6.10).
794
795 If an endpoint receives a SYN_REPLY which is larger than the
796 implementation supports, it MAY send a RST_STREAM with error code
797 FRAME_TOO_LARGE. All implementations MUST support the minimum size
798 limits defined in the Control Frames section (Section 2.2.1).
799
8002.6.3. RST_STREAM
801
802 The RST_STREAM frame allows for abnormal termination of a stream.
803 When sent by the creator of a stream, it indicates the creator wishes
804 to cancel the stream. When sent by the recipient of a stream, it
805 indicates an error or that the recipient did not want to accept the
806 stream, so the stream should be closed.
807
808 +----------------------------------+
809 |1| version | 3 |
810 +----------------------------------+
811 | Flags (8) | 8 |
812 +----------------------------------+
813 |X| Stream-ID (31bits) |
814 +----------------------------------+
815 | Status code |
816 +----------------------------------+
817
818 Flags: Flags related to this frame. RST_STREAM does not define any
819 flags. This value must be 0.
820
821 Length: An unsigned 24-bit value representing the number of bytes
822 after the length field. For RST_STREAM control frames, this value is
823 always 8.
824
825 Stream-ID: The 31-bit identifier for this stream.
826
827 Status code: (32 bits) An indicator for why the stream is being
828 terminated.The following status codes are defined:
829
830 1 - PROTOCOL_ERROR. This is a generic error, and should only be
831 used if a more specific error is not available.
832
833 2 - INVALID_STREAM. This is returned when a frame is received for
834 a stream which is not active.
835
836
837
838
839Belshe & Peon Expires August 4, 2012 [Page 15]
840
841Internet-Draft SPDY Feb 2012
842
843
844 3 - REFUSED_STREAM. Indicates that the stream was refused before
845 any processing has been done on the stream.
846
847 4 - UNSUPPORTED_VERSION. Indicates that the recipient of a stream
848 does not support the SPDY version requested.
849
850 5 - CANCEL. Used by the creator of a stream to indicate that the
851 stream is no longer needed.
852
853 6 - INTERNAL_ERROR. This is a generic error which can be used
854 when the implementation has internally failed, not due to anything
855 in the protocol.
856
857 7 - FLOW_CONTROL_ERROR. The endpoint detected that its peer
858 violated the flow control protocol.
859
860 8 - STREAM_IN_USE. The endpoint received a SYN_REPLY for a stream
861 already open.
862
863 9 - STREAM_ALREADY_CLOSED. The endpoint received a data or
864 SYN_REPLY frame for a stream which is half closed.
865
866 10 - INVALID_CREDENTIALS. The server received a request for a
867 resource whose origin does not have valid credentials in the
868 client certificate vector.
869
870 11 - FRAME_TOO_LARGE. The endpoint received a frame which this
871 implementation could not support. If FRAME_TOO_LARGE is sent for
872 a SYN_STREAM, HEADERS, or SYN_REPLY frame without fully processing
873 the compressed portion of those frames, then the compression state
874 will be out-of-sync with the other endpoint. In this case,
875 senders of FRAME_TOO_LARGE MUST close the session.
876
877 Note: 0 is not a valid status code for a RST_STREAM.
878
879 After receiving a RST_STREAM on a stream, the recipient must not send
880 additional frames for that stream, and the stream moves into the
881 closed state.
882
8832.6.4. SETTINGS
884
885 A SETTINGS frame contains a set of id/value pairs for communicating
886 configuration data about how the two endpoints may communicate.
887 SETTINGS frames can be sent at any time by either endpoint, are
888 optionally sent, and are fully asynchronous. When the server is the
889 sender, the sender can request that configuration data be persisted
890 by the client across SPDY sessions and returned to the server in
891 future communications.
892
893
894
895Belshe & Peon Expires August 4, 2012 [Page 16]
896
897Internet-Draft SPDY Feb 2012
898
899
900 Persistence of SETTINGS ID/Value pairs is done on a per origin/IP
901 pair (the "origin" is the set of scheme, host, and port from the URI.
902 See [RFC6454]). That is, when a client connects to a server, and the
903 server persists settings within the client, the client SHOULD return
904 the persisted settings on future connections to the same origin AND
905 IP address and TCP port. Clients MUST NOT request servers to use the
906 persistence features of the SETTINGS frames, and servers MUST ignore
907 persistence related flags sent by a client.
908
909 +----------------------------------+
910 |1| version | 4 |
911 +----------------------------------+
912 | Flags (8) | Length (24 bits) |
913 +----------------------------------+
914 | Number of entries |
915 +----------------------------------+
916 | ID/Value Pairs |
917 | ... |
918
919 Control bit: The control bit is always 1 for this message.
920
921 Version: The SPDY version number.
922
923 Type: The message type for a SETTINGS message is 4.
924
925 Flags: FLAG_SETTINGS_CLEAR_SETTINGS (0x1): When set, the client
926 should clear any previously persisted SETTINGS ID/Value pairs. If
927 this frame contains ID/Value pairs with the
928 FLAG_SETTINGS_PERSIST_VALUE set, then the client will first clear its
929 existing, persisted settings, and then persist the values with the
930 flag set which are contained within this frame. Because persistence
931 is only implemented on the client, this flag can only be used when
932 the sender is the server.
933
934 Length: An unsigned 24-bit value representing the number of bytes
935 after the length field. The total size of a SETTINGS frame is 8
936 bytes + length.
937
938 Number of entries: A 32-bit value representing the number of ID/value
939 pairs in this message.
940
941 ID: A 32-bit ID number, comprised of 8 bits of flags and 24 bits of
942 unique ID.
943
944 ID.flags:
945
946 FLAG_SETTINGS_PERSIST_VALUE (0x1): When set, the sender of this
947 SETTINGS frame is requesting that the recipient persist the ID/
948
949
950
951Belshe & Peon Expires August 4, 2012 [Page 17]
952
953Internet-Draft SPDY Feb 2012
954
955
956 Value and return it in future SETTINGS frames sent from the
957 sender to this recipient. Because persistence is only
958 implemented on the client, this flag is only sent by the
959 server.
960
961 FLAG_SETTINGS_PERSISTED (0x2): When set, the sender is
962 notifying the recipient that this ID/Value pair was previously
963 sent to the sender by the recipient with the
964 FLAG_SETTINGS_PERSIST_VALUE, and the sender is returning it.
965 Because persistence is only implemented on the client, this
966 flag is only sent by the client.
967
968 Defined IDs:
969
970 1 - SETTINGS_UPLOAD_BANDWIDTH allows the sender to send its
971 expected upload bandwidth on this channel. This number is an
972 estimate. The value should be the integral number of kilobytes
973 per second that the sender predicts as an expected maximum
974 upload channel capacity.
975
976 2 - SETTINGS_DOWNLOAD_BANDWIDTH allows the sender to send its
977 expected download bandwidth on this channel. This number is an
978 estimate. The value should be the integral number of kilobytes
979 per second that the sender predicts as an expected maximum
980 download channel capacity.
981
982 3 - SETTINGS_ROUND_TRIP_TIME allows the sender to send its
983 expected round-trip-time on this channel. The round trip time
984 is defined as the minimum amount of time to send a control
985 frame from this client to the remote and receive a response.
986 The value is represented in milliseconds.
987
988 4 - SETTINGS_MAX_CONCURRENT_STREAMS allows the sender to inform
989 the remote endpoint the maximum number of concurrent streams
990 which it will allow. By default there is no limit. For
991 implementors it is recommended that this value be no smaller
992 than 100.
993
994 5 - SETTINGS_CURRENT_CWND allows the sender to inform the
995 remote endpoint of the current TCP CWND value.
996
997 6 - SETTINGS_DOWNLOAD_RETRANS_RATE allows the sender to inform
998 the remote endpoint the retransmission rate (bytes
999 retransmitted / total bytes transmitted).
1000
1001 7 - SETTINGS_INITIAL_WINDOW_SIZE allows the sender to inform
1002 the remote endpoint the initial window size (in bytes) for new
1003 streams.
1004
1005
1006
1007Belshe & Peon Expires August 4, 2012 [Page 18]
1008
1009Internet-Draft SPDY Feb 2012
1010
1011
1012 8 - SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE allows the server
1013 to inform the client if the new size of the client certificate
1014 vector.
1015
1016 Value: A 32-bit value.
1017
1018 The message is intentionally extensible for future information which
1019 may improve client-server communications. The sender does not need
1020 to send every type of ID/value. It must only send those for which it
1021 has accurate values to convey. When multiple ID/value pairs are
1022 sent, they should be sent in order of lowest id to highest id. A
1023 single SETTINGS frame MUST not contain multiple values for the same
1024 ID. If the recipient of a SETTINGS frame discovers multiple values
1025 for the same ID, it MUST ignore all values except the first one.
1026
1027 A server may send multiple SETTINGS frames containing different ID/
1028 Value pairs. When the same ID/Value is sent twice, the most recent
1029 value overrides any previously sent values. If the server sends IDs
1030 1, 2, and 3 with the FLAG_SETTINGS_PERSIST_VALUE in a first SETTINGS
1031 frame, and then sends IDs 4 and 5 with the
1032 FLAG_SETTINGS_PERSIST_VALUE, when the client returns the persisted
1033 state on its next SETTINGS frame, it SHOULD send all 5 settings (1,
1034 2, 3, 4, and 5 in this example) to the server.
1035
10362.6.5. PING
1037
1038 The PING control frame is a mechanism for measuring a minimal round-
1039 trip time from the sender. It can be sent from the client or the
1040 server. Recipients of a PING frame should send an identical frame to
1041 the sender as soon as possible (if there is other pending data
1042 waiting to be sent, PING should take highest priority). Each ping
1043 sent by a sender should use a unique ID.
1044
1045 +----------------------------------+
1046 |1| version | 6 |
1047 +----------------------------------+
1048 | 0 (flags) | 4 (length) |
1049 +----------------------------------|
1050 | 32-bit ID |
1051 +----------------------------------+
1052
1053 Control bit: The control bit is always 1 for this message.
1054
1055 Version: The SPDY version number.
1056
1057 Type: The message type for a PING message is 6.
1058
1059 Length: This frame is always 4 bytes long.
1060
1061
1062
1063Belshe & Peon Expires August 4, 2012 [Page 19]
1064
1065Internet-Draft SPDY Feb 2012
1066
1067
1068 ID: A unique ID for this ping, represented as an unsigned 32 bit
1069 value. When the client initiates a ping, it must use an odd numbered
1070 ID. When the server initiates a ping, it must use an even numbered
1071 ping. Use of odd/even IDs is required in order to avoid accidental
1072 looping on PINGs (where each side initiates an identical PING at the
1073 same time).
1074
1075 Note: If a sender uses all possible PING ids (e.g. has sent all 2^31
1076 possible IDs), it can wrap and start re-using IDs.
1077
1078 If a server receives an even numbered PING which it did not initiate,
1079 it must ignore the PING. If a client receives an odd numbered PING
1080 which it did not initiate, it must ignore the PING.
1081
10822.6.6. GOAWAY
1083
1084 The GOAWAY control frame is a mechanism to tell the remote side of
1085 the connection to stop creating streams on this session. It can be
1086 sent from the client or the server. Once sent, the sender will not
1087 respond to any new SYN_STREAMs on this session. Recipients of a
1088 GOAWAY frame must not send additional streams on this session,
1089 although a new session can be established for new streams. The
1090 purpose of this message is to allow an endpoint to gracefully stop
1091 accepting new streams (perhaps for a reboot or maintenance), while
1092 still finishing processing of previously established streams.
1093
1094 There is an inherent race condition between an endpoint sending
1095 SYN_STREAMs and the remote sending a GOAWAY message. To deal with
1096 this case, the GOAWAY contains a last-stream-id indicating the
1097 stream-id of the last stream which was created on the sending
1098 endpoint in this session. If the receiver of the GOAWAY sent new
1099 SYN_STREAMs for sessions after this last-stream-id, they were not
1100 processed by the server and the receiver may treat the stream as
1101 though it had never been created at all (hence the receiver may want
1102 to re-create the stream later on a new session).
1103
1104 Endpoints should always send a GOAWAY message before closing a
1105 connection so that the remote can know whether a stream has been
1106 partially processed or not. (For example, if an HTTP client sends a
1107 POST at the same time that a server closes a connection, the client
1108 cannot know if the server started to process that POST request if the
1109 server does not send a GOAWAY frame to indicate where it stopped
1110 working).
1111
1112 After sending a GOAWAY message, the sender must ignore all SYN_STREAM
1113 frames for new streams.
1114
1115
1116
1117
1118
1119Belshe & Peon Expires August 4, 2012 [Page 20]
1120
1121Internet-Draft SPDY Feb 2012
1122
1123
1124 +----------------------------------+
1125 |1| version | 7 |
1126 +----------------------------------+
1127 | 0 (flags) | 8 (length) |
1128 +----------------------------------|
1129 |X| Last-good-stream-ID (31 bits) |
1130 +----------------------------------+
1131 | Status code |
1132 +----------------------------------+
1133
1134 Control bit: The control bit is always 1 for this message.
1135
1136 Version: The SPDY version number.
1137
1138 Type: The message type for a GOAWAY message is 7.
1139
1140 Length: This frame is always 8 bytes long.
1141
1142 Last-good-stream-Id: The last stream id which was replied to (with
1143 either a SYN_REPLY or RST_STREAM) by the sender of the GOAWAY
1144 message. If no streams were replied to, this value MUST be 0.
1145
1146 Status: The reason for closing the session.
1147
1148 0 - OK. This is a normal session teardown.
1149
1150 1 - PROTOCOL_ERROR. This is a generic error, and should only be
1151 used if a more specific error is not available.
1152
1153 11 - INTERNAL_ERROR. This is a generic error which can be used
1154 when the implementation has internally failed, not due to anything
1155 in the protocol.
1156
11572.6.7. HEADERS
1158
1159 The HEADERS frame augments a stream with additional headers. It may
1160 be optionally sent on an existing stream at any time. Specific
1161 application of the headers in this frame is application-dependent.
1162 The name/value header block within this frame is compressed.
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175Belshe & Peon Expires August 4, 2012 [Page 21]
1176
1177Internet-Draft SPDY Feb 2012
1178
1179
1180+------------------------------------+
1181|1| version | 8 |
1182+------------------------------------+
1183| Flags (8) | Length (24 bits) |
1184+------------------------------------+
1185|X| Stream-ID (31bits) |
1186+------------------------------------+
1187| Number of Name/Value pairs (int32) | <+
1188+------------------------------------+ |
1189| Length of name (int32) | | This section is the "Name/Value
1190+------------------------------------+ | Header Block", and is compressed.
1191| Name (string) | |
1192+------------------------------------+ |
1193| Length of value (int32) | |
1194+------------------------------------+ |
1195| Value (string) | |
1196+------------------------------------+ |
1197| (repeats) | <+
1198
1199 Flags: Flags related to this frame. Valid flags are:
1200
1201 0x01 = FLAG_FIN - marks this frame as the last frame to be
1202 transmitted on this stream and puts the sender in the half-closed
1203 (Section 2.3.6) state.
1204
1205 Length: An unsigned 24 bit value representing the number of bytes
1206 after the length field. The minimum length of the length field is 4
1207 (when the number of name value pairs is 0).
1208
1209 Stream-ID: The stream this HEADERS block is associated with.
1210
1211 Name/Value Header Block: A set of name/value pairs carried as part of
1212 the SYN_STREAM. see Name/Value Header Block (Section 2.6.10).
1213
12142.6.8. WINDOW_UPDATE
1215
1216 The WINDOW_UPDATE control frame is used to implement per stream flow
1217 control in SPDY. Flow control in SPDY is per hop, that is, only
1218 between the two endpoints of a SPDY connection. If there are one or
1219 more intermediaries between the client and the origin server, flow
1220 control signals are not explicitly forwarded by the intermediaries.
1221 (However, throttling of data transfer by any recipient may have the
1222 effect of indirectly propagating flow control information upstream
1223 back to the original sender.) Flow control only applies to the data
1224 portion of data frames. Recipients must buffer all control frames.
1225 If a recipient fails to buffer an entire control frame, it MUST issue
1226 a stream error (Section 2.4.2) with the status code
1227 FLOW_CONTROL_ERROR for the stream.
1228
1229
1230
1231Belshe & Peon Expires August 4, 2012 [Page 22]
1232
1233Internet-Draft SPDY Feb 2012
1234
1235
1236 Flow control in SPDY is implemented by a data transfer window kept by
1237 the sender of each stream. The data transfer window is a simple
1238 uint32 that indicates how many bytes of data the sender can transmit.
1239 After a stream is created, but before any data frames have been
1240 transmitted, the sender begins with the initial window size. This
1241 window size is a measure of the buffering capability of the
1242 recipient. The sender must not send a data frame with data length
1243 greater than the transfer window size. After sending each data
1244 frame, the sender decrements its transfer window size by the amount
1245 of data transmitted. When the window size becomes less than or equal
1246 to 0, the sender must pause transmitting data frames. At the other
1247 end of the stream, the recipient sends a WINDOW_UPDATE control back
1248 to notify the sender that it has consumed some data and freed up
1249 buffer space to receive more data.
1250
1251 +----------------------------------+
1252 |1| version | 9 |
1253 +----------------------------------+
1254 | 0 (flags) | 8 (length) |
1255 +----------------------------------+
1256 |X| Stream-ID (31-bits) |
1257 +----------------------------------+
1258 |X| Delta-Window-Size (31-bits) |
1259 +----------------------------------+
1260
1261 Control bit: The control bit is always 1 for this message.
1262
1263 Version: The SPDY version number.
1264
1265 Type: The message type for a WINDOW_UPDATE message is 9.
1266
1267 Length: The length field is always 8 for this frame (there are 8
1268 bytes after the length field).
1269
1270 Stream-ID: The stream ID that this WINDOW_UPDATE control frame is
1271 for.
1272
1273 Delta-Window-Size: The additional number of bytes that the sender can
1274 transmit in addition to existing remaining window size. The legal
1275 range for this field is 1 to 2^31 - 1 (0x7fffffff) bytes.
1276
1277 The window size as kept by the sender must never exceed 2^31
1278 (although it can become negative in one special case). If a sender
1279 receives a WINDOW_UPDATE that causes the its window size to exceed
1280 this limit, it must send RST_STREAM with status code
1281 FLOW_CONTROL_ERROR to terminate the stream.
1282
1283 When a SPDY connection is first established, the default initial
1284
1285
1286
1287Belshe & Peon Expires August 4, 2012 [Page 23]
1288
1289Internet-Draft SPDY Feb 2012
1290
1291
1292 window size for all streams is 64KB. An endpoint can use the
1293 SETTINGS control frame to adjust the initial window size for the
1294 connection. That is, its peer can start out using the 64KB default
1295 initial window size when sending data frames before receiving the
1296 SETTINGS. Because SETTINGS is asynchronous, there may be a race
1297 condition if the recipient wants to decrease the initial window size,
1298 but its peer immediately sends 64KB on the creation of a new
1299 connection, before waiting for the SETTINGS to arrive. This is one
1300 case where the window size kept by the sender will become negative.
1301 Once the sender detects this condition, it must stop sending data
1302 frames and wait for the recipient to catch up. The recipient has two
1303 choices:
1304
1305 immediately send RST_STREAM with FLOW_CONTROL_ERROR status code.
1306
1307 allow the head of line blocking (as there is only one stream for
1308 the session and the amount of data in flight is bounded by the
1309 default initial window size), and send WINDOW_UPDATE as it
1310 consumes data.
1311
1312 In the case of option 2, both sides must compute the window size
1313 based on the initial window size in the SETTINGS. For example, if
1314 the recipient sets the initial window size to be 16KB, and the sender
1315 sends 64KB immediately on connection establishment, the sender will
1316 discover its window size is -48KB on receipt of the SETTINGS. As the
1317 recipient consumes the first 16KB, it must send a WINDOW_UPDATE of
1318 16KB back to the sender. This interaction continues until the
1319 sender's window size becomes positive again, and it can resume
1320 transmitting data frames.
1321
1322 After the recipient reads in a data frame with FLAG_FIN that marks
1323 the end of the data stream, it should not send WINDOW_UPDATE frames
1324 as it consumes the last data frame. A sender should ignore all the
1325 WINDOW_UPDATE frames associated with the stream after it send the
1326 last frame for the stream.
1327
1328 The data frames from the sender and the WINDOW_UPDATE frames from the
1329 recipient are completely asynchronous with respect to each other.
1330 This property allows a recipient to aggressively update the window
1331 size kept by the sender to prevent the stream from stalling.
1332
13332.6.9. CREDENTIAL
1334
1335 The CREDENTIAL control frame is used by the client to send additional
1336 client certificates to the server. A SPDY client may decide to send
1337 requests for resources from different origins on the same SPDY
1338 session if it decides that that server handles both origins. For
1339 example if the IP address associated with both hostnames matches and
1340
1341
1342
1343Belshe & Peon Expires August 4, 2012 [Page 24]
1344
1345Internet-Draft SPDY Feb 2012
1346
1347
1348 the SSL server certificate presented in the initial handshake is
1349 valid for both hostnames. However, because the SSL connection can
1350 contain at most one client certificate, the client needs a mechanism
1351 to send additional client certificates to the server.
1352
1353 The server is required to maintain a vector of client certificates
1354 associated with a SPDY session. When the client needs to send a
1355 client certificate to the server, it will send a CREDENTIAL frame
1356 that specifies the index of the slot in which to store the
1357 certificate as well as proof that the client posesses the
1358 corresponding private key. The initial size of this vector must be
1359 8. If the client provides a client certificate during the first TLS
1360 handshake, the contents of this certificate must be copied into the
1361 first slot (index 1) in the CREDENTIAL vector, though it may be
1362 overwritten by subsequent CREDENTIAL frames. The server must
1363 exclusively use the CREDNETIAL vector when evaluating the client
1364 certificates associated with an origin. The server may change the
1365 size of this vector by sending a SETTINGS frame with the setting
1366 SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE value specified. In the
1367 event that the new size is smaller than the current size, truncation
1368 occurs preserving lower-index slots as possible.
1369
1370 TLS renegotiation with client authentication is incompatible with
1371 SPDY given the multiplexed nature of SPDY. Specifically, imagine
1372 that the client has 2 requests outstanding to the server for two
1373 different pages (in different tabs). When the renegotiation + client
1374 certificate request comes in, the browser is unable to determine
1375 which resource triggered the client certificate request, in order to
1376 prompt the user accordingly.
1377
1378 +----------------------------------+
1379 |1|000000000000001|0000000000001011|
1380 +----------------------------------+
1381 | flags (8) | Length (24 bits) |
1382 +----------------------------------+
1383 | Slot (16 bits) | |
1384 +-----------------+ |
1385 | Proof Length (32 bits) |
1386 +----------------------------------+
1387 | Proof |
1388 +----------------------------------+ <+
1389 | Certificate Length (32 bits) | |
1390 +----------------------------------+ | Repeated until end of frame
1391 | Certificate | |
1392 +----------------------------------+ <+
1393
1394 Slot: The index in the server's client certificate vector where this
1395 certificate should be stored. If there is already a certificate
1396
1397
1398
1399Belshe & Peon Expires August 4, 2012 [Page 25]
1400
1401Internet-Draft SPDY Feb 2012
1402
1403
1404 stored at this index, it will be overwritten. The index is one
1405 based, not zero based; zero is an invalid slot index.
1406
1407 Proof: Cryptographic proof that the client has possession of the
1408 private key associated with the certificate. The format is a TLS
1409 digitally-signed element
1410 (http://tools.ietf.org/html/rfc5246#section-4.7). The signature
1411 algorithm must be the same as that used in the CertificateVerify
1412 message. However, since the MD5+SHA1 signature type used in TLS 1.0
1413 connections can not be correctly encoded in a digitally-signed
1414 element, SHA1 must be used when MD5+SHA1 was used in the SSL
1415 connection. The signature is calculated over a 32 byte TLS extractor
1416 value (http://tools.ietf.org/html/rfc5705) with a label of "EXPORTER
1417 SPDY certificate proof" using the empty string as context. ForRSA
1418 certificates the signature would be a PKCS#1 v1.5 signature. For
1419 ECDSA, it would be an ECDSA-Sig-Value
1420 (http://tools.ietf.org/html/rfc5480#appendix-A). For a 1024-bit RSA
1421 key, the CREDENTIAL message would be ~500 bytes.
1422
1423 Certificate: The certificate chain, starting with the leaf
1424 certificate. Each certificate must be encoded as a 32 bit length,
1425 followed by a DER encoded certificate. The certificate must be of
1426 the same type (RSA, ECDSA, etc) as the client certificate associated
1427 with the SSL connection.
1428
1429 If the server receives a request for a resource with unacceptable
1430 credential (either missing or invalid), it must reply with a
1431 RST_STREAM frame with the status code INVALID_CREDENTIALS. Upon
1432 receipt of a RST_STREAM frame with INVALID_CREDENTIALS, the client
1433 should initiate a new stream directly to the requested origin and
1434 resend the request. Note, SPDY does not allow the server to request
1435 different client authentication for different resources in the same
1436 origin.
1437
1438 If the server receives an invalid CREDENTIAL frame, it MUST respond
1439 with a GOAWAY frame and shutdown the session.
1440
14412.6.10. Name/Value Header Block
1442
1443 The Name/Value Header Block is found in the SYN_STREAM, SYN_REPLY and
1444 HEADERS control frames, and shares a common format:
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455Belshe & Peon Expires August 4, 2012 [Page 26]
1456
1457Internet-Draft SPDY Feb 2012
1458
1459
1460 +------------------------------------+
1461 | Number of Name/Value pairs (int32) |
1462 +------------------------------------+
1463 | Length of name (int32) |
1464 +------------------------------------+
1465 | Name (string) |
1466 +------------------------------------+
1467 | Length of value (int32) |
1468 +------------------------------------+
1469 | Value (string) |
1470 +------------------------------------+
1471 | (repeats) |
1472
1473 Number of Name/Value pairs: The number of repeating name/value pairs
1474 following this field.
1475
1476 List of Name/Value pairs:
1477
1478 Length of Name: a 32-bit value containing the number of octets in
1479 the name field. Note that in practice, this length must not
1480 exceed 2^24, as that is the maximum size of a SPDY frame.
1481
1482 Name: 0 or more octets, 8-bit sequences of data, excluding 0.
1483
1484 Length of Value: a 32-bit value containing the number of octets in
1485 the value field. Note that in practice, this length must not
1486 exceed 2^24, as that is the maximum size of a SPDY frame.
1487
1488 Value: 0 or more octets, 8-bit sequences of data, excluding 0.
1489
1490 Each header name must have at least one value. Header names are
1491 encoded using the US-ASCII character set [ASCII] and must be all
1492 lower case. The length of each name must be greater than zero. A
1493 recipient of a zero-length name MUST issue a stream error
1494 (Section 2.4.2) with the status code PROTOCOL_ERROR for the
1495 stream-id.
1496
1497 Duplicate header names are not allowed. To send two identically
1498 named headers, send a header with two values, where the values are
1499 separated by a single NUL (0) byte. A header value can either be
1500 empty (e.g. the length is zero) or it can contain multiple, NUL-
1501 separated values, each with length greater than zero. The value
1502 never starts nor ends with a NUL character. Recipients of illegal
1503 value fields MUST issue a stream error (Section 2.4.2) with the
1504 status code PROTOCOL_ERROR for the stream-id.
1505
1506
1507
1508
1509
1510
1511Belshe & Peon Expires August 4, 2012 [Page 27]
1512
1513Internet-Draft SPDY Feb 2012
1514
1515
15162.6.10.1. Compression
1517
1518 The Name/Value Header Block is a section of the SYN_STREAM,
1519 SYN_REPLY, and HEADERS frames used to carry header meta-data. This
1520 block is always compressed using zlib compression. Within this
1521 specification, any reference to 'zlib' is referring to the ZLIB
1522 Compressed Data Format Specification Version 3.3 as part of RFC1950.
1523 [RFC1950]
1524
1525 For each HEADERS compression instance, the initial state is
1526 initialized using the following dictionary [UDELCOMPRESSION]:
1527
1528 const unsigned char SPDY_dictionary_txt[] = {
1529 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, \\ - - - - o p t i
1530 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, \\ o n s - - - - h
1531 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, \\ e a d - - - - p
1532 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, \\ o s t - - - - p
1533 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, \\ u t - - - - d e
1534 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, \\ l e t e - - - -
1535 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, \\ t r a c e - - -
1536 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, \\ - a c c e p t -
1537 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, \\ - - - a c c e p
1538 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, \\ t - c h a r s e
1539 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, \\ t - - - - a c c
1540 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, \\ e p t - e n c o
1541 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, \\ d i n g - - - -
1542 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, \\ a c c e p t - l
1543 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, \\ a n g u a g e -
1544 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, \\ - - - a c c e p
1545 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, \\ t - r a n g e s
1546 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, \\ - - - - a g e -
1547 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, \\ - - - a l l o w
1548 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, \\ - - - - a u t h
1549 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, \\ o r i z a t i o
1550 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, \\ n - - - - c a c
1551 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, \\ h e - c o n t r
1552 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, \\ o l - - - - c o
1553 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, \\ n n e c t i o n
1554 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t
1555 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, \\ e n t - b a s e
1556 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t
1557 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, \\ e n t - e n c o
1558 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, \\ d i n g - - - -
1559 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, \\ c o n t e n t -
1560 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, \\ l a n g u a g e
1561 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t
1562 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, \\ e n t - l e n g
1563 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, \\ t h - - - - c o
1564
1565
1566
1567Belshe & Peon Expires August 4, 2012 [Page 28]
1568
1569Internet-Draft SPDY Feb 2012
1570
1571
1572 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, \\ n t e n t - l o
1573 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, \\ c a t i o n - -
1574 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \\ - - c o n t e n
1575 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, \\ t - m d 5 - - -
1576 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, \\ - c o n t e n t
1577 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, \\ - r a n g e - -
1578 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \\ - - c o n t e n
1579 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, \\ t - t y p e - -
1580 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, \\ - - d a t e - -
1581 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, \\ - - e t a g - -
1582 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, \\ - - e x p e c t
1583 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, \\ - - - - e x p i
1584 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, \\ r e s - - - - f
1585 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, \\ r o m - - - - h
1586 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, \\ o s t - - - - i
1587 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, \\ f - m a t c h -
1588 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, \\ - - - i f - m o
1589 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, \\ d i f i e d - s
1590 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, \\ i n c e - - - -
1591 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, \\ i f - n o n e -
1592 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, \\ m a t c h - - -
1593 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, \\ - i f - r a n g
1594 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, \\ e - - - - i f -
1595 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, \\ u n m o d i f i
1596 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, \\ e d - s i n c e
1597 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, \\ - - - - l a s t
1598 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, \\ - m o d i f i e
1599 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, \\ d - - - - l o c
1600 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, \\ a t i o n - - -
1601 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, \\ - m a x - f o r
1602 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, \\ w a r d s - - -
1603 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, \\ - p r a g m a -
1604 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, \\ - - - p r o x y
1605 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, \\ - a u t h e n t
1606 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, \\ i c a t e - - -
1607 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, \\ - p r o x y - a
1608 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, \\ u t h o r i z a
1609 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, \\ t i o n - - - -
1610 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, \\ r a n g e - - -
1611 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, \\ - r e f e r e r
1612 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, \\ - - - - r e t r
1613 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, \\ y - a f t e r -
1614 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, \\ - - - s e r v e
1615 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, \\ r - - - - t e -
1616 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, \\ - - - t r a i l
1617 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, \\ e r - - - - t r
1618 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, \\ a n s f e r - e
1619 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, \\ n c o d i n g -
1620
1621
1622
1623Belshe & Peon Expires August 4, 2012 [Page 29]
1624
1625Internet-Draft SPDY Feb 2012
1626
1627
1628 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, \\ - - - u p g r a
1629 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, \\ d e - - - - u s
1630 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, \\ e r - a g e n t
1631 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, \\ - - - - v a r y
1632 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, \\ - - - - v i a -
1633 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, \\ - - - w a r n i
1634 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, \\ n g - - - - w w
1635 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, \\ w - a u t h e n
1636 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, \\ t i c a t e - -
1637 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, \\ - - m e t h o d
1638 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, \\ - - - - g e t -
1639 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, \\ - - - s t a t u
1640 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, \\ s - - - - 2 0 0
1641 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, \\ - O K - - - - v
1642 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, \\ e r s i o n - -
1643 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, \\ - - H T T P - 1
1644 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, \\ - 1 - - - - u r
1645 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, \\ l - - - - p u b
1646 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, \\ l i c - - - - s
1647 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, \\ e t - c o o k i
1648 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, \\ e - - - - k e e
1649 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, \\ p - a l i v e -
1650 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, \\ - - - o r i g i
1651 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, \\ n 1 0 0 1 0 1 2
1652 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, \\ 0 1 2 0 2 2 0 5
1653 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, \\ 2 0 6 3 0 0 3 0
1654 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, \\ 2 3 0 3 3 0 4 3
1655 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, \\ 0 5 3 0 6 3 0 7
1656 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, \\ 4 0 2 4 0 5 4 0
1657 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, \\ 6 4 0 7 4 0 8 4
1658 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, \\ 0 9 4 1 0 4 1 1
1659 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, \\ 4 1 2 4 1 3 4 1
1660 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, \\ 4 4 1 5 4 1 6 4
1661 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, \\ 1 7 5 0 2 5 0 4
1662 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, \\ 5 0 5 2 0 3 - N
1663 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, \\ o n - A u t h o
1664 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, \\ r i t a t i v e
1665 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, \\ - I n f o r m a
1666 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, \\ t i o n 2 0 4 -
1667 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, \\ N o - C o n t e
1668 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, \\ n t 3 0 1 - M o
1669 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, \\ v e d - P e r m
1670 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, \\ a n e n t l y 4
1671 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, \\ 0 0 - B a d - R
1672 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, \\ e q u e s t 4 0
1673 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, \\ 1 - U n a u t h
1674 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, \\ o r i z e d 4 0
1675 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, \\ 3 - F o r b i d
1676
1677
1678
1679Belshe & Peon Expires August 4, 2012 [Page 30]
1680
1681Internet-Draft SPDY Feb 2012
1682
1683
1684 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, \\ d e n 4 0 4 - N
1685 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, \\ o t - F o u n d
1686 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, \\ 5 0 0 - I n t e
1687 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, \\ r n a l - S e r
1688 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, \\ v e r - E r r o
1689 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, \\ r 5 0 1 - N o t
1690 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, \\ - I m p l e m e
1691 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, \\ n t e d 5 0 3 -
1692 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, \\ S e r v i c e -
1693 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, \\ U n a v a i l a
1694 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, \\ b l e J a n - F
1695 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, \\ e b - M a r - A
1696 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, \\ p r - M a y - J
1697 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, \\ u n - J u l - A
1698 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, \\ u g - S e p t -
1699 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, \\ O c t - N o v -
1700 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, \\ D e c - 0 0 - 0
1701 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, \\ 0 - 0 0 - M o n
1702 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, \\ - - T u e - - W
1703 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, \\ e d - - T h u -
1704 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, \\ - F r i - - S a
1705 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, \\ t - - S u n - -
1706 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, \\ G M T c h u n k
1707 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, \\ e d - t e x t -
1708 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, \\ h t m l - i m a
1709 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, \\ g e - p n g - i
1710 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, \\ m a g e - j p g
1711 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, \\ - i m a g e - g
1712 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, \\ i f - a p p l i
1713 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, \\ c a t i o n - x
1714 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, \\ m l - a p p l i
1715 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, \\ c a t i o n - x
1716 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, \\ h t m l - x m l
1717 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, \\ - t e x t - p l
1718 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, \\ a i n - t e x t
1719 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, \\ - j a v a s c r
1720 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, \\ i p t - p u b l
1721 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, \\ i c p r i v a t
1722 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, \\ e m a x - a g e
1723 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, \\ - g z i p - d e
1724 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, \\ f l a t e - s d
1725 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, \\ c h c h a r s e
1726 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, \\ t - u t f - 8 c
1727 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, \\ h a r s e t - i
1728 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, \\ s o - 8 8 5 9 -
1729 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, \\ 1 - u t f - - -
1730 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e \\ - e n q - 0 -
1731 };
1732
1733
1734
1735Belshe & Peon Expires August 4, 2012 [Page 31]
1736
1737Internet-Draft SPDY Feb 2012
1738
1739
1740 The entire contents of the name/value header block is compressed
1741 using zlib. There is a single zlib stream for all name value pairs
1742 in one direction on a connection. SPDY uses a SYNC_FLUSH between
1743 each compressed frame.
1744
1745 Implementation notes: the compression engine can be tuned to favor
1746 speed or size. Optimizing for size increases memory use and CPU
1747 consumption. Because header blocks are generally small, implementors
1748 may want to reduce the window-size of the compression engine from the
1749 default 15bits (a 32KB window) to more like 11bits (a 2KB window).
1750 The exact setting is chosen by the compressor, the decompressor will
1751 work with any setting.
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791Belshe & Peon Expires August 4, 2012 [Page 32]
1792
1793Internet-Draft SPDY Feb 2012
1794
1795
17963. HTTP Layering over SPDY
1797
1798 SPDY is intended to be as compatible as possible with current web-
1799 based applications. This means that, from the perspective of the
1800 server business logic or application API, the features of HTTP are
1801 unchanged. To achieve this, all of the application request and
1802 response header semantics are preserved, although the syntax of
1803 conveying those semantics has changed. Thus, the rules from the
1804 HTTP/1.1 specification in RFC2616 [RFC2616] apply with the changes in
1805 the sections below.
1806
18073.1. Connection Management
1808
1809 Clients SHOULD NOT open more than one SPDY session to a given origin
1810 [RFC6454] concurrently.
1811
1812 Note that it is possible for one SPDY session to be finishing (e.g. a
1813 GOAWAY message has been sent, but not all streams have finished),
1814 while another SPDY session is starting.
1815
18163.1.1. Use of GOAWAY
1817
1818 SPDY provides a GOAWAY message which can be used when closing a
1819 connection from either the client or server. Without a server GOAWAY
1820 message, HTTP has a race condition where the client sends a request
1821 (a new SYN_STREAM) just as the server is closing the connection, and
1822 the client cannot know if the server received the stream or not. By
1823 using the last-stream-id in the GOAWAY, servers can indicate to the
1824 client if a request was processed or not.
1825
1826 Note that some servers will choose to send the GOAWAY and immediately
1827 terminate the connection without waiting for active streams to
1828 finish. The client will be able to determine this because SPDY
1829 streams are determinstically closed. This abrupt termination will
1830 force the client to heuristically decide whether to retry the pending
1831 requests. Clients always need to be capable of dealing with this
1832 case because they must deal with accidental connection termination
1833 cases, which are the same as the server never having sent a GOAWAY.
1834
1835 More sophisticated servers will use GOAWAY to implement a graceful
1836 teardown. They will send the GOAWAY and provide some time for the
1837 active streams to finish before terminating the connection.
1838
1839 If a SPDY client closes the connection, it should also send a GOAWAY
1840 message. This allows the server to know if any server-push streams
1841 were received by the client.
1842
1843 If the endpoint closing the connection has not received any
1844
1845
1846
1847Belshe & Peon Expires August 4, 2012 [Page 33]
1848
1849Internet-Draft SPDY Feb 2012
1850
1851
1852 SYN_STREAMs from the remote, the GOAWAY will contain a last-stream-id
1853 of 0.
1854
18553.2. HTTP Request/Response
1856
18573.2.1. Request
1858
1859 The client initiates a request by sending a SYN_STREAM frame. For
1860 requests which do not contain a body, the SYN_STREAM frame MUST set
1861 the FLAG_FIN, indicating that the client intends to send no further
1862 data on this stream. For requests which do contain a body, the
1863 SYN_STREAM will not contain the FLAG_FIN, and the body will follow
1864 the SYN_STREAM in a series of DATA frames. The last DATA frame will
1865 set the FLAG_FIN to indicate the end of the body.
1866
1867 The SYN_STREAM Name/Value section will contain all of the HTTP
1868 headers which are associated with an HTTP request. The header block
1869 in SPDY is mostly unchanged from today's HTTP header block, with the
1870 following differences:
1871
1872 The first line of the request is unfolded into name/value pairs
1873 like other HTTP headers and MUST be present:
1874
1875 ":method" - the HTTP method for this request (e.g. "GET",
1876 "POST", "HEAD", etc)
1877
1878 ":path" - the url-path for this url with "/" prefixed. (See
1879 RFC1738 [RFC1738]). For example, for
1880 "http://www.google.com/search?q=dogs" the path would be
1881 "/search?q=dogs".
1882
1883 ":version" - the HTTP version of this request (e.g.
1884 "HTTP/1.1")
1885
1886 In addition, the following two name/value pairs must also be
1887 present in every request:
1888
1889 ":host" - the hostport (See RFC1738 [RFC1738]) portion of the
1890 URL for this request (e.g. "www.google.com:1234"). This header
1891 is the same as the HTTP 'Host' header.
1892
1893 ":scheme" - the scheme portion of the URL for this request
1894 (e.g. "https"))
1895
1896 Header names are all lowercase.
1897
1898 The Connection, Host, Keep-Alive, Proxy-Connection, and Transfer-
1899 Encoding headers are not valid and MUST not be sent.
1900
1901
1902
1903Belshe & Peon Expires August 4, 2012 [Page 34]
1904
1905Internet-Draft SPDY Feb 2012
1906
1907
1908 User-agents MUST support gzip compression. Regardless of the
1909 Accept-Encoding sent by the user-agent, the server may always send
1910 content encoded with gzip or deflate encoding.
1911
1912 If a server receives a request where the sum of the data frame
1913 payload lengths does not equal the size of the Content-Length
1914 header, the server MUST return a 400 (Bad Request) error.
1915
1916 POST-specific changes:
1917
1918 Although POSTs are inherently chunked, POST requests SHOULD
1919 also be accompanied by a Content-Length header. There are two
1920 reasons for this: First, it assists with upload progress meters
1921 for an improved user experience. But second, we know from
1922 early versions of SPDY that failure to send a content length
1923 header is incompatible with many existing HTTP server
1924 implementations. Existing user-agents do not omit the Content-
1925 Length header, and server implementations have come to depend
1926 upon this.
1927
1928 The user-agent is free to prioritize requests as it sees fit. If the
1929 user-agent cannot make progress without receiving a resource, it
1930 should attempt to raise the priority of that resource. Resources
1931 such as images, SHOULD generally use the lowest priority.
1932
1933 If a client sends a SYN_STREAM without all of the method, host, path,
1934 scheme, and version headers, the server MUST reply with a HTTP 400
1935 Bad Request reply.
1936
19373.2.2. Response
1938
1939 The server responds to a client request with a SYN_REPLY frame.
1940 Symmetric to the client's upload stream, server will send data after
1941 the SYN_REPLY frame via a series of DATA frames, and the last data
1942 frame will contain the FLAG_FIN to indicate successful end-of-stream.
1943 If a response (like a 202 or 204 response) contains no body, the
1944 SYN_REPLY frame may contain the FLAG_FIN flag to indicate no further
1945 data will be sent on the stream.
1946
1947 The response status line is unfolded into name/value pairs like
1948 other HTTP headers and must be present:
1949
1950 ":status" - The HTTP response status code (e.g. "200" or "200
1951 OK")
1952
1953 ":version" - The HTTP response version (e.g. "HTTP/1.1")
1954
1955
1956
1957
1958
1959Belshe & Peon Expires August 4, 2012 [Page 35]
1960
1961Internet-Draft SPDY Feb 2012
1962
1963
1964 All header names must be lowercase.
1965
1966 The Connection, Keep-Alive, Proxy-Connection, and Transfer-
1967 Encoding headers are not valid and MUST not be sent.
1968
1969 Responses MAY be accompanied by a Content-Length header for
1970 advisory purposes. (e.g. for UI progress meters)
1971
1972 If a client receives a response where the sum of the data frame
1973 payload lengths does not equal the size of the Content-Length
1974 header, the client MUST ignore the content length header.
1975
1976 If a client receives a SYN_REPLY without a status or without a
1977 version header, the client must reply with a RST_STREAM frame
1978 indicating a PROTOCOL ERROR.
1979
19803.2.3. Authentication
1981
1982 When a client sends a request to an origin server that requires
1983 authentication, the server can reply with a "401 Unauthorized"
1984 response, and include a WWW-Authenticate challenge header that
1985 defines the authentication scheme to be used. The client then
1986 retries the request with an Authorization header appropriate to the
1987 specified authentication scheme.
1988
1989 There are four options for proxy authentication, Basic, Digest, NTLM
1990 and Negotiate (SPNEGO). The first two options were defined in
1991 RFC2617 [RFC2617], and are stateless. The second two options were
1992 developed by Microsoft and specified in RFC4559 [RFC4559], and are
1993 stateful; otherwise known as multi-round authentication, or
1994 connection authentication.
1995
19963.2.3.1. Stateless Authentication
1997
1998 Stateless Authentication over SPDY is identical to how it is
1999 performed over HTTP. If multiple SPDY streams are concurrently sent
2000 to a single server, each will authenticate independently, similar to
2001 how two HTTP connections would independently authenticate to a proxy
2002 server.
2003
20043.2.3.2. Stateful Authentication
2005
2006 Unfortunately, the stateful authentication mechanisms were
2007 implemented and defined in a such a way that directly violates
2008 RFC2617 - they do not include a "realm" as part of the request. This
2009 is problematic in SPDY because it makes it impossible for a client to
2010 disambiguate two concurrent server authentication challenges.
2011
2012
2013
2014
2015Belshe & Peon Expires August 4, 2012 [Page 36]
2016
2017Internet-Draft SPDY Feb 2012
2018
2019
2020 To deal with this case, SPDY servers using Stateful Authentication
2021 MUST implement one of two changes:
2022
2023 Servers can add a "realm=<desired realm>" header so that the two
2024 authentication requests can be disambiguated and run concurrently.
2025 Unfortunately, given how these mechanisms work, this is probably
2026 not practical.
2027
2028 Upon sending the first stateful challenge response, the server
2029 MUST buffer and defer all further frames which are not part of
2030 completing the challenge until the challenge has completed.
2031 Completing the authentication challenge may take multiple round
2032 trips. Once the client receives a "401 Authenticate" response for
2033 a stateful authentication type, it MUST stop sending new requests
2034 to the server until the authentication has completed by receiving
2035 a non-401 response on at least one stream.
2036
20373.3. Server Push Transactions
2038
2039 SPDY enables a server to send multiple replies to a client for a
2040 single request. The rationale for this feature is that sometimes a
2041 server knows that it will need to send multiple resources in response
2042 to a single request. Without server push features, the client must
2043 first download the primary resource, then discover the secondary
2044 resource(s), and request them. Pushing of resources avoids the
2045 round-trip delay, but also creates a potential race where a server
2046 can be pushing content which a user-agent is in the process of
2047 requesting. The following mechanics attempt to prevent the race
2048 condition while enabling the performance benefit.
2049
2050 Browsers receiving a pushed response MUST validate that the server is
2051 authorized to push the URL using the browser same-origin [RFC6454]
2052 policy. For example, a SPDY connection to www.foo.com is generally
2053 not permitted to push a response for www.evil.com.
2054
2055 If the browser accepts a pushed response (e.g. it does not send a
2056 RST_STREAM), the browser MUST attempt to cache the pushed response in
2057 same way that it would cache any other response. This means
2058 validating the response headers and inserting into the disk cache.
2059
2060 Because pushed responses have no request, they have no request
2061 headers associated with them. At the framing layer, SPDY pushed
2062 streams contain an "associated-stream-id" which indicates the
2063 requested stream for which the pushed stream is related. The pushed
2064 stream inherits all of the headers from the associated-stream-id with
2065 the exception of ":host", ":scheme", and ":path", which are provided
2066 as part of the pushed response stream headers. The browser MUST
2067 store these inherited and implied request headers with the cached
2068
2069
2070
2071Belshe & Peon Expires August 4, 2012 [Page 37]
2072
2073Internet-Draft SPDY Feb 2012
2074
2075
2076 resource.
2077
2078 Implementation note: With server push, it is theoretically possible
2079 for servers to push unreasonable amounts of content or resources to
2080 the user-agent. Browsers MUST implement throttles to protect against
2081 unreasonable push attacks.
2082
20833.3.1. Server implementation
2084
2085 When the server intends to push a resource to the user-agent, it
2086 opens a new stream by sending a unidirectional SYN_STREAM. The
2087 SYN_STREAM MUST include an Associated-To-Stream-ID, and MUST set the
2088 FLAG_UNIDIRECTIONAL flag. The SYN_STREAM MUST include headers for
2089 ":scheme", ":host", ":path", which represent the URL for the resource
2090 being pushed. Subsequent headers may follow in HEADERS frames. The
2091 purpose of the association is so that the user-agent can
2092 differentiate which request induced the pushed stream; without it, if
2093 the user-agent had two tabs open to the same page, each pushing
2094 unique content under a fixed URL, the user-agent would not be able to
2095 differentiate the requests.
2096
2097 The Associated-To-Stream-ID must be the ID of an existing, open
2098 stream. The reason for this restriction is to have a clear endpoint
2099 for pushed content. If the user-agent requested a resource on stream
2100 11, the server replies on stream 11. It can push any number of
2101 additional streams to the client before sending a FLAG_FIN on stream
2102 11. However, once the originating stream is closed no further push
2103 streams may be associated with it. The pushed streams do not need to
2104 be closed (FIN set) before the originating stream is closed, they
2105 only need to be created before the originating stream closes.
2106
2107 It is illegal for a server to push a resource with the Associated-To-
2108 Stream-ID of 0.
2109
2110 To minimize race conditions with the client, the SYN_STREAM for the
2111 pushed resources MUST be sent prior to sending any content which
2112 could allow the client to discover the pushed resource and request
2113 it.
2114
2115 The server MUST only push resources which would have been returned
2116 from a GET request.
2117
2118 Note: If the server does not have all of the Name/Value Response
2119 headers available at the time it issues the HEADERS frame for the
2120 pushed resource, it may later use an additional HEADERS frame to
2121 augment the name/value pairs to be associated with the pushed stream.
2122 The subsequent HEADERS frame(s) must not contain a header for
2123 ':host', ':scheme', or ':path' (e.g. the server can't change the
2124
2125
2126
2127Belshe & Peon Expires August 4, 2012 [Page 38]
2128
2129Internet-Draft SPDY Feb 2012
2130
2131
2132 identity of the resource to be pushed). The HEADERS frame must not
2133 contain duplicate headers with a previously sent HEADERS frame. The
2134 server must send a HEADERS frame including the scheme/host/port
2135 headers before sending any data frames on the stream.
2136
21373.3.2. Client implementation
2138
2139 When fetching a resource the client has 3 possibilities:
2140
2141 the resource is not being pushed
2142
2143 the resource is being pushed, but the data has not yet arrived
2144
2145 the resource is being pushed, and the data has started to arrive
2146
2147 When a SYN_STREAM and HEADERS frame which contains an Associated-To-
2148 Stream-ID is received, the client must not issue GET requests for the
2149 resource in the pushed stream, and instead wait for the pushed stream
2150 to arrive.
2151
2152 If a client receives a server push stream with stream-id 0, it MUST
2153 issue a session error (Section 2.4.1) with the status code
2154 PROTOCOL_ERROR.
2155
2156 When a client receives a SYN_STREAM from the server without a the
2157 ':host', ':scheme', and ':path' headers in the Name/Value section, it
2158 MUST reply with a RST_STREAM with error code HTTP_PROTOCOL_ERROR.
2159
2160 To cancel individual server push streams, the client can issue a
2161 stream error (Section 2.4.2) with error code CANCEL. Upon receipt,
2162 the server MUST stop sending on this stream immediately (this is an
2163 Abrupt termination).
2164
2165 To cancel all server push streams related to a request, the client
2166 may issue a stream error (Section 2.4.2) with error code CANCEL on
2167 the associated-stream-id. By cancelling that stream, the server MUST
2168 immediately stop sending frames for any streams with
2169 in-association-to for the original stream.
2170
2171 If the server sends a HEADER frame containing duplicate headers with
2172 a previous HEADERS frame for the same stream, the client must issue a
2173 stream error (Section 2.4.2) with error code PROTOCOL ERROR.
2174
2175 If the server sends a HEADERS frame after sending a data frame for
2176 the same stream, the client MAY ignore the HEADERS frame. Ignoring
2177 the HEADERS frame after a data frame prevents handling of HTTP's
2178 trailing headers
2179 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40).
2180
2181
2182
2183Belshe & Peon Expires August 4, 2012 [Page 39]
2184
2185Internet-Draft SPDY Feb 2012
2186
2187
21884. Design Rationale and Notes
2189
2190 Authors' notes: The notes in this section have no bearing on the SPDY
2191 protocol as specified within this document, and none of these notes
2192 should be considered authoritative about how the protocol works.
2193 However, these notes may prove useful in future debates about how to
2194 resolve protocol ambiguities or how to evolve the protocol going
2195 forward. They may be removed before the final draft.
2196
21974.1. Separation of Framing Layer and Application Layer
2198
2199 Readers may note that this specification sometimes blends the framing
2200 layer (Section 2) with requirements of a specific application - HTTP
2201 (Section 3). This is reflected in the request/response nature of the
2202 streams, the definition of the HEADERS and compression contexts which
2203 are very similar to HTTP, and other areas as well.
2204
2205 This blending is intentional - the primary goal of this protocol is
2206 to create a low-latency protocol for use with HTTP. Isolating the
2207 two layers is convenient for description of the protocol and how it
2208 relates to existing HTTP implementations. However, the ability to
2209 reuse the SPDY framing layer is a non goal.
2210
22114.2. Error handling - Framing Layer
2212
2213 Error handling at the SPDY layer splits errors into two groups: Those
2214 that affect an individual SPDY stream, and those that do not.
2215
2216 When an error is confined to a single stream, but general framing is
2217 in tact, SPDY attempts to use the RST_STREAM as a mechanism to
2218 invalidate the stream but move forward without aborting the
2219 connection altogether.
2220
2221 For errors occuring outside of a single stream context, SPDY assumes
2222 the entire session is hosed. In this case, the endpoint detecting
2223 the error should initiate a connection close.
2224
22254.3. One Connection Per Domain
2226
2227 SPDY attempts to use fewer connections than other protocols have
2228 traditionally used. The rationale for this behavior is because it is
2229 very difficult to provide a consistent level of service (e.g. TCP
2230 slow-start), prioritization, or optimal compression when the client
2231 is connecting to the server through multiple channels.
2232
2233 Through lab measurements, we have seen consistent latency benefits by
2234 using fewer connections from the client. The overall number of
2235 packets sent by SPDY can be as much as 40% less than HTTP. Handling
2236
2237
2238
2239Belshe & Peon Expires August 4, 2012 [Page 40]
2240
2241Internet-Draft SPDY Feb 2012
2242
2243
2244 large numbers of concurrent connections on the server also does
2245 become a scalability problem, and SPDY reduces this load.
2246
2247 The use of multiple connections is not without benefit, however.
2248 Because SPDY multiplexes multiple, independent streams onto a single
2249 stream, it creates a potential for head-of-line blocking problems at
2250 the transport level. In tests so far, the negative effects of head-
2251 of-line blocking (especially in the presence of packet loss) is
2252 outweighed by the benefits of compression and prioritization.
2253
22544.4. Fixed vs Variable Length Fields
2255
2256 SPDY favors use of fixed length 32bit fields in cases where smaller,
2257 variable length encodings could have been used. To some, this seems
2258 like a tragic waste of bandwidth. SPDY choses the simple encoding
2259 for speed and simplicity.
2260
2261 The goal of SPDY is to reduce latency on the network. The overhead
2262 of SPDY frames is generally quite low. Each data frame is only an 8
2263 byte overhead for a 1452 byte payload (~0.6%). At the time of this
2264 writing, bandwidth is already plentiful, and there is a strong trend
2265 indicating that bandwidth will continue to increase. With an average
2266 worldwide bandwidth of 1Mbps, and assuming that a variable length
2267 encoding could reduce the overhead by 50%, the latency saved by using
2268 a variable length encoding would be less than 100 nanoseconds. More
2269 interesting are the effects when the larger encodings force a packet
2270 boundary, in which case a round-trip could be induced. However, by
2271 addressing other aspects of SPDY and TCP interactions, we believe
2272 this is completely mitigated.
2273
22744.5. Compression Context(s)
2275
2276 When isolating the compression contexts used for communicating with
2277 multiple origins, we had a few choices to make. We could have
2278 maintained a map (or list) of compression contexts usable for each
2279 origin. The basic case is easy - each HEADERS frame would need to
2280 identify the context to use for that frame. However, compression
2281 contexts are not cheap, so the lifecycle of each context would need
2282 to be bounded. For proxy servers, where we could churn through many
2283 contexts, this would be a concern. We considered using a static set
2284 of contexts, say 16 of them, which would bound the memory use. We
2285 also considered dynamic contexts, which could be created on the fly,
2286 and would need to be subsequently destroyed. All of these are
2287 complicated, and ultimately we decided that such a mechanism creates
2288 too many problems to solve.
2289
2290 Alternatively, we've chosen the simple approach, which is to simply
2291 provide a flag for resetting the compression context. For the common
2292
2293
2294
2295Belshe & Peon Expires August 4, 2012 [Page 41]
2296
2297Internet-Draft SPDY Feb 2012
2298
2299
2300 case (no proxy), this fine because most requests are to the same
2301 origin and we never need to reset the context. For cases where we
2302 are using two different origins over a single SPDY session, we simply
2303 reset the compression state between each transition.
2304
23054.6. Unidirectional streams
2306
2307 Many readers notice that unidirectional streams are both a bit
2308 confusing in concept and also somewhat redundant. If the recipient
2309 of a stream doesn't wish to send data on a stream, it could simply
2310 send a SYN_REPLY with the FLAG_FIN bit set. The FLAG_UNIDIRECTIONAL
2311 is, therefore, not necessary.
2312
2313 It is true that we don't need the UNIDIRECTIONAL markings. It is
2314 added because it avoids the recipient of pushed streams from needing
2315 to send a set of empty frames (e.g. the SYN_STREAM w/ FLAG_FIN) which
2316 otherwise serve no purpose.
2317
23184.7. Data Compression
2319
2320 Generic compression of data portion of the streams (as opposed to
2321 compression of the headers) without knowing the content of the stream
2322 is redundant. There is no value in compressing a stream which is
2323 already compressed. Because of this, SPDY does allow data
2324 compression to be optional. We included it because study of existing
2325 websites shows that many sites are not using compression as they
2326 should, and users suffer because of it. We wanted a mechanism where,
2327 at the SPDY layer, site administrators could simply force compression
2328 - it is better to compress twice than to not compress.
2329
2330 Overall, however, with this feature being optional and sometimes
2331 redundant, it is unclear if it is useful at all. We will likely
2332 remove it from the specification.
2333
23344.8. Server Push
2335
2336 A subtle but important point is that server push streams must be
2337 declared before the associated stream is closed. The reason for this
2338 is so that proxies have a lifetime for which they can discard
2339 information about previous streams. If a pushed stream could
2340 associate itself with an already-closed stream, then endpoints would
2341 not have a specific lifecycle for when they could disavow knowledge
2342 of the streams which went before.
2343
2344
2345
2346
2347
2348
2349
2350
2351Belshe & Peon Expires August 4, 2012 [Page 42]
2352
2353Internet-Draft SPDY Feb 2012
2354
2355
23565. Security Considerations
2357
23585.1. Use of Same-origin constraints
2359
2360 This specification uses the same-origin policy [RFC6454] in all cases
2361 where verification of content is required.
2362
23635.2. HTTP Headers and SPDY Headers
2364
2365 At the application level, HTTP uses name/value pairs in its headers.
2366 Because SPDY merges the existing HTTP headers with SPDY headers,
2367 there is a possibility that some HTTP applications already use a
2368 particular header name. To avoid any conflicts, all headers
2369 introduced for layering HTTP over SPDY are prefixed with ":". ":" is
2370 not a valid sequence in HTTP header naming, preventing any possible
2371 conflict.
2372
23735.3. Cross-Protocol Attacks
2374
2375 By utilizing TLS, we believe that SPDY introduces no new cross-
2376 protocol attacks. TLS encrypts the contents of all transmission
2377 (except the handshake itself), making it difficult for attackers to
2378 control the data which could be used in a cross-protocol attack.
2379
23805.4. Server Push Implicit Headers
2381
2382 Pushed resources do not have an associated request. In order for
2383 existing HTTP cache control validations (such as the Vary header) to
2384 work, however, all cached resources must have a set of request
2385 headers. For this reason, browsers MUST be careful to inherit
2386 request headers from the associated stream for the push. This
2387 includes the 'Cookie' header.
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407Belshe & Peon Expires August 4, 2012 [Page 43]
2408
2409Internet-Draft SPDY Feb 2012
2410
2411
24126. Privacy Considerations
2413
24146.1. Long Lived Connections
2415
2416 SPDY aims to keep connections open longer between clients and servers
2417 in order to reduce the latency when a user makes a request. The
2418 maintenance of these connections over time could be used to expose
2419 private information. For example, a user using a browser hours after
2420 the previous user stopped using that browser may be able to learn
2421 about what the previous user was doing. This is a problem with HTTP
2422 in its current form as well, however the short lived connections make
2423 it less of a risk.
2424
24256.2. SETTINGS frame
2426
2427 The SPDY SETTINGS frame allows servers to store out-of-band
2428 transmitted information about the communication between client and
2429 server on the client. Although this is intended only to be used to
2430 reduce latency, renegade servers could use it as a mechanism to store
2431 identifying information about the client in future requests.
2432
2433 Clients implementing privacy modes, such as Google Chrome's
2434 "incognito mode", may wish to disable client-persisted SETTINGS
2435 storage.
2436
2437 Clients MUST clear persisted SETTINGS information when clearing the
2438 cookies.
2439
2440 TODO: Put range maximums on each type of setting to limit
2441 inappropriate uses.
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463Belshe & Peon Expires August 4, 2012 [Page 44]
2464
2465Internet-Draft SPDY Feb 2012
2466
2467
24687. Incompatibilities with SPDY draft #2
2469
2470 Here is a list of the major changes between this draft and draft #2.
2471
2472 Addition of flow control
2473
2474 Increased 16 bit length fields in SYN_STREAM and SYN_REPLY to 32
2475 bits.
2476
2477 Changed definition of compression for DATA frames
2478
2479 Updated compression dictionary
2480
2481 Fixed off-by-one on the compression dictionary for headers
2482
2483 Increased priority field from 2bits to 3bits.
2484
2485 Removed NOOP frame
2486
2487 Split the request "url" into "scheme", "host", and "path"
2488
2489 Added the requirement that POSTs contain content-length.
2490
2491 Removed wasted 16bits of unused space from the end of the
2492 SYN_REPLY and HEADERS frames.
2493
2494 Fixed bug: Priorities were described backward (0 was lowest
2495 instead of highest).
2496
2497 Fixed bug: Name/Value header counts were duplicated in both the
2498 Name Value header block and also the containing frame.
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519Belshe & Peon Expires August 4, 2012 [Page 45]
2520
2521Internet-Draft SPDY Feb 2012
2522
2523
25248. Requirements Notation
2525
2526 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
2527 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
2528 document are to be interpreted as described in RFC 2119 [RFC2119].
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575Belshe & Peon Expires August 4, 2012 [Page 46]
2576
2577Internet-Draft SPDY Feb 2012
2578
2579
25809. Acknowledgements
2581
2582 Many individuals have contributed to the design and evolution of
2583 SPDY: Adam Langley, Wan-Teh Chang, Jim Morrison, Mark Nottingham,
2584 Alyssa Wilk, Costin Manolache, William Chan, Vitaliy Lvin, Joe Chan,
2585 Adam Barth, Ryan Hamilton, Gavin Peters, Kent Alstad, Kevin Lindsay,
2586 Paul Amer, Fan Yang, Jonathan Leighton
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631Belshe & Peon Expires August 4, 2012 [Page 47]
2632
2633Internet-Draft SPDY Feb 2012
2634
2635
263610. Normative References
2637
2638 [RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
2639 RFC 793, September 1981.
2640
2641 [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform
2642 Resource Locators (URL)", RFC 1738, December 1994.
2643
2644 [RFC1950] Deutsch, L. and J-L. Gailly, "ZLIB Compressed Data Format
2645 Specification version 3.3", RFC 1950, May 1996.
2646
2647 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
2648 Requirement Levels", BCP 14, RFC 2119, March 1997.
2649
2650 [RFC2285] Mandeville, R., "Benchmarking Terminology for LAN
2651 Switching Devices", RFC 2285, February 1998.
2652
2653 [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
2654 Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
2655 Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
2656
2657 [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
2658 Leach, P., Luotonen, A., and L. Stewart, "HTTP
2659 Authentication: Basic and Digest Access Authentication",
2660 RFC 2617, June 1999.
2661
2662 [RFC4559] Jaganathan, K., Zhu, L., and J. Brezak, "SPNEGO-based
2663 Kerberos and NTLM HTTP Authentication in Microsoft
2664 Windows", RFC 4559, June 2006.
2665
2666 [RFC4366] Blake-Wilson, S., Nystrom, M., Hopwood, D., Mikkelsen, J.,
2667 and T. Wright, "Transport Layer Security (TLS)
2668 Extensions", RFC 4366, April 2006.
2669
2670 [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
2671 (TLS) Protocol Version 1.2", RFC 5246, August 2008.
2672
2673 [RFC6454] Barth, A., "The Web Origin Concept", RFC 6454,
2674 December 2011.
2675
2676 [TLSNPN] Langley, A., "TLS Next Protocol Negotiation",
2677 <http://tools.ietf.org/html/
2678 draft-agl-tls-nextprotoneg-01>.
2679
2680 [ASCII] "US-ASCII. Coded Character Set - 7-Bit American Standard
2681 Code for Information Interchange. Standard ANSI X3.4-1986,
2682 ANSI, 1986.".
2683
2684
2685
2686
2687Belshe & Peon Expires August 4, 2012 [Page 48]
2688
2689Internet-Draft SPDY Feb 2012
2690
2691
2692 [UDELCOMPRESSION]
2693 Yang, F., Amer, P., and J. Leighton, "A Methodology to
2694 Derive SPDY's Initial Dictionary for Zlib Compression",
2695 <http://www.eecis.udel.edu/~amer/PEL/poc/pdf/
2696 SPDY-Fan.pdf>.
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743Belshe & Peon Expires August 4, 2012 [Page 49]
2744
2745Internet-Draft SPDY Feb 2012
2746
2747
2748Appendix A. Changes
2749
2750 To be removed by RFC Editor before publication
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799Belshe & Peon Expires August 4, 2012 [Page 50]
2800
2801Internet-Draft SPDY Feb 2012
2802
2803
2804Authors' Addresses
2805
2806 Mike Belshe
2807 Twist
2808
2809 Email: mbelshe@chromium.org
2810
2811
2812 Roberto Peon
2813 Google, Inc
2814
2815 Email: fenix@google.com
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855Belshe & Peon Expires August 4, 2012 [Page 51]
2856
diff --git a/libmicrospdy.pc.in b/libmicrospdy.pc.in
new file mode 100644
index 00000000..fa9062fd
--- /dev/null
+++ b/libmicrospdy.pc.in
@@ -0,0 +1,13 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: libmicrospdy
7Description: A library for creating an embedded SPDY server
8Version: @VERSION@
9Requires:
10Conflicts:
11Libs: -L${libdir} -lmicrospdy
12Libs.private: @SPDY_LIBDEPS@
13Cflags: -I${includedir}
diff --git a/m4/openssl.m4 b/m4/openssl.m4
new file mode 100644
index 00000000..1317e7e4
--- /dev/null
+++ b/m4/openssl.m4
@@ -0,0 +1,69 @@
1dnl Check to find the OpenSSL headers/libraries
2
3AC_DEFUN([spdy_OPENSSL],
4[
5 AC_ARG_WITH(openssl,
6 AS_HELP_STRING([--with-openssl=DIR], [OpenSSL base directory, or:]),
7 [openssl="$withval"
8 CPPFLAGS="$CPPFLAGS -I$withval/include"
9 LDFLAGS="$LDFLAGS -L$withval/lib"]
10 )
11
12 AC_ARG_WITH(openssl-include,
13 AS_HELP_STRING([--with-openssl-include=DIR], [OpenSSL headers directory (without trailing /openssl)]),
14 [openssl_include="$withval"
15 CPPFLAGS="$CPPFLAGS -I$withval"]
16 )
17
18 AC_ARG_WITH(openssl-lib,
19 AS_HELP_STRING([--with-openssl-lib=DIR], [OpenSSL library directory]),
20 [openssl_lib="$withval"
21 LDFLAGS="$LDFLAGS -L$withval"]
22 )
23
24 AC_CHECK_HEADERS(openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h,
25 [],
26 [AC_MSG_WARN([OpenSSL header files not found.]); break]
27 )
28
29case $host_os in
30 *mingw*)
31 AC_CHECK_LIB(crypto, SHA1_Init,
32 [LIBS="$LIBS -lcrypto -lgdi32"],
33 [AC_MSG_WARN([OpenSSL libraries not found.])]
34 )
35 ;;
36 *)
37
38 AC_CHECK_LIB(crypto, SHA1_Init,
39 [LIBS="$LIBS -lcrypto"],
40 [AC_MSG_WARN([OpenSSL libraries not found.])]
41 )
42
43 AC_CHECK_FUNC(dlopen,
44 [],
45 [AC_CHECK_LIB(dl, dlopen,
46 [LIBS="$LIBS -ldl"],
47 [AC_MSG_WARN([OpenSSL depends on libdl.]); break]
48 )]
49 )
50
51 AC_CHECK_FUNC(SSL_library_init,
52 [],
53 [AC_CHECK_LIB(ssl, SSL_library_init,
54 [LIBS="$LIBS -lssl"],
55 [AC_MSG_WARN([OpenSSL?.]); break]
56 )]
57 )
58 ;;
59esac
60
61# AC_CHECK_FUNCS([RAND_pseudo_bytes EVP_EncryptInit_ex], ,
62# [AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break],
63# )
64
65# AC_CHECK_DECL([OpenSSL_add_all_algorithms], ,
66# [AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break],
67# [#include <openssl/evp.h>]
68# )
69])
diff --git a/src/Makefile.am b/src/Makefile.am
index 79b19bf5..8e9bcc2f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,4 +6,13 @@ zzuftests = testzzuf
6endif 6endif
7endif 7endif
8endif 8endif
9SUBDIRS = include microhttpd examples $(curltests) $(zzuftests) . 9if ENABLE_SPDY
10# fixme: should test for spdylay before building testspdy!
11microspdy = microspdy testspdy
12endif
13
14SUBDIRS = include microhttpd $(microspdy) examples $(curltests) $(zzuftests) .
15
16EXTRA_DIST = \
17 datadir/cert-and-key.pem \
18 datadir/cert-and-key-for-wireshark.pem
diff --git a/src/datadir/cert-and-key-for-wireshark.pem b/src/datadir/cert-and-key-for-wireshark.pem
new file mode 100644
index 00000000..eacd4b40
--- /dev/null
+++ b/src/datadir/cert-and-key-for-wireshark.pem
@@ -0,0 +1,15 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIICXgIBAAKBgQDc1k7EFEspRcr6PdPmvAd02hBDUG2O5dDkoRK+6tgEBvQxsTxz
350TGwJ8RbSV+qUOnncZBwhnI4i71QSEezMP6I6liRA+fUtdh3cZFvdDpxgU6P15y
45JxfnnDeZJR5O4tfMxN99t34EOEMruZZ0CNYJJgbmIteE0hLI418oUs7cwIDAQAB
5AoGAW3WOLXrSHge/pp/QkLCyzdw5/AblONdJCkcDQnp0eEaA/8uNY9sWCtJfjpIL
6g0eKs3KOV1GR6DZ0iDIvC1h2mO6pwyrJhRYHKPO9pnx7xpv1T9zYTuVwoMfVjPfO
7UCWFedSsSKR76+oP0TrwPDqp3JoMFcAyAqZKMg2JrRUpL3ECQQD92cVSYxSEKwX3
8cHWXVp1mSkuRMR/KX70NC/9XpYr8FEjvtXBTkmp7oG3TaDwd6nhSAodtY+Zkseyj
9k5NXM6sNAkEA3rT6opc1YK0pL3uweg+AFP4lRUYrrft1bDELhLmVm9Nf4xEdTnDO
10IotiX4GYQ64Bm8J+yxVU204soGynVXbgfwJBALQLCqq+X0TGhvrSpnRqGET+mM4n
11u1Z7xMhGJBpz7TmQ4ZIya7K6fA+m3347xbeqHyB7brYlTrlIgIAcITqOCNkCQQDE
123tuJC34mHi0ASqkw3a7t39R2rpdCT733jEuQYrY8b9id061CgDnZE7o8j0VY3uOR
13G5gWUp8W1r5gemxaAqJlAkEAwVImBKyKy3oIMsd3WsoqYCMBM+cpX8H2JAEEISPT
14Y5zSPZ7kT9JgY2zJwXf3qL+uG1oKZ6f0wn4BYujctTbXwQ==
15-----END RSA PRIVATE KEY-----
diff --git a/src/datadir/cert-and-key.pem b/src/datadir/cert-and-key.pem
new file mode 100644
index 00000000..e33608c1
--- /dev/null
+++ b/src/datadir/cert-and-key.pem
@@ -0,0 +1,34 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIICXgIBAAKBgQDc1k7EFEspRcr6PdPmvAd02hBDUG2O5dDkoRK+6tgEBvQxsTxz
350TGwJ8RbSV+qUOnncZBwhnI4i71QSEezMP6I6liRA+fUtdh3cZFvdDpxgU6P15y
45JxfnnDeZJR5O4tfMxN99t34EOEMruZZ0CNYJJgbmIteE0hLI418oUs7cwIDAQAB
5AoGAW3WOLXrSHge/pp/QkLCyzdw5/AblONdJCkcDQnp0eEaA/8uNY9sWCtJfjpIL
6g0eKs3KOV1GR6DZ0iDIvC1h2mO6pwyrJhRYHKPO9pnx7xpv1T9zYTuVwoMfVjPfO
7UCWFedSsSKR76+oP0TrwPDqp3JoMFcAyAqZKMg2JrRUpL3ECQQD92cVSYxSEKwX3
8cHWXVp1mSkuRMR/KX70NC/9XpYr8FEjvtXBTkmp7oG3TaDwd6nhSAodtY+Zkseyj
9k5NXM6sNAkEA3rT6opc1YK0pL3uweg+AFP4lRUYrrft1bDELhLmVm9Nf4xEdTnDO
10IotiX4GYQ64Bm8J+yxVU204soGynVXbgfwJBALQLCqq+X0TGhvrSpnRqGET+mM4n
11u1Z7xMhGJBpz7TmQ4ZIya7K6fA+m3347xbeqHyB7brYlTrlIgIAcITqOCNkCQQDE
123tuJC34mHi0ASqkw3a7t39R2rpdCT733jEuQYrY8b9id061CgDnZE7o8j0VY3uOR
13G5gWUp8W1r5gemxaAqJlAkEAwVImBKyKy3oIMsd3WsoqYCMBM+cpX8H2JAEEISPT
14Y5zSPZ7kT9JgY2zJwXf3qL+uG1oKZ6f0wn4BYujctTbXwQ==
15-----END RSA PRIVATE KEY-----
16-----BEGIN CERTIFICATE-----
17MIIDJTCCAo6gAwIBAgIJAIjfJkuxM1pAMA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV
18BAYTAkJHMQ4wDAYDVQQIEwVTb2ZpYTEOMAwGA1UEBxMFU29maWExCzAJBgNVBAoT
19AkFVMQ8wDQYDVQQDEwZBbmRyZXkxHjAcBgkqhkiG9w0BCQEWD3Jvb3RAZ29vZ2xl
20LmNvbTAeFw0xMjA5MDgxMTU2MzNaFw0xMzA5MDgxMTU2MzNaMGsxCzAJBgNVBAYT
21AkJHMQ4wDAYDVQQIEwVTb2ZpYTEOMAwGA1UEBxMFU29maWExCzAJBgNVBAoTAkFV
22MQ8wDQYDVQQDEwZBbmRyZXkxHjAcBgkqhkiG9w0BCQEWD3Jvb3RAZ29vZ2xlLmNv
23bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3NZOxBRLKUXK+j3T5rwHdNoQ
24Q1BtjuXQ5KESvurYBAb0MbE8c+dExsCfEW0lfqlDp53GQcIZyOIu9UEhHszD+iOp
25YkQPn1LXYd3GRb3Q6cYFOj9ecuScX55w3mSUeTuLXzMTffbd+BDhDK7mWdAjWCSY
26G5iLXhNISyONfKFLO3MCAwEAAaOB0DCBzTAdBgNVHQ4EFgQUPp4dR3IT0t6bSE3Y
27b91MyHJU2+8wgZ0GA1UdIwSBlTCBkoAUPp4dR3IT0t6bSE3Yb91MyHJU2++hb6Rt
28MGsxCzAJBgNVBAYTAkJHMQ4wDAYDVQQIEwVTb2ZpYTEOMAwGA1UEBxMFU29maWEx
29CzAJBgNVBAoTAkFVMQ8wDQYDVQQDEwZBbmRyZXkxHjAcBgkqhkiG9w0BCQEWD3Jv
30b3RAZ29vZ2xlLmNvbYIJAIjfJkuxM1pAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
31AQEFBQADgYEAeBPoIRueOJ+SwpVniE2gmnvogWH9+irJnapDKGZrC/JsTA7ArqRd
32EHO1xZxqF+v+v128LmwWAdaazgMUHjR7e7B0xo4Tcp+9+voczc/GBTO0wnp6HT76
332kUB6rPwwg9bycW8hAJiJJtr3IW5eYMtXDqM4RrbxhA1n2EAaZPVa5s=
34-----END CERTIFICATE-----
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am
index c965d8a6..f6f01bb9 100644
--- a/src/examples/Makefile.am
+++ b/src/examples/Makefile.am
@@ -9,20 +9,32 @@ AM_CPPFLAGS = \
9 -I$(top_srcdir)/src/include \ 9 -I$(top_srcdir)/src/include \
10 @LIBGCRYPT_CFLAGS@ 10 @LIBGCRYPT_CFLAGS@
11 11
12AM_CFLAGS = -DDATADIR=\"$(top_srcdir)/src/datadir/\"
13
12if USE_COVERAGE 14if USE_COVERAGE
13 AM_CFLAGS = --coverage 15 AM_CFLAGS += --coverage
16endif
17
18if ENABLE_SPDY
19spdyex = \
20 spdy_event_loop \
21 spdy_fileserver \
22 spdy_response_with_callback
14endif 23endif
15 24
25
16# example programs 26# example programs
17noinst_PROGRAMS = \ 27noinst_PROGRAMS = \
18minimal_example \ 28 minimal_example \
19dual_stack_example \ 29 dual_stack_example \
20minimal_example_comet \ 30 minimal_example_comet \
21querystring_example \ 31 querystring_example \
22fileserver_example \ 32 fileserver_example \
23fileserver_example_dirs \ 33 fileserver_example_dirs \
24fileserver_example_external_select \ 34 fileserver_example_external_select \
25refuse_post_example 35 refuse_post_example \
36 $(spdyex)
37
26 38
27if ENABLE_HTTPS 39if ENABLE_HTTPS
28noinst_PROGRAMS += https_fileserver_example 40noinst_PROGRAMS += https_fileserver_example
@@ -116,3 +128,31 @@ https_fileserver_example_SOURCES = \
116https_fileserver_example.c 128https_fileserver_example.c
117https_fileserver_example_LDADD = \ 129https_fileserver_example_LDADD = \
118 $(top_builddir)/src/microhttpd/libmicrohttpd.la 130 $(top_builddir)/src/microhttpd/libmicrohttpd.la
131
132
133spdy_event_loop_SOURCES = \
134 spdy_event_loop.c
135spdy_event_loop_LDADD = \
136 $(top_builddir)/src/microspdy/libmicrospdy.la \
137 -lssl \
138 -lcrypto \
139 -lz \
140 -ldl
141
142spdy_fileserver_SOURCES = \
143 spdy_fileserver.c
144spdy_fileserver_LDADD = \
145 $(top_builddir)/src/microspdy/libmicrospdy.la \
146 -lssl \
147 -lcrypto \
148 -lz \
149 -ldl
150
151spdy_response_with_callback_SOURCES = \
152 spdy_response_with_callback.c
153spdy_response_with_callback_LDADD = \
154 $(top_builddir)/src/microspdy/libmicrospdy.la \
155 -lssl \
156 -lcrypto \
157 -lz \
158 -ldl
diff --git a/src/examples/spdy_event_loop.c b/src/examples/spdy_event_loop.c
new file mode 100644
index 00000000..6caea07a
--- /dev/null
+++ b/src/examples/spdy_event_loop.c
@@ -0,0 +1,444 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file event_loop.c
21 * @brief shows how to use the daemon. THIS IS MAINLY A TEST AND DEBUG
22 * PROGRAM
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include <unistd.h>
28#include <stdlib.h>
29#include <stdint.h>
30#include <stdbool.h>
31#include <string.h>
32#include <stdio.h>
33#include <ctype.h>
34#include <errno.h>
35#include "microspdy.h"
36#include <sys/time.h>
37#include <time.h>
38#include <arpa/inet.h>
39//#include "../framinglayer/structures.h"
40//#include "../applicationlayer/alstructures.h"
41
42int run = 1;
43int run2 = 1;
44
45
46 uint64_t loops;
47 time_t start;
48
49
50void
51new_session_callback (void *cls,
52 struct SPDY_Session * session)
53{
54 char ipstr[1024];
55
56 struct sockaddr *addr;
57 socklen_t addr_len = SPDY_get_remote_addr(session, &addr);
58
59 if(!addr_len)
60 {
61 printf("SPDY_get_remote_addr");
62 abort();
63 }
64
65 if(AF_INET == addr->sa_family)
66 {
67 struct sockaddr_in * addr4 = (struct sockaddr_in *) addr;
68 if(NULL == inet_ntop(AF_INET, &(addr4->sin_addr), ipstr, sizeof(ipstr)))
69 {
70 printf("inet_ntop");
71 abort();
72 }
73 printf("New connection from: %s:%i\n", ipstr, ntohs(addr4->sin_port));
74
75 }
76 else if(AF_INET6 == addr->sa_family)
77 {
78 struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *) addr;
79 if(NULL == inet_ntop(AF_INET6, &(addr6->sin6_addr), ipstr, sizeof(ipstr)))
80 {
81 printf("inet_ntop");
82 abort();
83 }
84 printf("New connection from: %s:%i\n", ipstr, ntohs(addr6->sin6_port));
85
86 }
87}
88
89void
90session_closed_handler (void *cls,
91 struct SPDY_Session * session,
92 int by_client)
93{
94 //printf("session_closed_handler called\n");
95
96 if(SPDY_YES != by_client)
97 {
98 //killchild(child,"wrong by_client");
99 printf("session closed by server\n");
100 }
101 else
102 {
103 printf("session closed by client\n");
104 }
105
106 //session_closed_called = 1;
107}
108
109void
110response_done_callback(void *cls,
111 struct SPDY_Response *response,
112 struct SPDY_Request *request,
113 enum SPDY_RESPONSE_RESULT status,
114 bool streamopened)
115{
116 (void)streamopened;
117 if(strcmp(cls, "/close (daemon1)") == 0)
118 run = 0;
119 else {
120 if(strcmp(cls, "/close (daemon2)") == 0) run2 = 0;
121 loops = 0;
122 start = time(NULL);
123 }
124 if(SPDY_RESPONSE_RESULT_SUCCESS != status)
125 {
126 printf("not sent frame cause %i", status);
127 }
128 printf("answer for %s was sent\n", (char*)cls);
129 //printf("raw sent headers %s\n", (char *)(response->headers)+8);
130
131 SPDY_destroy_request(request);
132 SPDY_destroy_response(response);
133 free(cls);
134}
135
136int
137print_headers (void *cls,
138 const char *name, const char *value)
139{
140 (void)cls;
141 printf("%s: %s\n",name,value);
142 return SPDY_YES;
143}
144
145/*
146void
147new_request_cb (void *cls,
148 struct SPDY_Request * request,
149 uint8_t priority,
150 const char *method,
151 const char *path,
152 const char *version,
153 const char *host,
154 const char *scheme,
155 struct SPDY_NameValue * headers)
156{
157 (void)cls;
158 (void)request;
159 printf("Priority: %i\nHTTP headers, scheme: %s\n\n%s %s %s\nHost: %s\n", priority,scheme,method,path,version,host);
160 SPDY_name_value_iterate(headers, &print_headers, NULL);
161}
162*/
163
164int
165append_headers_to_data (void *cls,
166 const char *name, const char **value, int num_values)
167{
168 char **data = (char **)cls;
169 void *tofree = *data;
170 int i;
171
172 if(num_values)
173 for(i=0;i<num_values;++i)
174 {
175 asprintf(data,"%s%s: %s\n", *data,name,value[i]);
176 }
177 else
178 asprintf(data,"%s%s: \n", *data,name);
179
180 free(tofree);
181 return SPDY_YES;
182}
183
184void
185standard_request_handler(void *cls,
186 struct SPDY_Request * request,
187 uint8_t priority,
188 const char *method,
189 const char *path,
190 const char *version,
191 const char *host,
192 const char *scheme,
193 struct SPDY_NameValue * headers)
194{
195 char *html;
196 char *data;
197 struct SPDY_Response *response=NULL;
198
199 printf("received request for '%s %s %s'\n", method, path, version);
200 if(strcmp(path,"/main.css")==0)
201 {
202 if(NULL != cls)
203 asprintf(&html,"body{color:green;}");
204 else
205 asprintf(&html,"body{color:red;}");
206
207 //struct SPDY_NameValue *headers=SPDY_name_value_create();
208 //SPDY_name_value_add(headers,"content-type","text/css");
209
210 response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
211 free(html);
212 }
213 else
214 {
215 asprintf(&data,"Priority: %i\nHTTP headers, scheme: %s\n\n%s %s %s\nHost: %s\n", priority,scheme,method,path,version,host);
216
217 SPDY_name_value_iterate(headers, &append_headers_to_data, &data);
218
219 if(strcmp(path,"/close")==0)
220 {
221 asprintf(&html,"<html>"
222 "<body><b>Closing now!<br>This is an answer to the following "
223 "request:</b><br><br><pre>%s</pre></body></html>",data);
224 }
225 else
226 {
227 asprintf(&html,"<html><link href=\"main.css\" rel=\"stylesheet\" type=\"text/css\" />"
228 "<body><b>This is an answer to the following "
229 "request:</b><br><br><pre>%s</pre></body></html>",data);
230 }
231
232 free(data);
233
234 response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
235 free(html);
236 }
237
238 if(NULL==response){
239 fprintf(stdout,"no response obj\n");
240 abort();
241 }
242
243 char *pathcls;
244 asprintf(&pathcls, "%s (daemon%i)",path,NULL==cls ? 1 : 2);
245 if(SPDY_queue_response(request,response,true,false,&response_done_callback,pathcls)!=SPDY_YES)
246 {
247 fprintf(stdout,"queue\n");
248 abort();
249 }
250}
251
252void sig_handler(int signo)
253{
254 printf("received signal\n");
255}
256
257int
258main (int argc, char *const *argv)
259{
260 if(argc != 2) return 1;
261
262 if (signal(SIGPIPE, sig_handler) == SIG_ERR)
263 printf("\ncan't catch SIGPIPE\n");
264
265 SPDY_init();
266
267 struct sockaddr_in addr4;
268 struct in_addr inaddr4;
269 inaddr4.s_addr = htonl(INADDR_ANY);
270 addr4.sin_family = AF_INET;
271 addr4.sin_addr = inaddr4;
272 addr4.sin_port = htons(atoi(argv[1]));
273
274 struct SPDY_Daemon *daemon = SPDY_start_daemon(atoi(argv[1]),
275 DATADIR "cert-and-key.pem",
276 DATADIR "cert-and-key.pem",
277 &new_session_callback,&session_closed_handler,&standard_request_handler,NULL,NULL,
278 SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 10,
279 //SPDY_DAEMON_OPTION_SOCK_ADDR, (struct sockaddr *)&addr4,
280 SPDY_DAEMON_OPTION_END);
281
282 if(NULL==daemon){
283 printf("no daemon\n");
284 return 1;
285 }
286
287 struct sockaddr_in6 addr6;
288 addr6.sin6_family = AF_INET6;
289 addr6.sin6_addr = in6addr_any;
290 addr6.sin6_port = htons(atoi(argv[1]) + 1);
291
292 struct SPDY_Daemon *daemon2 = SPDY_start_daemon(atoi(argv[1]) + 1,
293 DATADIR "cert-and-key.pem",
294 DATADIR "cert-and-key.pem",
295 &new_session_callback,NULL,&standard_request_handler,NULL,&main,
296 //SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 0,
297 //SPDY_DAEMON_OPTION_SOCK_ADDR, (struct sockaddr *)&addr6,
298 //SPDY_DAEMON_OPTION_FLAGS, SPDY_DAEMON_FLAG_ONLY_IPV6,
299 SPDY_DAEMON_OPTION_END);
300
301 if(NULL==daemon2){
302 printf("no daemon\n");
303 return 1;
304 }
305
306 do
307 {
308 unsigned long long timeoutlong=0;
309 struct timeval timeout;
310 volatile int rc; /* select() return code */
311 volatile int ret;
312
313 fd_set read_fd_set;
314 fd_set write_fd_set;
315 fd_set except_fd_set;
316 int maxfd = -1;
317
318 if(run && daemon != NULL)
319 {
320 loops++;
321 FD_ZERO(&read_fd_set);
322 FD_ZERO(&write_fd_set);
323 FD_ZERO(&except_fd_set);
324
325 ret = SPDY_get_timeout(daemon, &timeoutlong);
326 //printf("tout %i\n",timeoutlong);
327 if(SPDY_NO == ret || timeoutlong > 1)
328 {
329 //do sth else
330 //sleep(1);
331
332 //try new connection
333 timeout.tv_sec = 1;
334 timeout.tv_usec = 0;
335 }
336 else
337 {
338 timeout.tv_sec = timeoutlong;
339 timeout.tv_usec = 0;//(timeoutlong % 1000) * 1000;
340 }
341
342 printf("ret=%i; timeoutlong=%i; sec=%i; usec=%i\n", ret, timeoutlong, timeout.tv_sec, timeout.tv_usec);
343 //raise(SIGINT);
344
345 /* get file descriptors from the transfers */
346 maxfd = SPDY_get_fdset (daemon,
347 &read_fd_set,
348 &write_fd_set,
349 &except_fd_set);
350
351//struct timeval ts1,ts2;
352 //gettimeofday(&ts1, NULL);
353 rc = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
354 //gettimeofday(&ts2, NULL);
355 printf("rc %i\n",rc);
356 // printf("time for select %i\n",ts2.tv_usec - ts1.tv_usec);
357 // printf("%i %i %i %i\n",ts1.tv_sec, ts1.tv_usec,ts2.tv_sec, ts2.tv_usec);
358
359 switch(rc) {
360 case -1:
361 /* select error */
362 break;
363 case 0:
364
365 break;
366 default:
367 SPDY_run(daemon);
368
369 break;
370 }
371 }
372 else if(daemon != NULL){
373
374 printf("%i loops in %i secs\n", loops, time(NULL) - start);
375 SPDY_stop_daemon(daemon);
376 daemon=NULL;
377 }
378
379 if(run2)
380 {
381 FD_ZERO(&read_fd_set);
382 FD_ZERO(&write_fd_set);
383 FD_ZERO(&except_fd_set);
384
385 ret = SPDY_get_timeout(daemon2, &timeoutlong);
386 //printf("tout %i\n",timeoutlong);
387 if(SPDY_NO == ret || timeoutlong > 1)
388 {
389 //do sth else
390 //sleep(1);
391
392 //try new connection
393 timeout.tv_sec = 1;
394 timeout.tv_usec = 0;
395 }
396 else
397 {
398 timeout.tv_sec = timeoutlong;
399 timeout.tv_usec = 0;//(timeoutlong % 1000) * 1000;
400 }
401
402 //printf("ret=%i; timeoutlong=%i; sec=%i; usec=%i\n", ret, timeoutlong, timeout.tv_sec, timeout.tv_usec);
403 //raise(SIGINT);
404
405 /* get file descriptors from the transfers */
406 maxfd = SPDY_get_fdset (daemon2,
407 &read_fd_set,
408 &write_fd_set,
409 &except_fd_set);
410
411 rc = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
412
413 switch(rc) {
414 case -1:
415 /* select error */
416 break;
417 case 0:
418
419 break;
420 default:
421 SPDY_run(daemon2);
422
423 break;
424 }
425 }
426 else if(daemon2 != NULL){
427 SPDY_stop_daemon(daemon2);
428 daemon2=NULL;
429 }
430 }
431 while(run || run2);
432
433 if(daemon != NULL){
434 SPDY_stop_daemon(daemon);
435 }
436 if(daemon2 != NULL){
437 SPDY_stop_daemon(daemon2);
438 }
439
440 SPDY_deinit();
441
442 return 0;
443}
444
diff --git a/src/examples/spdy_fileserver.c b/src/examples/spdy_fileserver.c
new file mode 100644
index 00000000..a59b6e9e
--- /dev/null
+++ b/src/examples/spdy_fileserver.c
@@ -0,0 +1,340 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file fileserver.c
21 * @brief Simple example how the lib can be used for serving
22 * files directly read from the system
23 * @author Andrey Uzunov
24 */
25
26#include <unistd.h>
27#include <stdlib.h>
28#include <stdint.h>
29#include <stdbool.h>
30#include <string.h>
31#include <stdio.h>
32#include <ctype.h>
33#include <errno.h>
34#include "microspdy.h"
35#include "time.h"
36
37
38int run = 1;
39char* basedir;
40
41
42#define GET_MIME_TYPE(fname, mime) do {\
43 uint __len = strlen(fname);\
44 if (__len < 4 || '.' != (fname)[__len - 4]) break;\
45 const char * __ext = &(fname)[__len - 3];\
46 if(0 == strcmp(__ext, "jpg")) (mime) = strdup("image/jpeg");\
47 else if(0 == strcmp(__ext, "png")) (mime) = strdup("image/png");\
48 else if(0 == strcmp(__ext, "css")) (mime) = strdup("text/css");\
49 else if(0 == strcmp(__ext, "gif")) (mime) = strdup("image/gif");\
50 else if(0 == strcmp(__ext, "htm")) (mime) = strdup("text/html");\
51 else \
52 { \
53 (mime) = strdup("application/octet-stream");\
54 printf("MIME for %s is applic...\n", (fname));\
55 }\
56 if(NULL == (mime))\
57 {\
58 printf("no memory\n");\
59 abort();\
60 }\
61 } while (0)
62
63
64static const char *DAY_NAMES[] =
65 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
66
67static const char *MONTH_NAMES[] =
68 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
69 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
70
71//taken from http://stackoverflow.com/questions/2726975/how-can-i-generate-an-rfc1123-date-string-from-c-code-win32
72//and modified for linux
73char *Rfc1123_DateTimeNow()
74{
75 const int RFC1123_TIME_LEN = 29;
76 time_t t;
77 struct tm tm;
78 char * buf = malloc(RFC1123_TIME_LEN+1);
79
80 time(&t);
81 gmtime_r( &t, &tm);
82
83 strftime(buf, RFC1123_TIME_LEN+1, "---, %d --- %Y %H:%M:%S GMT", &tm);
84 memcpy(buf, DAY_NAMES[tm.tm_wday], 3);
85 memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
86
87 return buf;
88}
89
90
91ssize_t
92response_callback (void *cls,
93 void *buffer,
94 size_t max,
95 bool *more)
96{
97 FILE *fd =(FILE*)cls;
98
99 int ret = fread(buffer,1,max,fd);
100 *more = feof(fd) == 0;
101
102 //if(!(*more))
103 // fclose(fd);
104
105 return ret;
106}
107
108
109void
110response_done_callback(void *cls,
111 struct SPDY_Response *response,
112 struct SPDY_Request *request,
113 enum SPDY_RESPONSE_RESULT status,
114 bool streamopened)
115{
116 (void)streamopened;
117 //printf("answer for %s was sent\n", (char *)cls);
118
119 /*if(SPDY_RESPONSE_RESULT_SUCCESS != status)
120 {
121 printf("answer for %s was NOT sent, %i\n", (char *)cls,status);
122 }*/
123
124 SPDY_destroy_request(request);
125 SPDY_destroy_response(response);
126 if(NULL!=cls)fclose(cls);
127}
128
129void
130standard_request_handler(void *cls,
131 struct SPDY_Request * request,
132 uint8_t priority,
133 const char *method,
134 const char *path,
135 const char *version,
136 const char *host,
137 const char *scheme,
138 struct SPDY_NameValue * headers)
139{
140 (void)cls;
141 (void)request;
142 (void)priority;
143 (void)host;
144 (void)scheme;
145 (void)headers;
146
147 struct SPDY_Response *response=NULL;
148 struct SPDY_NameValue *resp_headers;
149 char *fname;
150 char *fsize;
151 char *mime=NULL;
152 char *date=NULL;
153 ssize_t filesize = -666;
154 FILE *fd = NULL;
155 int ret = -666;
156
157 //printf("received request for '%s %s %s'\n", method, path, version);
158 if(strlen(path) > 1 && NULL == strstr(path, "..") && '/' == path[0])
159 {
160 asprintf(&fname,"%s%s",basedir,path);
161 if(0 == access(fname, R_OK))
162 {
163 if(NULL == (fd = fopen(fname,"r"))
164 || 0 != (ret = fseek(fd, 0L, SEEK_END))
165 || -1 == (filesize = ftell(fd))
166 || 0 != (ret = fseek(fd, 0L, SEEK_SET)))
167 {
168 printf("Error on opening %s\n%i %i %i\n",fname, fd, ret, filesize);
169 response = SPDY_build_response(SPDY_HTTP_INTERNAL_SERVER_ERROR,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
170 }
171 else
172 {
173 if(NULL == (resp_headers = SPDY_name_value_create()))
174 {
175 printf("SPDY_name_value_create failed\n");
176 abort();
177 }
178
179 date = Rfc1123_DateTimeNow();
180 if(NULL == date
181 || SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_DATE,date))
182 {
183 printf("SPDY_name_value_add or Rfc1123_DateTimeNow failed\n");
184 abort();
185 }
186 free(date);
187
188 if(-1 == asprintf(&fsize, "%i", filesize)
189 || SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_LENGTH,fsize))
190 {
191 printf("SPDY_name_value_add or asprintf failed\n");
192 abort();
193 }
194 free(fsize);
195
196 GET_MIME_TYPE(path,mime);
197 if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,mime))
198 {
199 printf("SPDY_name_value_add failed\n");
200 abort();
201 }
202 free(mime);
203
204 if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_SERVER,"libmicrospdy/fileserver"))
205 {
206 printf("SPDY_name_value_add failed\n");
207 abort();
208 }
209
210 response = SPDY_build_response_with_callback(200,NULL,
211 SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
212 SPDY_name_value_destroy(resp_headers);
213 }
214
215 if(NULL==response){
216 printf("no response obj\n");
217 abort();
218 }
219
220 if(SPDY_queue_response(request,response,true,false,&response_done_callback,fd)!=SPDY_YES)
221 {
222 printf("queue\n");
223 abort();
224 }
225
226 free(fname);
227 return;
228 }
229 free(fname);
230 }
231
232 if(strcmp(path,"/close")==0)
233 {
234 run = 0;
235 }
236
237 response = SPDY_build_response(SPDY_HTTP_NOT_FOUND,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
238 printf("Not found %s\n",path);
239
240 if(NULL==response){
241 printf("no response obj\n");
242 abort();
243 }
244
245 if(SPDY_queue_response(request,response,true,false,&response_done_callback,NULL)!=SPDY_YES)
246 {
247 printf("queue\n");
248 abort();
249 }
250}
251
252int
253main (int argc, char *const *argv)
254{
255 unsigned long long timeoutlong=0;
256 struct timeval timeout;
257 int ret;
258 fd_set read_fd_set;
259 fd_set write_fd_set;
260 fd_set except_fd_set;
261 int maxfd = -1;
262 struct SPDY_Daemon *daemon;
263
264 if(argc != 5)
265 {
266 printf("Usage: %s cert-file key-file base-dir port\n", argv[0]);
267 return 1;
268 }
269
270 SPDY_init();
271
272 daemon = SPDY_start_daemon(atoi(argv[4]),
273 argv[1],
274 argv[2],
275 NULL,
276 NULL,
277 &standard_request_handler,
278 NULL,
279 NULL,
280 SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
281 1800,
282 SPDY_DAEMON_OPTION_END);
283
284 if(NULL==daemon){
285 printf("no daemon\n");
286 return 1;
287 }
288
289 basedir = argv[3];
290 timeout.tv_usec = 0;
291
292 do
293 {
294 FD_ZERO(&read_fd_set);
295 FD_ZERO(&write_fd_set);
296 FD_ZERO(&except_fd_set);
297
298 ret = SPDY_get_timeout(daemon, &timeoutlong);
299 if(SPDY_NO == ret || timeoutlong > 1)
300 {
301 //do sth else
302 //sleep(1);
303
304 //try new connection
305 timeout.tv_sec = 1;
306 }
307 else
308 {
309 timeout.tv_sec = timeoutlong;
310 }
311
312 maxfd = SPDY_get_fdset (daemon,
313 &read_fd_set,
314 &write_fd_set,
315 &except_fd_set);
316
317 ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
318
319 switch(ret) {
320 case -1:
321 printf("select error: %i\n", errno);
322 break;
323 case 0:
324
325 break;
326 default:
327 SPDY_run(daemon);
328
329 break;
330 }
331 }
332 while(run);
333
334 SPDY_stop_daemon(daemon);
335
336 SPDY_deinit();
337
338 return 0;
339}
340
diff --git a/src/examples/spdy_response_with_callback.c b/src/examples/spdy_response_with_callback.c
new file mode 100644
index 00000000..f8a17442
--- /dev/null
+++ b/src/examples/spdy_response_with_callback.c
@@ -0,0 +1,230 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file response_with_callback.c
21 * @brief shows how to create responses with callbacks
22 * @author Andrey Uzunov
23 */
24
25#include <unistd.h>
26#include <stdlib.h>
27#include <stdint.h>
28#include <stdbool.h>
29#include <string.h>
30#include <stdio.h>
31#include <ctype.h>
32#include <errno.h>
33#include "microspdy.h"
34
35int run = 1;
36
37
38ssize_t
39response_callback (void *cls,
40 void *buffer,
41 size_t max,
42 bool *more)
43{
44 FILE *fd =(FILE*)cls;
45
46 int ret = fread(buffer,1,max,fd);
47 *more = feof(fd) == 0;
48
49 if(!(*more))
50 fclose(fd);
51
52 return ret;
53}
54
55
56void
57response_done_callback(void *cls,
58 struct SPDY_Response *response,
59 struct SPDY_Request *request,
60 bool streamopened)
61{
62 (void)streamopened;
63 printf("answer for %s was sent\n", (char *)cls);
64
65 SPDY_destroy_request(request);
66 SPDY_destroy_response(response);
67 free(cls);
68}
69
70void
71standard_request_handler(void *cls,
72 struct SPDY_Request * request,
73 uint8_t priority,
74 const char *method,
75 const char *path,
76 const char *version,
77 const char *host,
78 const char *scheme,
79 struct SPDY_NameValue * headers)
80{
81 (void)cls;
82 (void)request;
83 (void)priority;
84 (void)host;
85 (void)scheme;
86 (void)headers;
87
88 char *html;
89 struct SPDY_Response *response=NULL;
90 struct SPDY_NameValue *resp_headers;
91
92 printf("received request for '%s %s %s'\n", method, path, version);
93 if(strcmp(path,"/spdy-draft.txt")==0)
94 {
95 FILE *fd = fopen(DATADIR "spdy-draft.txt","r");
96
97 if(NULL == (resp_headers = SPDY_name_value_create()))
98 {
99 fprintf(stdout,"SPDY_name_value_create failed\n");
100 abort();
101 }
102 if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,"text/plain"))
103 {
104 fprintf(stdout,"SPDY_name_value_add failed\n");
105 abort();
106 }
107
108 response = SPDY_build_response_with_callback(200,NULL,
109 SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
110 SPDY_name_value_destroy(resp_headers);
111 }
112 else
113 {
114 if(strcmp(path,"/close")==0)
115 {
116 asprintf(&html,"<html>"
117 "<body><b>Closing now!</body></html>");
118 run = 0;
119 }
120 else
121 {
122 asprintf(&html,"<html>"
123 "<body><a href=\"/spdy-draft.txt\">/spdy-draft.txt</a><br></body></html>");
124 }
125
126 response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
127 free(html);
128 }
129
130 if(NULL==response){
131 fprintf(stdout,"no response obj\n");
132 abort();
133 }
134
135 void *clspath = strdup(path);
136
137 if(SPDY_queue_response(request,response,true,false,&response_done_callback,clspath)!=SPDY_YES)
138 {
139 fprintf(stdout,"queue\n");
140 abort();
141 }
142}
143
144int
145main (int argc, char *const *argv)
146{
147 unsigned long long timeoutlong=0;
148 struct timeval timeout;
149 int ret;
150 fd_set read_fd_set;
151 fd_set write_fd_set;
152 fd_set except_fd_set;
153 int maxfd = -1;
154 struct SPDY_Daemon *daemon;
155
156 if(argc != 2)
157 {
158 return 1;
159 }
160
161 SPDY_init();
162
163 daemon = SPDY_start_daemon(atoi(argv[1]),
164 DATADIR "cert-and-key.pem",
165 DATADIR "cert-and-key.pem",
166 NULL,
167 NULL,
168 &standard_request_handler,
169 NULL,
170 NULL,
171 SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
172 1800,
173 SPDY_DAEMON_OPTION_END);
174
175 if(NULL==daemon){
176 printf("no daemon\n");
177 return 1;
178 }
179
180 timeout.tv_usec = 0;
181
182 do
183 {
184 FD_ZERO(&read_fd_set);
185 FD_ZERO(&write_fd_set);
186 FD_ZERO(&except_fd_set);
187
188 ret = SPDY_get_timeout(daemon, &timeoutlong);
189 if(SPDY_NO == ret || timeoutlong > 1)
190 {
191 //do sth else
192 //sleep(1);
193
194 //try new connection
195 timeout.tv_sec = 1;
196 }
197 else
198 {
199 timeout.tv_sec = timeoutlong;
200 }
201
202 maxfd = SPDY_get_fdset (daemon,
203 &read_fd_set,
204 &write_fd_set,
205 &except_fd_set);
206
207 ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
208
209 switch(ret) {
210 case -1:
211 printf("select error: %i\n", errno);
212 break;
213 case 0:
214
215 break;
216 default:
217 SPDY_run(daemon);
218
219 break;
220 }
221 }
222 while(run);
223
224 SPDY_stop_daemon(daemon);
225
226 SPDY_deinit();
227
228 return 0;
229}
230
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 65a71229..cce55616 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -1,4 +1,9 @@
1SUBDIRS = plibc . 1SUBDIRS = plibc .
2include_HEADERS = microhttpd.h 2
3if ENABLE_SPDY
4microspdy = microspdy.h
5endif
6
7include_HEADERS = microhttpd.h $(microspdy)
3 8
4EXTRA_DIST = platform.h 9EXTRA_DIST = platform.h
diff --git a/src/include/microspdy.h b/src/include/microspdy.h
new file mode 100644
index 00000000..ac9123b8
--- /dev/null
+++ b/src/include/microspdy.h
@@ -0,0 +1,1275 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012, 2013 Christian Grothoff
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file microspdy.h
21 * @brief public interface to libmicrospdy
22 * @author Andrey Uzunov
23 * @author Christian Grothoff
24 *
25 * All symbols defined in this header start with SPDY_. libmisrospdy is a small
26 * SPDY daemon library. The application can start multiple daemons
27 * and they are independent.<p>
28 *
29 * The header file defines various constants used by the SPDY and the HTTP protocol.
30 * This does not mean that the lib actually interprets all of these
31 * values. Not everything is implemented. The provided constants are exported as a convenience
32 * for users of the library. The lib does not verify that provided
33 * HTTP headers and if their values conform to the SPDY protocol,
34 * it only checks if the required headers for the SPDY requests and
35 * responses are provided.<p>
36 *
37 * The library uses just a single thread.<p>
38 *
39 * Before including "microspdy.h" you should add the necessary
40 * includes to define the types used in this file (which headers are needed may
41 * depend on your platform; for possible suggestions consult
42 * "platform.h" in the libmicrospdy distribution).<p>
43 *
44 * All of the functions returning SPDY_YES/SPDY_NO return
45 * SPDY_INPUT_ERROR when any of the parameters are invalid, e.g.,
46 * required parameter is NULL.
47 */
48#ifndef SPDY_MICROSPDY_H
49#define SPDY_MICROSPDY_H
50
51#include <zlib.h>
52#include <stdbool.h>
53
54/**
55 * return code for "YES".
56 */
57#define SPDY_YES 1
58
59/**
60 * return code for "NO".
61 */
62#define SPDY_NO 0
63
64/**
65 * return code for error when input parameters are wrong. To be returned
66 * only by functions which return int. The others will return NULL on
67 * input error.
68 */
69#define SPDY_INPUT_ERROR -1
70
71/**
72 * SPDY version supported by the lib.
73 */
74#define SPDY_VERSION 3
75
76/**
77 * The maximum allowed size (without 8 byte headers) of
78 * SPDY frames (value length) is 8192. The lib will accept and
79 * send frames with length at most this value here.
80 */
81#define SPDY_MAX_SUPPORTED_FRAME_SIZE 8192
82
83/**
84 * HTTP response codes.
85 */
86#define SPDY_HTTP_CONTINUE 100
87#define SPDY_HTTP_SWITCHING_PROTOCOLS 101
88#define SPDY_HTTP_PROCESSING 102
89
90#define SPDY_HTTP_OK 200
91#define SPDY_HTTP_CREATED 201
92#define SPDY_HTTP_ACCEPTED 202
93#define SPDY_HTTP_NON_AUTHORITATIVE_INFORMATION 203
94#define SPDY_HTTP_NO_CONTENT 204
95#define SPDY_HTTP_RESET_CONTENT 205
96#define SPDY_HTTP_PARTIAL_CONTENT 206
97#define SPDY_HTTP_MULTI_STATUS 207
98
99#define SPDY_HTTP_MULTIPLE_CHOICES 300
100#define SPDY_HTTP_MOVED_PERMANENTLY 301
101#define SPDY_HTTP_FOUND 302
102#define SPDY_HTTP_SEE_OTHER 303
103#define SPDY_HTTP_NOT_MODIFIED 304
104#define SPDY_HTTP_USE_PROXY 305
105#define SPDY_HTTP_SWITCH_PROXY 306
106#define SPDY_HTTP_TEMPORARY_REDIRECT 307
107
108#define SPDY_HTTP_BAD_REQUEST 400
109#define SPDY_HTTP_UNAUTHORIZED 401
110#define SPDY_HTTP_PAYMENT_REQUIRED 402
111#define SPDY_HTTP_FORBIDDEN 403
112#define SPDY_HTTP_NOT_FOUND 404
113#define SPDY_HTTP_METHOD_NOT_ALLOWED 405
114#define SPDY_HTTP_METHOD_NOT_ACCEPTABLE 406
115#define SPDY_HTTP_PROXY_AUTHENTICATION_REQUIRED 407
116#define SPDY_HTTP_REQUEST_TIMEOUT 408
117#define SPDY_HTTP_CONFLICT 409
118#define SPDY_HTTP_GONE 410
119#define SPDY_HTTP_LENGTH_REQUIRED 411
120#define SPDY_HTTP_PRECONDITION_FAILED 412
121#define SPDY_HTTP_REQUEST_ENTITY_TOO_LARGE 413
122#define SPDY_HTTP_REQUEST_URI_TOO_LONG 414
123#define SPDY_HTTP_UNSUPPORTED_MEDIA_TYPE 415
124#define SPDY_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416
125#define SPDY_HTTP_EXPECTATION_FAILED 417
126#define SPDY_HTTP_UNPROCESSABLE_ENTITY 422
127#define SPDY_HTTP_LOCKED 423
128#define SPDY_HTTP_FAILED_DEPENDENCY 424
129#define SPDY_HTTP_UNORDERED_COLLECTION 425
130#define SPDY_HTTP_UPGRADE_REQUIRED 426
131#define SPDY_HTTP_NO_RESPONSE 444
132#define SPDY_HTTP_RETRY_WITH 449
133#define SPDY_HTTP_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS 450
134#define SPDY_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS 451
135
136#define SPDY_HTTP_INTERNAL_SERVER_ERROR 500
137#define SPDY_HTTP_NOT_IMPLEMENTED 501
138#define SPDY_HTTP_BAD_GATEWAY 502
139#define SPDY_HTTP_SERVICE_UNAVAILABLE 503
140#define SPDY_HTTP_GATEWAY_TIMEOUT 504
141#define SPDY_HTTP_HTTP_VERSION_NOT_SUPPORTED 505
142#define SPDY_HTTP_VARIANT_ALSO_NEGOTIATES 506
143#define SPDY_HTTP_INSUFFICIENT_STORAGE 507
144#define SPDY_HTTP_BANDWIDTH_LIMIT_EXCEEDED 509
145#define SPDY_HTTP_NOT_EXTENDED 510
146
147/**
148 * HTTP headers are used in SPDY, but all of them MUST be lowercase.
149 * Some are not valid in SPDY and MUST not be used
150 */
151#define SPDY_HTTP_HEADER_ACCEPT "accept"
152#define SPDY_HTTP_HEADER_ACCEPT_CHARSET "accept-charset"
153#define SPDY_HTTP_HEADER_ACCEPT_ENCODING "accept-encoding"
154#define SPDY_HTTP_HEADER_ACCEPT_LANGUAGE "accept-language"
155#define SPDY_HTTP_HEADER_ACCEPT_RANGES "accept-ranges"
156#define SPDY_HTTP_HEADER_AGE "age"
157#define SPDY_HTTP_HEADER_ALLOW "allow"
158#define SPDY_HTTP_HEADER_AUTHORIZATION "authorization"
159#define SPDY_HTTP_HEADER_CACHE_CONTROL "cache-control"
160/* Connection header is forbidden in SPDY */
161#define SPDY_HTTP_HEADER_CONNECTION "connection"
162#define SPDY_HTTP_HEADER_CONTENT_ENCODING "content-encoding"
163#define SPDY_HTTP_HEADER_CONTENT_LANGUAGE "content-language"
164#define SPDY_HTTP_HEADER_CONTENT_LENGTH "content-length"
165#define SPDY_HTTP_HEADER_CONTENT_LOCATION "content-location"
166#define SPDY_HTTP_HEADER_CONTENT_MD5 "content-md5"
167#define SPDY_HTTP_HEADER_CONTENT_RANGE "content-range"
168#define SPDY_HTTP_HEADER_CONTENT_TYPE "content-type"
169#define SPDY_HTTP_HEADER_COOKIE "cookie"
170#define SPDY_HTTP_HEADER_DATE "date"
171#define SPDY_HTTP_HEADER_ETAG "etag"
172#define SPDY_HTTP_HEADER_EXPECT "expect"
173#define SPDY_HTTP_HEADER_EXPIRES "expires"
174#define SPDY_HTTP_HEADER_FROM "from"
175/* Host header is forbidden in SPDY */
176#define SPDY_HTTP_HEADER_HOST "host"
177#define SPDY_HTTP_HEADER_IF_MATCH "if-match"
178#define SPDY_HTTP_HEADER_IF_MODIFIED_SINCE "if-modified-since"
179#define SPDY_HTTP_HEADER_IF_NONE_MATCH "if-none-match"
180#define SPDY_HTTP_HEADER_IF_RANGE "if-range"
181#define SPDY_HTTP_HEADER_IF_UNMODIFIED_SINCE "if-unmodified-since"
182/* Keep-Alive header is forbidden in SPDY */
183#define SPDY_HTTP_HEADER_KEEP_ALIVE "keep-alive"
184#define SPDY_HTTP_HEADER_LAST_MODIFIED "last-modified"
185#define SPDY_HTTP_HEADER_LOCATION "location"
186#define SPDY_HTTP_HEADER_MAX_FORWARDS "max-forwards"
187#define SPDY_HTTP_HEADER_PRAGMA "pragma"
188#define SPDY_HTTP_HEADER_PROXY_AUTHENTICATE "proxy-authenticate"
189#define SPDY_HTTP_HEADER_PROXY_AUTHORIZATION "proxy-authorization"
190/* Proxy-Connection header is forbidden in SPDY */
191#define SPDY_HTTP_HEADER_PROXY_CONNECTION "proxy-connection"
192#define SPDY_HTTP_HEADER_RANGE "range"
193#define SPDY_HTTP_HEADER_REFERER "referer"
194#define SPDY_HTTP_HEADER_RETRY_AFTER "retry-after"
195#define SPDY_HTTP_HEADER_SERVER "server"
196#define SPDY_HTTP_HEADER_SET_COOKIE "set-cookie"
197#define SPDY_HTTP_HEADER_SET_COOKIE2 "set-cookie2"
198#define SPDY_HTTP_HEADER_TE "te"
199#define SPDY_HTTP_HEADER_TRAILER "trailer"
200/* Transfer-Encoding header is forbidden in SPDY */
201#define SPDY_HTTP_HEADER_TRANSFER_ENCODING "transfer-encoding"
202#define SPDY_HTTP_HEADER_UPGRADE "upgrade"
203#define SPDY_HTTP_HEADER_USER_AGENT "user-agent"
204#define SPDY_HTTP_HEADER_VARY "vary"
205#define SPDY_HTTP_HEADER_VIA "via"
206#define SPDY_HTTP_HEADER_WARNING "warning"
207#define SPDY_HTTP_HEADER_WWW_AUTHENTICATE "www-authenticate"
208
209/**
210 * HTTP versions (a value must be provided in SPDY requests/responses).
211 */
212#define SPDY_HTTP_VERSION_1_0 "HTTP/1.0"
213#define SPDY_HTTP_VERSION_1_1 "HTTP/1.1"
214
215/**
216 * HTTP methods
217 */
218#define SPDY_HTTP_METHOD_CONNECT "CONNECT"
219#define SPDY_HTTP_METHOD_DELETE "DELETE"
220#define SPDY_HTTP_METHOD_GET "GET"
221#define SPDY_HTTP_METHOD_HEAD "HEAD"
222#define SPDY_HTTP_METHOD_OPTIONS "OPTIONS"
223#define SPDY_HTTP_METHOD_POST "POST"
224#define SPDY_HTTP_METHOD_PUT "PUT"
225#define SPDY_HTTP_METHOD_TRACE "TRACE"
226
227/**
228 * HTTP POST encodings, see also
229 * http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
230 */
231#define SPDY_HTTP_POST_ENCODING_FORM_URLENCODED "application/x-www-form-urlencoded"
232#define SPDY_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data"
233
234
235/**
236 * Handle for the daemon (listening on a socket).
237 */
238struct SPDY_Daemon;
239
240
241/**
242 * Handle for a SPDY session/connection.
243 */
244struct SPDY_Session;
245
246
247/**
248 * Handle for a SPDY request sent by a client. The structure has pointer
249 * to the session's handler
250 */
251struct SPDY_Request;
252
253
254/**
255 * Handle for a response containing HTTP headers and data to be sent.
256 * The structure has pointer to the session's handler
257 * for this response.
258 */
259struct SPDY_Response;
260
261
262/**
263 * Collection of tuples of an HTTP header and values used in requests
264 * and responses.
265 */
266struct SPDY_NameValue;
267
268
269/**
270 * Collection of tuples of a SPDY setting ID, value
271 * and flags used to control the sessions.
272 */
273struct SPDY_Settings;
274
275
276/**
277 * SPDY daemon options. Passed in the varargs portion of
278 * SPDY_start_daemon to customize the daemon. Each option must
279 * be followed by a value of a specific type.<p>
280 *
281 * The values are used internally as flags, that is why they must be
282 * powers of 2.
283 */
284enum SPDY_DAEMON_OPTION
285{
286
287 /**
288 * No more options / last option. This is used
289 * to terminate the VARARGs list.
290 */
291 SPDY_DAEMON_OPTION_END = 0,
292
293 /**
294 * Set a custom timeout for all connections. Must be followed by
295 * a number of seconds, given as an 'unsigned int'. Use
296 * zero for no timeout.
297 */
298 SPDY_DAEMON_OPTION_SESSION_TIMEOUT = 1,
299
300 /**
301 * Bind daemon to the supplied sockaddr. This option must be
302 * followed by a 'struct sockaddr *'. The 'struct sockaddr*'
303 * should point to a 'struct sockaddr_in6' or to a
304 * 'struct sockaddr_in'.
305 */
306 SPDY_DAEMON_OPTION_SOCK_ADDR = 2,
307
308 /**
309 * Flags for the daemon. Must be followed by a SPDY_DAEMON_FLAG value
310 * which is the result of bitwise OR of desired flags.
311 */
312 SPDY_DAEMON_OPTION_FLAGS = 4,
313};
314
315
316/**
317 * Flags for starting SPDY daemon. They are used to set some settings
318 * for the daemon, which do not require values.
319 */
320enum SPDY_DAEMON_FLAG
321{
322 /**
323 * No flags selected.
324 */
325 SPDY_DAEMON_FLAG_NO = 0,
326
327 /**
328 * The server will bind only on IPv6 addresses. If the flag is set and
329 * the daemon is provided with IPv4 address or IPv6 is not supported,
330 * starting daemon will fail.
331 */
332 SPDY_DAEMON_FLAG_ONLY_IPV6 = 1,
333};
334
335
336/**
337 * SPDY settings IDs sent by both client and server in SPDY SETTINGS frame.
338 * They affect the whole SPDY session. Defined in SPDY Protocol - Draft 3.
339 */
340enum SPDY_SETTINGS
341{
342
343 /**
344 * Allows the sender to send its expected upload bandwidth on this
345 * channel. This number is an estimate. The value should be the
346 * integral number of kilobytes per second that the sender predicts
347 * as an expected maximum upload channel capacity.
348 */
349 SPDY_SETTINGS_UPLOAD_BANDWIDTH = 1,
350
351 /**
352 * Allows the sender to send its expected download bandwidth on this
353 * channel. This number is an estimate. The value should be the
354 * integral number of kilobytes per second that the sender predicts as
355 * an expected maximum download channel capacity.
356 */
357 SPDY_SETTINGS_DOWNLOAD_BANDWIDTH = 2,
358
359 /**
360 * Allows the sender to send its expected round-trip-time on this
361 * channel. The round trip time is defined as the minimum amount of
362 * time to send a control frame from this client to the remote and
363 * receive a response. The value is represented in milliseconds.
364 */
365 SPDY_SETTINGS_ROUND_TRIP_TIME = 3,
366
367 /**
368 * Allows the sender to inform the remote endpoint the maximum number
369 * of concurrent streams which it will allow. By default there is no
370 * limit. For implementors it is recommended that this value be no
371 * smaller than 100.
372 */
373 SPDY_SETTINGS_MAX_CONCURRENT_STREAMS = 4,
374
375 /**
376 * Allows the sender to inform the remote endpoint of the current TCP
377 * CWND value.
378 */
379 SPDY_SETTINGS_CURRENT_CWND = 5,
380
381 /**
382 * Allows the sender to inform the remote endpoint the retransmission
383 * rate (bytes retransmitted / total bytes transmitted).
384 */
385 SPDY_SETTINGS_DOWNLOAD_RETRANS_RATE = 6,
386
387 /**
388 * Allows the sender to inform the remote endpoint the initial window
389 * size (in bytes) for new streams.
390 */
391 SPDY_SETTINGS_INITIAL_WINDOW_SIZE = 7,
392
393 /**
394 * Allows the server to inform the client if the new size of the
395 * client certificate vector.
396 */
397 SPDY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8,
398};
399
400
401/**
402 * Flags for each individual SPDY setting in the SPDY SETTINGS frame.
403 * They affect only one setting to which they are set.
404 * Defined in SPDY Protocol - Draft 3.
405 */
406enum SPDY_FLAG_SETTINGS{
407
408 /**
409 * When set, the sender of this SETTINGS frame is requesting that the
410 * recipient persist the ID/Value and return it in future SETTINGS
411 * frames sent from the sender to this recipient. Because persistence
412 * is only implemented on the client, this flag is only sent by the
413 * server.
414 */
415 SPDY_FLAG_SETTINGS_PERSIST_VALUE = 1,
416
417 /**
418 * When set, the sender is notifying the recipient that this ID/Value
419 * pair was previously sent to the sender by the recipient with the
420 * SPDY_FLAG_SETTINGS_PERSIST_VALUE, and the sender is returning it.
421 * Because persistence is only implemented on the client, this flag is
422 * only sent by the client.
423 */
424 SPDY_FLAG_SETTINGS_PERSISTED = 2,
425};
426
427
428/**
429 * Flag associated with a whole SPDY SETTINGS frame. Affect all the
430 * settings in the frame. Defined in SPDY Protocol - Draft 3.
431 */
432enum SPDY_FLAG_SETTINGS_FRAME
433{
434
435 /**
436 * When set, the client should clear any previously persisted SETTINGS
437 * ID/Value pairs. If this frame contains ID/Value pairs with the
438 * SPDY_FLAG_SETTINGS_PERSIST_VALUE set, then the client will first
439 * clear its existing, persisted settings, and then persist the values
440 * with the flag set which are contained within this frame. Because
441 * persistence is only implemented on the client, this flag can only
442 * be used when the sender is the server.
443 */
444 SPDY_FLAG_SETTINGS_CLEAR_SETTINGS = 1,
445};
446
447
448/**
449 * SPDY settings function options. Passed in the varargs portion of
450 * SPDY_SettingsReceivedCallback and SPDY_send_settings to customize
451 * more the settings handling. Each option must
452 * be followed by a value of a specific type.<p>
453 *
454 * The values are used internally as flags, that is why they must be
455 * powers of 2.
456 */
457enum SPDY_SETTINGS_OPTION
458{
459
460 /**
461 * No more options / last option. This is used
462 * to terminate the VARARGs list.
463 */
464 SPDY_SETTINGS_OPTION_END = 0,
465};
466
467
468/**
469 * Used as a parameter for SPDY_ResponseResultCallback and shows if the
470 * response was actually written to the TLS socket or discarded by the
471 * lib for any reason (and respectively the reason).
472 */
473enum SPDY_RESPONSE_RESULT
474{
475
476 /**
477 * The lib has written the full response to the TLS socket.
478 */
479 SPDY_RESPONSE_RESULT_SUCCESS = 0,
480
481 /**
482 * The session is being closed, so the data is being discarded
483 */
484 SPDY_RESPONSE_RESULT_SESSION_CLOSED = 1,
485
486 /**
487 * The stream for this response has been closed. May happen when the
488 * sender had sent first SYN_STREAM and after that RST_STREAM.
489 */
490 SPDY_RESPONSE_RESULT_STREAM_CLOSED = 2,
491};
492
493
494/**
495 * Callback for serious error condition. The default action is to print
496 * an error message and abort().
497 *
498 * @param cls user specified value
499 * @param file where the error occured
500 * @param line where the error occured
501 * @param reason error details message, may be NULL
502 */
503typedef void
504(*SPDY_PanicCallback) (void * cls,
505 const char * file,
506 unsigned int line,
507 const char * reason);
508
509
510/**
511 * Callback for new SPDY session established by a client. Called
512 * immediately after the TCP connection was established.
513 *
514 * @param cls client-defined closure
515 * @param session handler for the new SPDY session
516 */
517typedef void
518(*SPDY_NewSessionCallback) (void * cls,
519 struct SPDY_Session * session);
520
521
522/**
523 * Callback for closed session. Called after the TCP connection was
524 * closed. In this callback function the user has the last
525 * chance to access the SPDY_Session structure. After that the latter
526 * will be cleaned!
527 *
528 * @param cls client-defined closure
529 * @param session handler for the closed SPDY session
530 * @param by_client SPDY_YES if the session close was initiated by the
531 * client;
532 * SPDY_NO if closed by the server
533 */
534typedef void
535(*SPDY_SessionClosedCallback) (void * cls,
536 struct SPDY_Session * session,
537 int by_client);
538
539
540/**
541 * Iterator over name-value pairs.
542 *
543 * @param cls client-defined closure
544 * @param name of the pair
545 * @param value of the pair
546 * @return SPDY_YES to continue iterating,
547 * SPDY_NO to abort the iteration
548 */
549typedef int
550(*SPDY_NameValueIterator) (void * cls,
551 const char * name,
552 const char * const * value,
553 int num_values);
554
555
556/**
557 * Callback for received SPDY request.
558 *
559 * @param cls client-defined closure
560 * @param request handler. The request object is required for
561 * sending responses.
562 * @param priority of the SPDY stream which the request was
563 * sent over
564 * @param method HTTP method
565 * @param path HTTP path
566 * @param version HTTP version just like in HTTP request/response:
567 * "HTTP/1.0" or "HTTP/1.1" currently
568 * @param host called host as in HTTP
569 * @param scheme used ("http" or "https"). In SPDY 3 it is only "https".
570 * @param headers other HTTP headers from the request
571 */
572typedef void (*SPDY_NewRequestCallback) (void * cls,
573 struct SPDY_Request * request,
574 uint8_t priority,
575 const char * method,
576 const char * path,
577 const char * version,
578 const char * host,
579 const char * scheme,
580 struct SPDY_NameValue * headers);
581
582
583/**
584 * Callback for received new data chunk from the POST data of a given
585 * request.
586 *
587 * @param cls client-defined closure
588 * @param request handler
589 * @param buf data chunk from the POST data
590 * @param size the size of the data chunk 'buf' in bytes
591 * @param more false if this is the last chunk from the POST data. Note:
592 * true does not mean that more data will come, exceptional
593 * situation is possible
594 * @return SPDY_YES to continue calling the function,
595 * SPDY_NO to stop calling the function for this request
596 */
597typedef int (*SPDY_NewPOSTDataCallback) (void * cls,
598 struct SPDY_Request *request,
599 const void * buf,
600 size_t size,
601 bool more);
602// How about passing POST encoding information
603// here as well?
604//TODO
605
606
607/**
608 * Callback to be used with SPDY_build_response_with_callback. The
609 * callback will be called when the lib wants to write to the TLS socket.
610 * The application should provide the data to be sent.
611 *
612 * @param cls client-defined closure
613 * @param max maximum number of bytes that are allowed to be written
614 * to the buffer.
615 * @param more true if more data will be sent (i.e. the function must
616 * be calleed again),
617 * false if this is the last chunk, the lib will close
618 * the stream
619 * @return number of bytes written to buffer. On error the call MUST
620 * return value less than 0 to indicate the library.
621 */
622typedef ssize_t (*SPDY_ResponseCallback) (void * cls,
623 void * buffer,
624 size_t max,
625 bool * more);
626
627
628/**
629 * Callback to be called when the last bytes from the response was sent
630 * to the client or when the response was discarded from the lib. This
631 * callback is a very good place to discard the request and the response
632 * objects, if they will not be reused (e.g., sending the same response
633 * again). If the stream is closed it is safe to discard the request
634 * object.
635 *
636 * @param cls client-defined closure
637 * @param response handler to the response that was just sent
638 * @param request handler to the request for which the response was sent
639 * @param status shows if actually the response was sent or it was
640 * discarded by the lib for any reason (e.g., closing session,
641 * closing stream, stopping daemon, etc.). It is possible that
642 * status indicates an error but parts of the response headers
643 * and/or body (in one
644 * or several frames) were already sent to the client.
645 * @param streamopened indicates if the the stream for this request/
646 * response pair is still opened. If yes, the server may want
647 * to use SPDY push to send something additional to the client
648 * and/or close the stream.
649 */
650typedef void
651(*SPDY_ResponseResultCallback) (void * cls,
652 struct SPDY_Response * response,
653 struct SPDY_Request * request,
654 enum SPDY_RESPONSE_RESULT status,
655 bool streamopened);
656
657
658/**
659 * Callback to notify when SPDY ping response is received.
660 *
661 * @param session handler for which the ping request was sent
662 * @param rtt the timespan between sending ping request and receiving it
663 * from the library
664 */
665typedef void
666(*SPDY_PingCallback) (void * cls,
667 struct SPDY_Session * session,
668 struct timeval * rtt);
669
670
671/**
672 * Iterator over settings ID/Value/Flags tuples.
673 *
674 * @param cls client-defined closure
675 * @param id SPDY settings ID
676 * @param value value for this setting
677 * @param flags flags for this tuple; use
678 * enum SPDY_FLAG_SETTINGS
679 * @return SPDY_YES to continue iterating,
680 * SPDY_NO to abort the iteration
681 */
682typedef int
683(*SPDY_SettingsIterator) (void * cls,
684 enum SPDY_SETTINGS id,
685 int32_t value,
686 uint8_t flags);
687
688
689/**
690 * Callback to notify when SPDY SETTINGS are received from the client.
691 *
692 * @param session handler for which settings are received
693 * @param settings ID/value/flags tuples of the settings
694 * @param flags for the whole settings frame; use
695 * enum SPDY_FLAG_SETTINGS_FRAME
696 * @param ... list of options (type-value pairs,
697 * terminated with SPDY_SETTINGS_OPTION_END).
698 */
699typedef void
700(*SPDY_SettingsReceivedCallback) (struct SPDY_Session * session,
701 struct SPDY_Settings * settings,
702 uint8_t flags,
703 ...);
704
705
706/* Global functions for the library */
707
708
709/**
710 * Init function for the whole library. It MUST be called before any
711 * other function of the library to initialize things like TLS context
712 * and possibly other stuff needed by the lib. Currently the call
713 * always returns SPDY_YES.
714 *
715 * @return SPDY_YES if the library was correctly initialized and its
716 * functions can be used now;
717 * SPDY_NO on error
718 */
719int
720SPDY_init (void);
721
722
723/**
724 * Deinit function for the whole lib. It can be called after finishing
725 * using the library. It frees and cleans up resources allocated in
726 * SPDY_init. Currently the function does not do anything.
727 */
728void
729SPDY_deinit (void);
730
731
732/**
733 * Sets the global error handler to a different implementation. "cb"
734 * will only be called in the case of typically fatal, serious
735 * internal consistency issues. These issues should only arise in the
736 * case of serious memory corruption or similar problems with the
737 * architecture as well as failed assertions. While "cb" is allowed to
738 * return and the lib will then try to continue, this is never safe.
739 *
740 * The default implementation that is used if no panic function is set
741 * simply prints an error message and calls "abort". Alternative
742 * implementations might call "exit" or other similar functions.
743 *
744 * @param cb new error handler
745 * @param cls passed to error handler
746 */
747void
748SPDY_set_panic_func (SPDY_PanicCallback cb,
749 void *cls);
750
751
752/* Daemon functions */
753
754
755/**
756 * Start a SPDY webserver on the given port.
757 *
758 * @param port to bind to. The value is ignored if address structure
759 * is passed as daemon option
760 * @param certfile path to the certificate that will be used by server
761 * @param keyfile path to the keyfile for the certificate
762 * @param nscb callback called when a new SPDY session is
763 * established by a client
764 * @param sccb callback called when a session is closed
765 * @param nrcb callback called when a client sends request
766 * @param npdcb callback called when HTTP POST params are received
767 * after request
768 * @param cls common extra argument to all of the callbacks
769 * @param ... list of options (type-value pairs,
770 * terminated with SPDY_DAEMON_OPTION_END).
771 * @return NULL on error, handle to daemon on success
772 */
773struct SPDY_Daemon *
774SPDY_start_daemon (uint16_t port,
775 const char * certfile,
776 const char * keyfile,
777 SPDY_NewSessionCallback nscb,
778 SPDY_SessionClosedCallback sccb,
779 SPDY_NewRequestCallback nrcb,
780 SPDY_NewPOSTDataCallback npdcb,
781 void * cls,
782 ...);
783
784
785/**
786 * Shutdown the daemon. First all sessions are closed. It is NOT safe
787 * to call this function in user callbacks.
788 *
789 * @param daemon to stop
790 */
791void
792SPDY_stop_daemon (struct SPDY_Daemon *daemon);
793
794
795/**
796 * Obtain the select sets for this daemon. Only those are retrieved,
797 * which some processing should be done for, i.e. not all sockets are
798 * added to write_fd_set.<p>
799 *
800 * It is possible that there is
801 * nothing to be read from a socket but there is data either in the
802 * TLS subsystem's read buffers or in libmicrospdy's read buffers, which
803 * waits for being processed. In such case the file descriptor will be
804 * added to write_fd_set. Since it is very likely for the socket to be
805 * ready for writing, the select used in the application's event loop
806 * will return with success, SPDY_run will be called, the data will be
807 * processed and maybe something will be written to the socket. Without
808 * this behaviour, considering a proper event loop, data may stay in the
809 * buffers, but run is never called.
810 *
811 * @param daemon to get sets from
812 * @param read_fd_set read set
813 * @param write_fd_set write set
814 * @param except_fd_set except set
815 * @return largest FD added to any of the sets
816 */
817int
818SPDY_get_fdset (struct SPDY_Daemon * daemon,
819 fd_set * read_fd_set,
820 fd_set * write_fd_set,
821 fd_set * except_fd_set);
822
823
824/**
825 * Obtain timeout value for select for this daemon. The returned value
826 * is how long select
827 * should at most block, not the timeout value set for connections.
828 *
829 * @param daemon to query for timeout
830 * @param timeout will be set to the timeout value (in seconds)
831 * @return SPDY_YES on success
832 * SPDY_NO if no connections exist that
833 * would necessiate the use of a timeout right now
834 */
835int
836SPDY_get_timeout (struct SPDY_Daemon * daemon,
837 unsigned long long * timeout);
838
839
840/**
841 * Run webserver operations. This method must be called in
842 * the client event loop.
843 *
844 * @param daemon to run
845 */
846void
847SPDY_run (struct SPDY_Daemon *daemon);
848
849
850/* SPDY Session handling functions */
851
852
853/**
854 * Closes a SPDY session. SPDY clients and servers are expected to keep
855 * sessions opened as long as possible. However, the server may want to
856 * close some connections, e.g. if there are too many, to free some
857 * resources. The function can also be used to close a specific session
858 * if the client is not desired.
859 *
860 * @param session handler to be closed
861 */
862void
863SPDY_close_session(struct SPDY_Session * session);
864
865
866/**
867 * Associate a void pointer with a session. The data accessible by the
868 * pointer can later be used wherever the session handler is available.
869 *
870 * @param session handler
871 * @param cls any data pointed by a pointer to be accessible later
872 */
873void
874SPDY_set_cls_to_session(struct SPDY_Session * session,
875 void * cls);
876
877
878/**
879 * Retrieves the pointer associated with SPDY_set_cls_to_session().
880 *
881 * @param session handler to get its cls
882 * @return same pointer added by SPDY_set_cls_to_session() or
883 * NULL when nothing was associated
884 */
885void *
886SPDY_get_cls_from_session(struct SPDY_Session * session);
887
888
889/**
890 * Retrieves the remote address of a given session.
891 *
892 * @param session handler to get its remote address
893 * @param addr out parameter; pointing to remote address
894 * @return length of the address structure
895 */
896socklen_t
897SPDY_get_remote_addr(struct SPDY_Session * session,
898 struct sockaddr ** addr);
899
900
901/* SPDY name/value data structure handling functions */
902
903
904/**
905 * Create a new NameValue structure. It is needed for putting inside the
906 * HTTP headers and their values for a response. The user should later
907 * destroy alone the structure.
908 *
909 * @return hendler to the new empty structure or NULL on error
910 */
911struct SPDY_NameValue *
912SPDY_name_value_create ();
913
914
915/**
916 * Add name/value pair to a NameValue structure. SPDY_NO will be returned
917 * if the name/value pair is already in the structure. It is legal to
918 * add different values for the same name.
919 *
920 * @param container structure to which the new pair is added
921 * @param name for the value. Null-terminated string.
922 * @param value the value itself. Null-terminated string.
923 * @return SPDY_NO on error or SPDY_YES on success
924 */
925int
926SPDY_name_value_add (struct SPDY_NameValue * container,
927 const char * name,
928 const char * value);
929
930
931/**
932 * Lookup value for a name in a name/value structure.
933 *
934 * @param container structure in which to lookup
935 * @param name the name to look for
936 * @param num_values length of the returned array with values
937 * @return NULL if no such item was found, or an array containing the
938 * values
939 */
940const char * const *
941SPDY_name_value_lookup (struct SPDY_NameValue *container,
942 const char *name,
943 int * num_values);
944
945
946/**
947 * Iterate over name/value structure.
948 *
949 * @param container structure which to iterate over
950 * @param iterator callback to call on each name/value pair;
951 * maybe NULL (then just count headers)
952 * @param iterator_cls extra argument to iterator
953 * @return number of entries iterated over
954 */
955int
956SPDY_name_value_iterate (struct SPDY_NameValue *container,
957 SPDY_NameValueIterator iterator,
958 void *iterator_cls);
959
960
961/**
962 * Destroy a NameValue structure. Use this function to destroy only
963 * objects which, after passed to, will not be destroied by other
964 * functions.
965 *
966 */
967void
968SPDY_name_value_destroy (struct SPDY_NameValue * container);
969
970
971/* SPDY request handling functions */
972
973
974/**
975 * Gets the session responsible for the given
976 * request.
977 *
978 * @param request for which the session is wanted
979 * @return session handler for the request
980 */
981struct SPDY_Session *
982SPDY_get_session_for_request(const struct SPDY_Request * request);
983
984
985/**
986 * Associate a void pointer with a request. The data accessible by the
987 * pointer can later be used wherever the request handler is available.
988 *
989 * @param request with which to associate a pointer
990 * @param cls any data pointed by a pointer to be accessible later
991 */
992void
993SPDY_set_cls_to_request(struct SPDY_Request * request,
994 void * cls);
995
996
997/**
998 * Retrieves the pointer associated with the request by
999 * SPDY_set_cls_to_request().
1000 *
1001 * @param request to get its cls
1002 * @return same pointer added by SPDY_set_cls_to_request() or
1003 * NULL when nothing was associated
1004 */
1005void *
1006SPDY_get_cls_from_request(struct SPDY_Request * request);
1007
1008
1009/* SPDY response handling functions */
1010
1011
1012/**
1013 * Create response object containing all needed headers and data. The
1014 * response object is not bound to a request, so it can be used multiple
1015 * times with SPDY_queue_response() and schould be
1016 * destroied by calling the SPDY_destroy_response().<p>
1017 *
1018 * Currently the library does not provide compression of the body data.
1019 * It is up to the user to pass already compressed data and the
1020 * appropriate headers to this function when desired.
1021 *
1022 * @param status HTTP status code for the response (e.g. 404)
1023 * @param statustext HTTP status message for the response, which will
1024 * be appended to the status code (e.g. "OK"). Can be NULL
1025 * @param version HTTP version for the response (e.g. "http/1.1")
1026 * @param headers name/value structure containing additional HTTP headers.
1027 * Can be NULL. Can be used multiple times, it is up to
1028 * the user to destoy the object when not needed anymore.
1029 * @param data the body of the response. The lib will make a copy of it,
1030 * so it is up to the user to take care of the memory
1031 * pointed by data
1032 * @param size length of data. It can be 0, then the lib will send only
1033 * headers
1034 * @return NULL on error, handle to response object on success
1035 */
1036struct SPDY_Response *
1037SPDY_build_response(int status,
1038 const char * statustext,
1039 const char * version,
1040 struct SPDY_NameValue * headers,
1041 const void * data,
1042 size_t size);
1043
1044
1045/**
1046 * Create response object containing all needed headers. The data will
1047 * be provided later when the lib calls the callback function (just
1048 * before writing it to the TLS socket). The
1049 * response object is not bound to a request, so it can be used multiple
1050 * times with SPDY_queue_response() and schould be
1051 * destroied by calling the SPDY_destroy_response().<p>
1052 *
1053 * Currently the library does not provide compression of the body data.
1054 * It is up to the user to pass already compressed data and the
1055 * appropriate headers to this function and the callback when desired.
1056 *
1057 * @param status HTTP status code for the response (e.g. 404)
1058 * @param statustext HTTP status message for the response, which will
1059 * be appended to the status code (e.g. "OK"). Can be NULL
1060 * @param version HTTP version for the response (e.g. "http/1.1")
1061 * @param headers name/value structure containing additional HTTP headers.
1062 * Can be NULL. Can be used multiple times, it is up to
1063 * the user to destoy the object when not needed anymore.
1064 * @param rcb callback to use to obtain response data
1065 * @param rcb_cls extra argument to rcb
1066 * @param block_size preferred block size for querying rcb (advisory only,
1067 * the lib will call rcb specifying the block size); clients
1068 * should pick a value that is appropriate for IO and
1069 * memory performance requirements. The function will
1070 * fail if the value is bigger than the maximum
1071 * supported value (SPDY_MAX_SUPPORTED_FRAME_SIZE).
1072 * Can be 0, then the lib will use
1073 * SPDY_MAX_SUPPORTED_FRAME_SIZE instead.
1074 * @return NULL on error, handle to response object on success
1075 */
1076struct SPDY_Response *
1077SPDY_build_response_with_callback(int status,
1078 const char * statustext,
1079 const char * version,
1080 struct SPDY_NameValue * headers,
1081 SPDY_ResponseCallback rcb,
1082 void *rcb_cls,
1083 uint32_t block_size);
1084
1085
1086/**
1087 * Queue response object to be sent to the client. A successfully queued
1088 * response may never be sent, e.g. when the stream gets closed. The
1089 * data will be added to the output queue. The call will fail, if the
1090 * output for this session
1091 * is closed (i.e. the session is closed, half or full) or the output
1092 * channel for the stream, on which the request was received, is closed
1093 * (i.e. the stream is closed, half or full).
1094 *
1095 * @param request object identifying the request to which the
1096 * response is returned
1097 * @param response object containg headers and data to be sent
1098 * @param closestream TRUE if the server does NOT intend to PUSH
1099 * something more associated to this request/response later,
1100 * FALSE otherwise
1101 * @param consider_priority if FALSE, the response will be added to the
1102 * end of the queue. If TRUE, the response will be added after
1103 * the last previously added response with priority of the
1104 * request grater or equal to that of the current one. This
1105 * means that the function should be called with TRUE each time
1106 * if one wants to be sure that the output queue behaves like
1107 * a priority queue
1108 * @param rrcb callback called when all the data was sent (last frame
1109 * from response) or when that frame was discarded (e.g. the
1110 * stream has been closed meanwhile)
1111 * @param rrcb_cls extra argument to rcb
1112 * @return SPDY_NO on error or SPDY_YES on success
1113 */
1114int
1115SPDY_queue_response (struct SPDY_Request * request,
1116 struct SPDY_Response *response,
1117 bool closestream,
1118 bool consider_priority,
1119 SPDY_ResponseResultCallback rrcb,
1120 void * rrcb_cls);
1121
1122
1123/**
1124 * Destroy a response structure. It should be called for all objects
1125 * returned by SPDY_build_response*() functions to free the memory
1126 * associated with the prepared response. It is safe to call this
1127 * function not before being sure that the response will not be used by
1128 * the lib anymore, this means after SPDY_ResponseResultCallback
1129 * callbacks were called for all calls to SPDY_queue_response() passing
1130 * this response.
1131 *
1132 * @param response to destroy
1133 */
1134void
1135SPDY_destroy_response (struct SPDY_Response *response);
1136
1137
1138/* SPDY settings ID/value data structure handling functions */
1139
1140
1141/**
1142 * Create a new SettingsIDValue structure. It is needed for putting
1143 * inside tuples of SPDY option, flags and value for sending to the
1144 * client.
1145 *
1146 * @return hendler to the new empty structure or NULL on error
1147 */
1148const struct SPDY_Settings *
1149SPDY_settings_create ();
1150
1151
1152/**
1153 * Add or update a tuple to a SettingsIDValue structure.
1154 *
1155 * @param container structure to which the new tuple is added
1156 * @param id SPDY settings ID that will be sent. If this ID already in
1157 * container, the tupple for it will be updated (value and/or
1158 * flags). If it is not in the container, a new tupple will be
1159 * added.
1160 * @param flags SPDY settings flags applied only to this setting
1161 * @param value of the setting
1162 * @return SPDY_NO on error
1163 * or SPDY_YES if a new setting was added
1164 */
1165int
1166SPDY_settings_add (struct SPDY_Settings *container,
1167 enum SPDY_SETTINGS id,
1168 enum SPDY_FLAG_SETTINGS flags,
1169 int32_t value);
1170
1171
1172/**
1173 * Lookup value and flags for an ID in a settings ID/value structure.
1174 *
1175 * @param container structure in which to lookup
1176 * @param id SPDY settings ID to search for
1177 * @param flags out param for SPDY settings flags for this setting;
1178 * check it against the flags in enum SPDY_FLAG_SETTINGS
1179 * @param value out param for the value of this setting
1180 * @return SPDY_NO if the setting is not into the structure
1181 * or SPDY_YES if it is into it
1182 */
1183int
1184SPDY_settings_lookup (const struct SPDY_Settings * container,
1185 enum SPDY_SETTINGS id,
1186 enum SPDY_FLAG_SETTINGS * flags,
1187 int32_t * value);
1188
1189
1190/**
1191 * Iterate over settings ID/value structure.
1192 *
1193 * @param container structure which to iterate over
1194 * @param iterator callback to call on each ID/value pair;
1195 * maybe NULL (then just count number of settings)
1196 * @param iterator_cls extra argument to iterator
1197 * @return number of entries iterated over
1198 */
1199int
1200SPDY_settings_iterate (const struct SPDY_Settings * container,
1201 SPDY_SettingsIterator iterator,
1202 void * iterator_cls);
1203
1204
1205/**
1206 * Destroy a settings ID/value structure. Use this function to destroy
1207 * only objects which, after passed to, will not be destroied by other
1208 * functions.
1209 *
1210 * @param container structure which to detroy
1211 */
1212void
1213SPDY_settings_destroy (struct SPDY_Settings * container);
1214
1215
1216/* SPDY SETTINGS handling functions */
1217
1218
1219/**
1220 * Send SPDY SETTINGS to the client. The call will return fail if there
1221 * in invald setting into the settings container (e.g. invalid setting
1222 * ID).
1223 *
1224 * @param session SPDY_Session handler for which settings are being sent
1225 * @param settings ID/value pairs of the settings to be sent.
1226 * Can be used multiple times, it is up to the user to destoy
1227 * the object when not needed anymore.
1228 * @param flags for the whole settings frame. They are valid for all tuples
1229 * @param ... list of options (type-value pairs,
1230 * terminated with SPDY_SETTINGS_OPTION_END).
1231 * @return SPDY_NO on error or SPDY_YES on
1232 * success
1233 */
1234int
1235SPDY_send_settings (struct SPDY_Session * session,
1236 struct SPDY_Settings * settings,
1237 enum SPDY_FLAG_SETTINGS_FRAME flags,
1238 ...);
1239
1240
1241/* SPDY misc functions */
1242
1243
1244/**
1245 * Destroy a request structure. It should be called for all objects
1246 * received as a parameter in SPDY_NewRequestCallback to free the memory
1247 * associated with the request. It is safe to call this
1248 * function not before being sure that the request will not be used by
1249 * the lib anymore, this means after the stream, on which this request
1250 * had been sent, was closed and all SPDY_ResponseResultCallback
1251 * callbacks were called for all calls to SPDY_queue_response() passing
1252 * this request object.
1253 *
1254 * @param request to destroy
1255 */
1256void
1257SPDY_destroy_request (struct SPDY_Request * request);
1258
1259
1260/**
1261 * Send SPDY ping to the client
1262 *
1263 * @param session handler for which the ping request is sent
1264 * @param rttcb callback called when ping response to the request is
1265 * received
1266 * @param rttcb_cls extra argument to rttcb
1267 * @return SPDY_NO on error or SPDY_YES on success
1268 */
1269int
1270SPDY_send_ping(struct SPDY_Session * session,
1271 SPDY_PingCallback rttcb,
1272 void * rttcb_cls);
1273
1274
1275#endif
diff --git a/src/microspdy/EXPORT.sym b/src/microspdy/EXPORT.sym
new file mode 100644
index 00000000..eb6604bc
--- /dev/null
+++ b/src/microspdy/EXPORT.sym
@@ -0,0 +1,2 @@
1SPDY_start_daemon
2SPDY_stop_daemon
diff --git a/src/microspdy/Makefile.am b/src/microspdy/Makefile.am
new file mode 100644
index 00000000..0509134a
--- /dev/null
+++ b/src/microspdy/Makefile.am
@@ -0,0 +1,38 @@
1if USE_PRIVATE_PLIBC_H
2 PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc
3endif
4
5AM_CPPFLAGS = \
6 $(PLIBC_INCLUDE) \
7 -I$(top_srcdir)/src/include \
8 -I$(top_srcdir)/src/microspdy
9
10
11EXTRA_DIST = EXPORT.sym
12
13
14lib_LTLIBRARIES = \
15 libmicrospdy.la
16
17libmicrospdy_la_SOURCES = \
18 tls.h tls.c \
19 structures.h structures.c \
20 internal.h internal.c \
21 daemon.h daemon.c \
22 stream.h stream.c \
23 compression.h compression.c \
24 session.h session.c \
25 applicationlayer.c applicationlayer.h \
26 alstructures.c alstructures.h
27
28
29libmicrospdy_la_LDFLAGS = \
30 $(SPDY_LIB_LDFLAGS)
31
32libmicrospdy_la_CFLAGS = -Wextra \
33 $(SPDY_LIB_CFLAGS)
34
35
36if USE_COVERAGE
37 AM_CFLAGS = --coverage
38endif
diff --git a/src/microspdy/alstructures.c b/src/microspdy/alstructures.c
new file mode 100644
index 00000000..3495b052
--- /dev/null
+++ b/src/microspdy/alstructures.c
@@ -0,0 +1,41 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file alstructures.c
21 * @brief structures only for the application layer
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "alstructures.h"
27#include "internal.h"
28
29void
30SPDY_destroy_request (struct SPDY_Request *request)
31{
32 if(NULL == request)
33 {
34 SPDYF_DEBUG("request is NULL");
35 return;
36 }
37 //strings into request struct are just references to strings in
38 //headers, so no need to free them twice
39 SPDY_name_value_destroy(request->headers);
40 free(request);
41}
diff --git a/src/microspdy/alstructures.h b/src/microspdy/alstructures.h
new file mode 100644
index 00000000..61eb8cb6
--- /dev/null
+++ b/src/microspdy/alstructures.h
@@ -0,0 +1,79 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file alstructures.h
21 * @brief structures only for the application layer
22 * @author Andrey Uzunov
23 */
24
25#ifndef ALSTRUCTURES_H
26#define ALSTRUCTURES_H
27
28#include "platform.h"
29
30
31/**
32 * Represents a SPDY request.
33 */
34struct SPDY_Request
35{
36 /**
37 * SPDY stream in whose context the request was received
38 */
39 struct SPDYF_Stream *stream;
40
41 /**
42 * Other HTTP headers from the request
43 */
44 struct SPDY_NameValue *headers;
45
46 /**
47 * HTTP method
48 */
49 char *method;
50
51 /**
52 * HTTP path
53 */
54 char *path;
55
56 /**
57 * HTTP version just like in HTTP request/response:
58 * "HTTP/1.0" or "HTTP/1.1" currently
59 */
60 char *version;
61
62 /**
63 * called host as in HTTP
64 */
65 char *host;
66
67 /**
68 * The scheme used ("http" or "https")
69 */
70 char *scheme;
71
72 /**
73 * Extra field to be used by the user with set/get func for whatever
74 * purpose he wants.
75 */
76 void *user_cls;
77};
78
79#endif
diff --git a/src/microspdy/applicationlayer.c b/src/microspdy/applicationlayer.c
new file mode 100644
index 00000000..cbe484bc
--- /dev/null
+++ b/src/microspdy/applicationlayer.c
@@ -0,0 +1,679 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file applicationlayer.c
21 * @brief SPDY application or HTTP layer
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "applicationlayer.h"
27#include "alstructures.h"
28#include "structures.h"
29#include "internal.h"
30#include "daemon.h"
31#include "session.h"
32
33
34/**
35 * Callback called when new stream is created. It extracts the info from
36 * the stream to create (HTTP) request object and pass it to the client.
37 *
38 * @param cls
39 * @param stream the new SPDY stream
40 * @return SPDY_YES on success, SPDY_NO on memomry error
41 */
42static int
43spdy_handler_new_stream (void *cls,
44 struct SPDYF_Stream * stream)
45{
46 (void)cls;
47 uint i;
48 char *method = NULL;
49 char *path = NULL;
50 char *version = NULL;
51 char *host = NULL;
52 char *scheme = NULL;
53 struct SPDY_Request * request = NULL;
54 struct SPDY_NameValue * headers = NULL;
55 struct SPDY_NameValue * iterator = stream->headers;
56 struct SPDY_Daemon *daemon;
57
58 daemon = stream->session->daemon;
59
60 //if the user doesn't care, ignore it
61 if(NULL == daemon->new_request_cb)
62 return SPDY_YES;
63
64 if(NULL == (headers=SPDY_name_value_create()))
65 goto free_and_fail;
66
67 if(NULL==(request = malloc(sizeof(struct SPDY_Request))))
68 goto free_and_fail;
69
70 memset(request, 0, sizeof(struct SPDY_Request));
71 request->stream = stream;
72
73 /* extract the mandatory fields from stream->headers' structure
74 * to pass them to the client */
75 while(iterator != NULL)
76 {
77 if(strcmp(":method",iterator->name) == 0)
78 {
79 if(1 != iterator->num_values)
80 break;
81 method = iterator->value[0];
82 }
83 else if(strcmp(":path",iterator->name) == 0)
84 {
85 if(1 != iterator->num_values)
86 break;
87 path = iterator->value[0];
88 }
89 else if(strcmp(":version",iterator->name) == 0)
90 {
91 if(1 != iterator->num_values)
92 break;
93 version = iterator->value[0];
94 }
95 else if(strcmp(":host",iterator->name) == 0)
96 {
97 //TODO can it have more values?
98 if(1 != iterator->num_values)
99 break;
100 host = iterator->value[0];
101 }
102 else if(strcmp(":scheme",iterator->name) == 0)
103 {
104 if(1 != iterator->num_values)
105 break;
106 scheme = iterator->value[0];
107 }
108 else
109 for(i=0; i<iterator->num_values; ++i)
110 if (SPDY_YES != SPDY_name_value_add(headers,iterator->name,iterator->value[i]))
111 goto free_and_fail;
112
113 iterator = iterator->next;
114 }
115
116 request->method=method;
117 request->path=path;
118 request->version=version;
119 request->host=host;
120 request->scheme=scheme;
121 request->headers=headers;
122
123 //check request validity, all these fields are mandatory for a request
124 if(NULL == method || strlen(method) == 0
125 || NULL == path || strlen(path) == 0
126 || NULL == version || strlen(version) == 0
127 || NULL == host || strlen(host) == 0
128 || NULL == scheme || strlen(scheme) == 0
129 )
130 {
131 //TODO HTTP 400 Bad Request must be answered
132
133 SPDYF_DEBUG("Bad request");
134
135 SPDY_destroy_request(request);
136
137 return SPDY_YES;
138 }
139
140 //call client's callback function to notify
141 daemon->new_request_cb(daemon->cls,
142 request,
143 stream->priority,
144 method,
145 path,
146 version,
147 host,
148 scheme,
149 headers);
150
151 return SPDY_YES;
152
153 //for GOTO
154 free_and_fail:
155
156 SPDY_name_value_destroy(headers);
157 return SPDY_NO;
158}
159
160
161/**
162 * Callback to be called when the response queue object was handled and
163 * the data was already sent or discarded.
164 *
165 * @param cls
166 * @param response_queue the object which is being handled
167 * @param status shows if actually the response was sent or it was
168 * discarded by the lib for any reason (e.g., closing session,
169 * closing stream, stopping daemon, etc.). It is possible that
170 * status indicates an error but parts of the response headers
171 * and/or body (in one
172 * or several frames) were already sent to the client.
173 */
174static void
175spdy_handler_response_queue_result(void * cls,
176 struct SPDYF_Response_Queue *response_queue,
177 enum SPDY_RESPONSE_RESULT status)
178{
179 int streamopened;
180 struct SPDY_Request *request = (struct SPDY_Request *)cls;
181
182 SPDYF_ASSERT(NULL == response_queue->data_frame
183 && NULL != response_queue->control_frame
184 || NULL != response_queue->data_frame
185 && NULL == response_queue->control_frame,
186 "response queue must have either control frame or data frame");
187
188 streamopened = !response_queue->stream->is_out_closed;
189
190 response_queue->rrcb(response_queue->rrcb_cls, response_queue->response, request, status, streamopened);
191}
192
193
194int
195SPDY_init ()
196{
197 SPDYF_ASSERT(SPDYF_BUFFER_SIZE >= SPDY_MAX_SUPPORTED_FRAME_SIZE,
198 "Buffer size is less than max supported frame size!");
199 SPDYF_ASSERT(SPDY_MAX_SUPPORTED_FRAME_SIZE >= 32,
200 "Max supported frame size must be bigger than the minimal value!");
201 SPDYF_tls_global_init();
202 return SPDY_YES;
203}
204
205
206void
207SPDY_deinit ()
208{
209 //currently nothing to be freed/deinited
210 //SPDYF_tls_global_deinit doesn't do anything now
211 //SPDYF_tls_global_deinit();
212}
213
214
215void
216SPDY_run (struct SPDY_Daemon *daemon)
217{
218 if(NULL == daemon)
219 {
220 SPDYF_DEBUG("daemon is NULL");
221 return;
222 }
223
224 SPDYF_run(daemon);
225}
226
227
228int
229SPDY_get_timeout (struct SPDY_Daemon *daemon,
230 unsigned long long *timeout)
231{
232 if(NULL == daemon)
233 {
234 SPDYF_DEBUG("daemon is NULL");
235 return SPDY_INPUT_ERROR;
236 }
237
238 return SPDYF_get_timeout(daemon,timeout);
239}
240
241
242int
243SPDY_get_fdset (struct SPDY_Daemon *daemon,
244 fd_set *read_fd_set,
245 fd_set *write_fd_set,
246 fd_set *except_fd_set)
247{
248 if(NULL == daemon
249 || NULL == read_fd_set
250 || NULL == write_fd_set
251 || NULL == except_fd_set)
252 {
253 SPDYF_DEBUG("a parameter is NULL");
254 return SPDY_INPUT_ERROR;
255 }
256
257 return SPDYF_get_fdset(daemon,
258 read_fd_set,
259 write_fd_set,
260 except_fd_set,
261 false);
262}
263
264
265struct SPDY_Daemon *
266SPDY_start_daemon (uint16_t port,
267 const char *certfile,
268 const char *keyfile,
269 SPDY_NewSessionCallback nscb,
270 SPDY_SessionClosedCallback sccb,
271 SPDY_NewRequestCallback nrcb,
272 SPDY_NewPOSTDataCallback npdcb,
273 void * cls,
274 ...)
275{
276 struct SPDY_Daemon *daemon;
277 va_list valist;
278
279 if(NULL == certfile)
280 {
281 SPDYF_DEBUG("certfile is NULL");
282 return NULL;
283 }
284 if(NULL == keyfile)
285 {
286 SPDYF_DEBUG("keyfile is NULL");
287 return NULL;
288 }
289
290 va_start(valist, cls);
291 daemon = SPDYF_start_daemon_va ( port,
292 certfile,
293 keyfile,
294 nscb,
295 sccb,
296 nrcb,
297 npdcb,
298 &spdy_handler_new_stream,
299 cls,
300 NULL,
301 valist
302 );
303 va_end(valist);
304
305 return daemon;
306}
307
308
309void
310SPDY_stop_daemon (struct SPDY_Daemon *daemon)
311{
312 if(NULL == daemon)
313 {
314 SPDYF_DEBUG("daemon is NULL");
315 return;
316 }
317
318 SPDYF_stop_daemon(daemon);
319}
320
321
322struct SPDY_Response *
323SPDY_build_response(int status,
324 const char * statustext,
325 const char * version,
326 struct SPDY_NameValue * headers,
327 const void * data,
328 size_t size)
329{
330 struct SPDY_Response *response = NULL;
331 struct SPDY_NameValue ** all_headers = NULL;
332 char *fullstatus = NULL;
333 int ret;
334 int num_hdr_containers = 1;
335
336 if(NULL == version)
337 {
338 SPDYF_DEBUG("version is NULL");
339 return NULL;
340 }
341
342 if(NULL == (response = malloc(sizeof(struct SPDY_Response))))
343 goto free_and_fail;
344 memset(response, 0, sizeof(struct SPDY_Response));
345
346 if(NULL != headers)
347 num_hdr_containers = 2;
348
349 if(NULL == (all_headers = malloc(num_hdr_containers * sizeof(struct SPDY_NameValue *))))
350 goto free_and_fail;
351 memset(all_headers, 0, num_hdr_containers * sizeof(struct SPDY_NameValue *));
352
353 if(2 == num_hdr_containers)
354 all_headers[1] = headers;
355
356 if(NULL == (all_headers[0] = SPDY_name_value_create()))
357 goto free_and_fail;
358
359 if(NULL == statustext)
360 ret = asprintf(&fullstatus, "%i", status);
361 else
362 ret = asprintf(&fullstatus, "%i %s", status, statustext);
363 if(-1 == ret)
364 goto free_and_fail;
365
366 if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":status", fullstatus))
367 goto free_and_fail;
368
369 free(fullstatus);
370 fullstatus = NULL;
371
372 if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":version", version))
373 goto free_and_fail;
374
375 if(0 >= (response->headers_size = SPDYF_name_value_to_stream(all_headers,
376 num_hdr_containers,
377 &(response->headers))))
378 goto free_and_fail;
379
380 SPDY_name_value_destroy(all_headers[0]);
381 free(all_headers);
382
383 if(size > 0)
384 {
385 //copy the data to the response object
386 if(NULL == (response->data = malloc(size)))
387 {
388 free(response->headers);
389 goto free_and_fail;
390 }
391 memcpy(response->data, data, size);
392 response->data_size = size;
393 }
394
395 return response;
396
397 //for GOTO
398 free_and_fail:
399
400 free(fullstatus);
401 if(NULL != all_headers)
402 SPDY_name_value_destroy(all_headers[0]);
403 free(all_headers);
404 free(response);
405
406 return NULL;
407}
408
409
410struct SPDY_Response *
411SPDY_build_response_with_callback(int status,
412 const char * statustext,
413 const char * version,
414 struct SPDY_NameValue * headers,
415 SPDY_ResponseCallback rcb,
416 void *rcb_cls,
417 uint32_t block_size)
418{
419 struct SPDY_Response *response;
420
421 if(NULL == rcb)
422 {
423 SPDYF_DEBUG("rcb is NULL");
424 return NULL;
425 }
426 if(block_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)
427 {
428 SPDYF_DEBUG("block_size is wrong");
429 return NULL;
430 }
431
432 if(0 == block_size)
433 block_size = SPDY_MAX_SUPPORTED_FRAME_SIZE;
434
435 response = SPDY_build_response(status,
436 statustext,
437 version,
438 headers,
439 NULL,
440 0);
441
442 if(NULL == response)
443 {
444 return NULL;
445 }
446
447 response->rcb = rcb;
448 response->rcb_cls = rcb_cls;
449 response->rcb_block_size = block_size;
450
451 return response;
452}
453
454
455int
456SPDY_queue_response (struct SPDY_Request * request,
457 struct SPDY_Response *response,
458 bool closestream,
459 bool consider_priority,
460 SPDY_ResponseResultCallback rrcb,
461 void * rrcb_cls)
462{
463 struct SPDYF_Response_Queue *headers_to_queue;
464 struct SPDYF_Response_Queue *body_to_queue;
465 SPDYF_ResponseQueueResultCallback frqcb = NULL;
466 void *frqcb_cls = NULL;
467 int int_consider_priority = consider_priority ? SPDY_YES : SPDY_NO;
468
469 if(NULL == request)
470 {
471 SPDYF_DEBUG("request is NULL");
472 return SPDY_INPUT_ERROR;
473 }
474 if(NULL == response)
475 {
476 SPDYF_DEBUG("request is NULL");
477 return SPDY_INPUT_ERROR;
478 }
479
480 if(request->stream->is_out_closed
481 || SPDY_SESSION_STATUS_CLOSING == request->stream->session->status)
482 return SPDY_NO;
483
484 if(NULL != rrcb)
485 {
486 frqcb_cls = request;
487 frqcb = &spdy_handler_response_queue_result;
488 }
489
490 if(response->data_size > 0)
491 {
492 //SYN_REPLY and DATA will be queued
493
494 if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
495 response->headers,
496 response->headers_size,
497 response,
498 request->stream,
499 false,
500 NULL,
501 NULL,
502 NULL,
503 NULL)))
504 {
505 return SPDY_NO;
506 }
507
508 if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
509 response->data,
510 response->data_size,
511 response,
512 request->stream,
513 closestream,
514 frqcb,
515 frqcb_cls,
516 rrcb,
517 rrcb_cls)))
518 {
519 SPDYF_response_queue_destroy(headers_to_queue);
520 return SPDY_NO;
521 }
522
523 SPDYF_queue_response (headers_to_queue,
524 request->stream->session,
525 int_consider_priority);
526
527 SPDYF_queue_response (body_to_queue,
528 request->stream->session,
529 int_consider_priority);
530 }
531 else if(NULL == response->rcb)
532 {
533 //no "body" will be queued, e.g. HTTP 404 without body
534
535 if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
536 response->headers,
537 response->headers_size,
538 response,
539 request->stream,
540 closestream,
541 frqcb,
542 frqcb_cls,
543 rrcb,
544 rrcb_cls)))
545 {
546 return SPDY_NO;
547 }
548
549 SPDYF_queue_response (headers_to_queue,
550 request->stream->session,
551 int_consider_priority);
552 }
553 else
554 {
555 //response with callbacks
556
557 if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
558 response->headers,
559 response->headers_size,
560 response,
561 request->stream,
562 false,
563 NULL,
564 NULL,
565 NULL,
566 NULL)))
567 {
568 return SPDY_NO;
569 }
570
571 if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
572 response->data,
573 response->data_size,
574 response,
575 request->stream,
576 closestream,
577 frqcb,
578 frqcb_cls,
579 rrcb,
580 rrcb_cls)))
581 {
582 SPDYF_response_queue_destroy(headers_to_queue);
583 return SPDY_NO;
584 }
585
586 SPDYF_queue_response (headers_to_queue,
587 request->stream->session,
588 int_consider_priority);
589
590 SPDYF_queue_response (body_to_queue,
591 request->stream->session,
592 int_consider_priority);
593 }
594
595 return SPDY_YES;
596}
597
598
599socklen_t
600SPDY_get_remote_addr(struct SPDY_Session * session,
601 struct sockaddr ** addr)
602{
603 if(NULL == session)
604 {
605 SPDYF_DEBUG("session is NULL");
606 return 0;
607 }
608
609 *addr = session->addr;
610
611 return session->addr_len;
612}
613
614
615struct SPDY_Session *
616SPDY_get_session_for_request(const struct SPDY_Request * request)
617{
618 if(NULL == request)
619 {
620 SPDYF_DEBUG("request is NULL");
621 return NULL;
622 }
623
624 return request->stream->session;
625}
626
627
628void *
629SPDY_get_cls_from_session(struct SPDY_Session * session)
630{
631 if(NULL == session)
632 {
633 SPDYF_DEBUG("session is NULL");
634 return NULL;
635 }
636
637 return session->user_cls;
638}
639
640
641void
642SPDY_set_cls_to_session(struct SPDY_Session * session,
643 void * cls)
644{
645 if(NULL == session)
646 {
647 SPDYF_DEBUG("session is NULL");
648 return;
649 }
650
651 session->user_cls = cls;
652}
653
654
655void *
656SPDY_get_cls_from_request(struct SPDY_Request * request)
657{
658 if(NULL == request)
659 {
660 SPDYF_DEBUG("request is NULL");
661 return NULL;
662 }
663
664 return request->user_cls;
665}
666
667
668void
669SPDY_set_cls_to_request(struct SPDY_Request * request,
670 void * cls)
671{
672 if(NULL == request)
673 {
674 SPDYF_DEBUG("request is NULL");
675 return;
676 }
677
678 request->user_cls = cls;
679}
diff --git a/src/microspdy/applicationlayer.h b/src/microspdy/applicationlayer.h
new file mode 100644
index 00000000..53e3be0a
--- /dev/null
+++ b/src/microspdy/applicationlayer.h
@@ -0,0 +1,31 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file applicationlayer.h
21 * @brief SPDY application or HTTP layer
22 * @author Andrey Uzunov
23 */
24
25#ifndef APPLICATIONLAYER_H
26#define APPLICATIONLAYER_H
27
28#include "platform.h"
29
30
31#endif
diff --git a/src/microspdy/compression.c b/src/microspdy/compression.c
new file mode 100644
index 00000000..5b212d30
--- /dev/null
+++ b/src/microspdy/compression.c
@@ -0,0 +1,441 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file compression.c
21 * @brief zlib handling functions
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27#include "internal.h"
28#include "compression.h"
29
30/* spdy ver 3 specific dictionary used by zlib */
31static const unsigned char
32spdyf_zlib_dictionary[] = {
33 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // - - - - o p t i
34 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // o n s - - - - h
35 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // e a d - - - - p
36 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // o s t - - - - p
37 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // u t - - - - d e
38 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // l e t e - - - -
39 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // t r a c e - - -
40 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // - a c c e p t -
41 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
42 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t - c h a r s e
43 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t - - - - a c c
44 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e p t - e n c o
45 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // d i n g - - - -
46 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // a c c e p t - l
47 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // a n g u a g e -
48 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
49 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t - r a n g e s
50 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // - - - - a g e -
51 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // - - - a l l o w
52 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // - - - - a u t h
53 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // o r i z a t i o
54 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n - - - - c a c
55 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // h e - c o n t r
56 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // o l - - - - c o
57 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // n n e c t i o n
58 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
59 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // e n t - b a s e
60 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
61 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e n t - e n c o
62 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // d i n g - - - -
63 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // c o n t e n t -
64 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // l a n g u a g e
65 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
66 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // e n t - l e n g
67 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // t h - - - - c o
68 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // n t e n t - l o
69 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // c a t i o n - -
70 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
71 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t - m d 5 - - -
72 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // - c o n t e n t
73 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // - r a n g e - -
74 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
75 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t - t y p e - -
76 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // - - d a t e - -
77 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // - - e t a g - -
78 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // - - e x p e c t
79 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // - - - - e x p i
80 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // r e s - - - - f
81 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // r o m - - - - h
82 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // o s t - - - - i
83 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f - m a t c h -
84 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // - - - i f - m o
85 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // d i f i e d - s
86 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // i n c e - - - -
87 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // i f - n o n e -
88 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // m a t c h - - -
89 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // - i f - r a n g
90 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e - - - - i f -
91 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // u n m o d i f i
92 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // e d - s i n c e
93 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // - - - - l a s t
94 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // - m o d i f i e
95 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d - - - - l o c
96 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // a t i o n - - -
97 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // - m a x - f o r
98 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // w a r d s - - -
99 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // - p r a g m a -
100 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // - - - p r o x y
101 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // - a u t h e n t
102 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // i c a t e - - -
103 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // - p r o x y - a
104 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // u t h o r i z a
105 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // t i o n - - - -
106 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // r a n g e - - -
107 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // - r e f e r e r
108 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // - - - - r e t r
109 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y - a f t e r -
110 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // - - - s e r v e
111 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r - - - - t e -
112 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // - - - t r a i l
113 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // e r - - - - t r
114 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // a n s f e r - e
115 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // n c o d i n g -
116 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // - - - u p g r a
117 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // d e - - - - u s
118 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // e r - a g e n t
119 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // - - - - v a r y
120 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // - - - - v i a -
121 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // - - - w a r n i
122 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // n g - - - - w w
123 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w - a u t h e n
124 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // t i c a t e - -
125 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // - - m e t h o d
126 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // - - - - g e t -
127 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // - - - s t a t u
128 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s - - - - 2 0 0
129 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // - O K - - - - v
130 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // e r s i o n - -
131 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // - - H T T P - 1
132 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // - 1 - - - - u r
133 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l - - - - p u b
134 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // l i c - - - - s
135 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // e t - c o o k i
136 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e - - - - k e e
137 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p - a l i v e -
138 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // - - - o r i g i
139 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n 1 0 0 1 0 1 2
140 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 0 1 2 0 2 2 0 5
141 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 2 0 6 3 0 0 3 0
142 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 2 3 0 3 3 0 4 3
143 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 0 5 3 0 6 3 0 7
144 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 4 0 2 4 0 5 4 0
145 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 6 4 0 7 4 0 8 4
146 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 0 9 4 1 0 4 1 1
147 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 4 1 2 4 1 3 4 1
148 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 4 4 1 5 4 1 6 4
149 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 1 7 5 0 2 5 0 4
150 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 5 0 5 2 0 3 - N
151 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // o n - A u t h o
152 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // r i t a t i v e
153 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // - I n f o r m a
154 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // t i o n 2 0 4 -
155 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // N o - C o n t e
156 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // n t 3 0 1 - M o
157 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // v e d - P e r m
158 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // a n e n t l y 4
159 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 0 0 - B a d - R
160 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // e q u e s t 4 0
161 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1 - U n a u t h
162 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // o r i z e d 4 0
163 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3 - F o r b i d
164 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // d e n 4 0 4 - N
165 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // o t - F o u n d
166 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 5 0 0 - I n t e
167 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // r n a l - S e r
168 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // v e r - E r r o
169 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r 5 0 1 - N o t
170 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // - I m p l e m e
171 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // n t e d 5 0 3 -
172 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // S e r v i c e -
173 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // U n a v a i l a
174 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // b l e J a n - F
175 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // e b - M a r - A
176 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // p r - M a y - J
177 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // u n - J u l - A
178 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // u g - S e p t -
179 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // O c t - N o v -
180 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // D e c - 0 0 - 0
181 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0 - 0 0 - M o n
182 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // - - T u e - - W
183 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // e d - - T h u -
184 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // - F r i - - S a
185 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t - - S u n - -
186 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // G M T c h u n k
187 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // e d - t e x t -
188 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // h t m l - i m a
189 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // g e - p n g - i
190 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // m a g e - j p g
191 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // - i m a g e - g
192 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // i f - a p p l i
193 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
194 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // m l - a p p l i
195 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
196 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // h t m l - x m l
197 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // - t e x t - p l
198 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // a i n - t e x t
199 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // - j a v a s c r
200 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // i p t - p u b l
201 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // i c p r i v a t
202 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // e m a x - a g e
203 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // - g z i p - d e
204 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // f l a t e - s d
205 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // c h c h a r s e
206 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t - u t f - 8 c
207 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // h a r s e t - i
208 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // s o - 8 8 5 9 -
209 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1 - u t f - - -
210 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // - e n q - 0 -
211};
212
213
214int
215SPDYF_zlib_deflate_init(z_stream *strm)
216{
217 int ret;
218
219 strm->zalloc = Z_NULL;
220 strm->zfree = Z_NULL;
221 strm->opaque = Z_NULL;
222 //the second argument is "level of compression"
223 //use 0 for no compression; 9 for best compression
224 ret = deflateInit(strm, Z_DEFAULT_COMPRESSION);
225 if(ret != Z_OK)
226 {
227 SPDYF_DEBUG("deflate init");
228 return SPDY_NO;
229 }
230 ret = deflateSetDictionary(strm,
231 spdyf_zlib_dictionary,
232 sizeof(spdyf_zlib_dictionary));
233 if(ret != Z_OK)
234 {
235 SPDYF_DEBUG("deflate set dict");
236 deflateEnd(strm);
237 return SPDY_NO;
238 }
239 return SPDY_YES;
240}
241
242
243void
244SPDYF_zlib_deflate_end(z_stream *strm)
245{
246 deflateEnd(strm);
247}
248
249int
250SPDYF_zlib_deflate(z_stream *strm,
251 const void *src,
252 size_t src_size,
253 size_t *data_used,
254 void **dest,
255 size_t *dest_size)
256{
257 int ret;
258 int flush;
259 uint have;
260 Bytef out[SPDYF_ZLIB_CHUNK];
261
262 *dest = NULL;
263 *dest_size = 0;
264
265 do
266 {
267 /* check for big data bigger than the buffer used */
268 if(src_size > SPDYF_ZLIB_CHUNK)
269 {
270 strm->avail_in = SPDYF_ZLIB_CHUNK;
271 src_size -= SPDYF_ZLIB_CHUNK;
272 /* flush is used for the loop to detect if we still
273 * need to supply additional
274 * data to the stream via avail_in and next_in. */
275 flush = Z_NO_FLUSH;
276 }
277 else
278 {
279 strm->avail_in = src_size;
280 flush = Z_SYNC_FLUSH;
281 }
282 *data_used += strm->avail_in;
283
284 strm->next_in = (Bytef *)src;
285
286 /* Loop while output data is available */
287 do
288 {
289 strm->avail_out = SPDYF_ZLIB_CHUNK;
290 strm->next_out = out;
291
292 /* No need to check return value of deflate.
293 * (See zlib documentation at http://www.zlib.net/zlib_how.html */
294 ret = deflate(strm, flush);
295 have = SPDYF_ZLIB_CHUNK - strm->avail_out;
296
297 /* (Re)allocate memory for dest and keep track of it's size. */
298 *dest_size += have;
299 *dest = realloc(*dest, *dest_size);
300 if(!*dest)
301 {
302 SPDYF_DEBUG("realloc data for result");
303 deflateEnd(strm);
304 return SPDY_NO;
305 }
306 memcpy((*dest) + ((*dest_size) - have), out, have);
307 }
308 while(strm->avail_out == 0);
309 /* At this point, all of the input data should already
310 * have been used. */
311 SPDYF_ASSERT(strm->avail_in == 0,"compressing bug");
312 }
313 while(flush != Z_SYNC_FLUSH);
314
315 return Z_OK == ret ? SPDY_YES : SPDY_NO;
316}
317
318
319int
320SPDYF_zlib_inflate_init(z_stream *strm)
321{
322 int ret;
323
324 strm->zalloc = Z_NULL;
325 strm->zfree = Z_NULL;
326 strm->opaque = Z_NULL;
327 strm->avail_in = 0;
328 strm->next_in = Z_NULL;
329 //change 15 to lower value for performance and benchmark
330 //"The windowBits parameter is the base two logarithm of the
331 // maximum window size (the size of the history buffer)."
332 ret = inflateInit2(strm, 15);
333 if(ret != Z_OK)
334 {
335 SPDYF_DEBUG("Cannot inflateInit2 the stream");
336 return SPDY_NO;
337 }
338 return SPDY_YES;
339}
340
341
342void
343SPDYF_zlib_inflate_end(z_stream *strm)
344{
345 inflateEnd(strm);
346}
347
348
349int
350SPDYF_zlib_inflate(z_stream *strm,
351 const void *src,
352 size_t src_size,
353 void **dest,
354 size_t *dest_size)
355{
356 int ret = Z_OK;
357 uint32_t have;
358 Bytef out[SPDYF_ZLIB_CHUNK];
359
360 *dest = NULL;
361 *dest_size = 0;
362
363 /* decompress until deflate stream ends or end of file */
364 do
365 {
366 if(src_size > SPDYF_ZLIB_CHUNK)
367 {
368 strm->avail_in = SPDYF_ZLIB_CHUNK;
369 src_size -= SPDYF_ZLIB_CHUNK;
370 }
371 else
372 {
373 strm->avail_in = src_size;
374 src_size = 0;
375 }
376
377 if(strm->avail_in == 0){
378 //the loop breaks always here as the stream never ends
379 break;
380 }
381
382 strm->next_in = (Bytef *) src;
383 /* run inflate() on input until output buffer not full */
384 do {
385 strm->avail_out = SPDYF_ZLIB_CHUNK;
386 strm->next_out = out;
387 ret = inflate(strm, Z_SYNC_FLUSH);
388
389 switch (ret)
390 {
391 case Z_STREAM_ERROR:
392 SPDYF_DEBUG("Error on inflate");
393 //no inflateEnd here, same in zlib example
394 return SPDY_NO;
395
396 case Z_NEED_DICT:
397 ret = inflateSetDictionary(strm,
398 spdyf_zlib_dictionary,
399 sizeof(spdyf_zlib_dictionary));
400 if(ret != Z_OK)
401 {
402 SPDYF_DEBUG("Error on inflateSetDictionary");
403 inflateEnd(strm);
404 return SPDY_NO;
405 }
406 ret = inflate(strm, Z_SYNC_FLUSH);
407 if(Z_STREAM_ERROR == ret)
408 {
409 SPDYF_DEBUG("Error on inflate");
410 return SPDY_NO;
411 }
412 break;
413
414 case Z_DATA_ERROR:
415 SPDYF_DEBUG("Z_DATA_ERROR");
416 inflateEnd(strm);
417 return SPDY_NO;
418
419 case Z_MEM_ERROR:
420 SPDYF_DEBUG("Z_MEM_ERROR");
421 inflateEnd(strm);
422 return SPDY_NO;
423 }
424 have = SPDYF_ZLIB_CHUNK - strm->avail_out;
425 *dest_size += have;
426 /* (re)alloc memory for the output buffer */
427 *dest = realloc(*dest, *dest_size);
428 if(!*dest)
429 {
430 SPDYF_DEBUG("Cannot realloc memory");
431 inflateEnd(strm);
432 return SPDY_NO;
433 }
434 memcpy((*dest) + ((*dest_size) - have), out, have);
435 }
436 while (0 == strm->avail_out);
437 }
438 while (Z_STREAM_END != ret);
439
440 return Z_OK == ret || Z_STREAM_END == ret ? SPDY_YES : SPDY_NO;
441}
diff --git a/src/microspdy/compression.h b/src/microspdy/compression.h
new file mode 100644
index 00000000..ac37f115
--- /dev/null
+++ b/src/microspdy/compression.h
@@ -0,0 +1,117 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file compression.h
21 * @brief zlib handling functions
22 * @author Andrey Uzunov
23 */
24
25#ifndef COMPRESSION_H
26#define COMPRESSION_H
27
28#include "platform.h"
29
30/* size of buffers used by zlib on (de)compressing */
31#define SPDYF_ZLIB_CHUNK 16384
32
33
34/**
35 * Initializes the zlib stream for compression. Must be called once
36 * for a session on initialization.
37 *
38 * @param strm Zlib stream on which we work
39 * @return SPDY_NO if zlib failed. SPDY_YES otherwise
40 */
41int
42SPDYF_zlib_deflate_init(z_stream *strm);
43
44
45/**
46 * Deinitializes the zlib stream for compression. Should be called once
47 * for a session on cleaning up.
48 *
49 * @param strm Zlib stream on which we work
50 */
51void
52SPDYF_zlib_deflate_end(z_stream *strm);
53
54
55/**
56 * Compressing stream with zlib.
57 *
58 * @param strm Zlib stream on which we work
59 * @param src stream of the data to be compressed
60 * @param src_size size of the data
61 * @param data_used the number of bytes from src_stream that were used
62 * TODO do we need
63 * @param dest the resulting compressed stream. Should be NULL. Must be
64 * freed later manually.
65 * @param dest_size size of the data after compression
66 * @return SPDY_NO if malloc or zlib failed. SPDY_YES otherwise
67 */
68int
69SPDYF_zlib_deflate(z_stream *strm,
70 const void *src,
71 size_t src_size,
72 size_t *data_used,
73 void **dest,
74 size_t *dest_size);
75
76
77/**
78 * Initializes the zlib stream for decompression. Must be called once
79 * for a session.
80 *
81 * @param strm Zlib stream on which we work
82 * @return SPDY_NO if zlib failed. SPDY_YES otherwise
83 */
84int
85SPDYF_zlib_inflate_init(z_stream *strm);
86
87
88/**
89 * Deinitializes the zlib stream for decompression. Should be called once
90 * for a session on cleaning up.
91 *
92 * @param strm Zlib stream on which we work
93 */
94void
95SPDYF_zlib_inflate_end(z_stream *strm);
96
97
98/**
99 * Decompressing stream with zlib.
100 *
101 * @param strm Zlib stream on which we work
102 * @param src stream of the data to be decompressed
103 * @param src_size size of the data
104 * @param dest the resulting decompressed stream. Should be NULL. Must
105 * be freed manually.
106 * @param dest_size size of the data after decompression
107 * @return SPDY_NO if malloc or zlib failed. SPDY_YES otherwise. If the
108 * function fails, the SPDY session must be closed
109 */
110int
111SPDYF_zlib_inflate(z_stream *strm,
112 const void *src,
113 size_t src_size,
114 void **dest,
115 size_t *dest_size);
116
117#endif
diff --git a/src/microspdy/daemon.c b/src/microspdy/daemon.c
new file mode 100644
index 00000000..47e49ea1
--- /dev/null
+++ b/src/microspdy/daemon.c
@@ -0,0 +1,515 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file daemon.c
21 * @brief daemon functionality
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27#include "internal.h"
28#include "session.h"
29#include "tls.h"
30
31
32/**
33 * Default implementation of the panic function,
34 * prints an error message and aborts.
35 *
36 * @param cls unused
37 * @param file name of the file with the problem
38 * @param line line number with the problem
39 * @param reason error message with details
40 */
41static void
42spdyf_panic_std (void *cls,
43 const char *file,
44 unsigned int line,
45 const char *reason)
46{
47 (void)cls;
48 fprintf (stdout, "Fatal error in libmicrospdy %s:%u: %s\n",
49 file, line, reason);
50 //raise(SIGINT); //used for gdb
51 abort ();
52}
53
54
55/**
56 * Global handler for fatal errors.
57 */
58SPDY_PanicCallback spdyf_panic = &spdyf_panic_std;
59
60
61/**
62 * Global closure argument for "spdyf_panic".
63 */
64void *spdyf_panic_cls;
65
66
67/**
68 * Free resources associated with all closed connections.
69 * (destroy responses, free buffers, etc.).
70 *
71 * @param daemon daemon to clean up
72 */
73static void
74spdyf_cleanup_sessions (struct SPDY_Daemon *daemon)
75{
76 struct SPDY_Session *session;
77
78 while (NULL != (session = daemon->cleanup_head))
79 {
80 DLL_remove (daemon->cleanup_head,
81 daemon->cleanup_tail,
82 session);
83
84 SPDYF_session_destroy(session);
85 }
86}
87
88
89/**
90 * Closing of all connections handled by the daemon.
91 *
92 * @param daemon SPDY daemon
93 */
94static void
95spdyf_close_all_sessions (struct SPDY_Daemon *daemon)
96{
97 struct SPDY_Session *session;
98
99 while (NULL != (session = daemon->sessions_head))
100 {
101 //prepare GOAWAY frame
102 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
103 //try to send the frame (it is best effort, so it will maybe sent)
104 SPDYF_session_write(session,true);
105 SPDYF_session_close(session);
106 }
107
108 spdyf_cleanup_sessions(daemon);
109}
110
111
112/**
113 * Parse a list of options given as varargs.
114 *
115 * @param daemon the daemon to initialize
116 * @param valist the options
117 * @return SPDY_YES on success, SPDY_NO on error
118 */
119static int
120spdyf_parse_options_va (struct SPDY_Daemon *daemon,
121 va_list valist)
122{
123 enum SPDY_DAEMON_OPTION opt;
124
125 while (SPDY_DAEMON_OPTION_END != (opt = (enum SPDY_DAEMON_OPTION) va_arg (valist, int)))
126 {
127 if(opt & daemon->options)
128 {
129 SPDYF_DEBUG("Daemon option %i used twice",opt);
130 return SPDY_NO;
131 }
132 daemon->options |= opt;
133
134 switch (opt)
135 {
136 case SPDY_DAEMON_OPTION_SESSION_TIMEOUT:
137 daemon->session_timeout = va_arg (valist, unsigned int);
138 break;
139 case SPDY_DAEMON_OPTION_SOCK_ADDR:
140 daemon->address = va_arg (valist, struct sockaddr *);
141 break;
142 case SPDY_DAEMON_OPTION_FLAGS:
143 daemon->flags = va_arg (valist, enum SPDY_DAEMON_FLAG);
144 break;
145 default:
146 SPDYF_DEBUG("Wrong option for the daemon %i",opt);
147 return SPDY_NO;
148 }
149 }
150 return SPDY_YES;
151}
152
153
154void
155SPDY_set_panic_func (SPDY_PanicCallback cb,
156 void *cls)
157{
158 spdyf_panic = cb;
159 spdyf_panic_cls = cls;
160}
161
162
163struct SPDY_Daemon *
164SPDYF_start_daemon_va (uint16_t port,
165 const char *certfile,
166 const char *keyfile,
167 SPDY_NewSessionCallback nscb,
168 SPDY_SessionClosedCallback sccb,
169 SPDY_NewRequestCallback nrcb,
170 SPDY_NewPOSTDataCallback npdcb,
171 SPDYF_NewStreamCallback fnscb,
172 void * cls,
173 void * fcls,
174 va_list valist)
175{
176 struct SPDY_Daemon *daemon = NULL;
177 int afamily;
178 int option_on = 1;
179 int ret;
180 struct sockaddr_in* servaddr4 = NULL;
181#if HAVE_INET6
182 struct sockaddr_in6* servaddr6 = NULL;
183#endif
184 socklen_t addrlen;
185
186 if (NULL == (daemon = malloc (sizeof (struct SPDY_Daemon))))
187 {
188 SPDYF_DEBUG("malloc");
189 return NULL;
190 }
191 memset (daemon, 0, sizeof (struct SPDY_Daemon));
192 daemon->socket_fd = -1;
193 daemon->port = port;
194 if (NULL == (daemon->certfile = strdup (certfile)))
195 {
196 SPDYF_DEBUG("str");
197 goto free_and_fail;
198 }
199 if (NULL == (daemon->keyfile = strdup (keyfile)))
200 {
201 SPDYF_DEBUG("str");
202 goto free_and_fail;
203 }
204 daemon->new_session_cb = nscb;
205 daemon->session_closed_cb = sccb;
206 daemon->new_request_cb = nrcb;
207 daemon->new_post_data_cb = npdcb;
208 daemon->cls = cls;
209 daemon->fcls = fcls;
210 daemon->fnew_stream_cb = fnscb;
211
212 if(SPDY_YES != spdyf_parse_options_va (daemon, valist))
213 {
214 SPDYF_DEBUG("parse");
215 goto free_and_fail;
216 }
217
218 if(!port && NULL == daemon->address)
219 {
220 SPDYF_DEBUG("Port is 0");
221 goto free_and_fail;
222 }
223
224#if HAVE_INET6
225 //handling IPv6
226 if((daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
227 && NULL != daemon->address && AF_INET6 != daemon->address->sa_family)
228 {
229 SPDYF_DEBUG("SPDY_DAEMON_FLAG_ONLY_IPV6 set but IPv4 address provided");
230 goto free_and_fail;
231 }
232
233 if(NULL == daemon->address)
234 {
235 addrlen = sizeof (struct sockaddr_in6);
236
237 if (NULL == (servaddr6 = malloc (addrlen)))
238 {
239 SPDYF_DEBUG("malloc");
240 goto free_and_fail;
241 }
242 memset (servaddr6, 0, addrlen);
243 servaddr6->sin6_family = AF_INET6;
244 servaddr6->sin6_addr = in6addr_any;
245 servaddr6->sin6_port = htons (port);
246 daemon->address = (struct sockaddr *) servaddr6;
247 }
248
249 afamily = AF_INET6 == daemon->address->sa_family ? PF_INET6 : PF_INET;
250#else
251 //handling IPv4
252 if(daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
253 {
254 SPDYF_DEBUG("SPDY_DAEMON_FLAG_ONLY_IPV6 set but no support");
255 goto free_and_fail;
256 }
257
258 if(NULL == daemon->address)
259 {
260 addrlen = sizeof (struct sockaddr_in);
261
262 if (NULL == (servaddr4 = malloc (addrlen)))
263 {
264 SPDYF_DEBUG("malloc");
265 goto free_and_fail;
266 }
267 memset (servaddr4, 0, addrlen);
268 servaddr4->sin_family = AF_INET;
269 servaddr4->sin_addr = INADDR_ANY;
270 servaddr4->sin_port = htons (port);
271 daemon->address = (struct sockaddr *) servaddr4;
272 }
273
274 afamily = PF_INET;
275#endif
276
277 daemon->socket_fd = socket (afamily, SOCK_STREAM, 0);
278 if (-1 == daemon->socket_fd)
279 {
280 SPDYF_DEBUG("sock");
281 goto free_and_fail;
282 }
283
284 //setting option for the socket to reuse address
285 ret = setsockopt(daemon->socket_fd, SOL_SOCKET, SO_REUSEADDR, &option_on, sizeof(option_on));
286 if(ret)
287 {
288 SPDYF_DEBUG("WARNING: SO_REUSEADDR was not set for the server");
289 }
290
291#if HAVE_INET6
292 if(daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
293 {
294 ret = setsockopt(daemon->socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, &option_on, sizeof(option_on));
295 if(ret)
296 {
297 SPDYF_DEBUG("setsockopt with IPPROTO_IPV6 failed");
298 goto free_and_fail;
299 }
300 }
301#endif
302
303 if (-1 == bind (daemon->socket_fd, daemon->address, addrlen))
304 {
305 SPDYF_DEBUG("bind %i",errno);
306 goto free_and_fail;
307 }
308
309 if (listen (daemon->socket_fd, 20) < 0)
310 {
311 SPDYF_DEBUG("listen %i",errno);
312 goto free_and_fail;
313 }
314
315 if(SPDY_YES != SPDYF_tls_init(daemon))
316 {
317 SPDYF_DEBUG("tls");
318 goto free_and_fail;
319 }
320
321 return daemon;
322
323 //for GOTO
324 free_and_fail:
325 if(daemon->socket_fd > 0)
326 close (daemon->socket_fd);
327
328 free(servaddr4);
329#if HAVE_INET6
330 free(servaddr6);
331#endif
332 if(NULL != daemon->certfile)
333 free(daemon->certfile);
334 if(NULL != daemon->keyfile)
335 free(daemon->keyfile);
336 free (daemon);
337
338 return NULL;
339}
340
341
342void
343SPDYF_stop_daemon (struct SPDY_Daemon *daemon)
344{
345 SPDYF_tls_deinit(daemon);
346
347 shutdown (daemon->socket_fd, SHUT_RDWR);
348 spdyf_close_all_sessions (daemon);
349 close (daemon->socket_fd);
350
351 if(!(SPDY_DAEMON_OPTION_SOCK_ADDR & daemon->options))
352 free(daemon->address);
353
354 free(daemon->certfile);
355 free(daemon->keyfile);
356
357 free(daemon);
358}
359
360
361int
362SPDYF_get_timeout (struct SPDY_Daemon *daemon,
363 unsigned long long *timeout)
364{
365 time_t earliest_deadline = 0;
366 time_t now;
367 struct SPDY_Session *pos;
368 bool have_timeout;
369
370 if(0 == daemon->session_timeout)
371 return SPDY_NO;
372
373 now = SPDYF_monotonic_time();
374 have_timeout = false;
375 for (pos = daemon->sessions_head; NULL != pos; pos = pos->next)
376 {
377 if ( (! have_timeout) ||
378 (earliest_deadline > pos->last_activity + daemon->session_timeout) )
379 earliest_deadline = pos->last_activity + daemon->session_timeout;
380
381 have_timeout = true;
382
383 if (SPDY_YES == SPDYF_tls_is_pending(pos))
384 {
385 earliest_deadline = 0;
386 break;
387 }
388 }
389
390 if (!have_timeout)
391 return SPDY_NO;
392 if (earliest_deadline < now)
393 *timeout = 0;
394 else
395 //*timeout = 1000 * (1 + earliest_deadline - now);
396 *timeout = earliest_deadline - now;
397
398 return SPDY_YES;
399}
400
401
402int
403SPDYF_get_fdset (struct SPDY_Daemon *daemon,
404 fd_set *read_fd_set,
405 fd_set *write_fd_set,
406 fd_set *except_fd_set,
407 bool all)
408{
409 (void)except_fd_set;
410 struct SPDY_Session *pos;
411 int fd;
412 int max_fd = -1;
413
414 fd = daemon->socket_fd;
415 if (-1 != fd)
416 {
417 FD_SET (fd, read_fd_set);
418 /* update max file descriptor */
419 max_fd = fd;
420 }
421
422 for (pos = daemon->sessions_head; NULL != pos; pos = pos->next)
423 {
424 fd = pos->socket_fd;
425 FD_SET(fd, read_fd_set);
426 if(all
427 || NULL != pos->response_queue_head //frames pending
428 || NULL != pos->write_buffer //part of last frame pending
429 || SPDY_SESSION_STATUS_CLOSING == pos->status //the session is about to be closed
430 || daemon->session_timeout //timeout passed for the session
431 && (pos->last_activity + daemon->session_timeout < SPDYF_monotonic_time())
432 || SPDY_YES == SPDYF_tls_is_pending(pos) //data in TLS' read buffer pending
433 || ((pos->read_buffer_offset - pos->read_buffer_beginning) > 0) // data in lib's read buffer pending
434 )
435 FD_SET(fd, write_fd_set);
436 if(fd > max_fd)
437 max_fd = fd;
438 }
439
440 return max_fd;
441}
442
443
444void
445SPDYF_run (struct SPDY_Daemon *daemon)
446{
447 struct SPDY_Session *pos;
448 struct SPDY_Session *next;
449 int num_ready;
450 fd_set rs;
451 fd_set ws;
452 fd_set es;
453 int max;
454 struct timeval timeout;
455 int ds;
456
457 timeout.tv_sec = 0;
458 timeout.tv_usec = 0;
459 FD_ZERO (&rs);
460 FD_ZERO (&ws);
461 FD_ZERO (&es);
462 //here we need really all descriptors to see later which are ready
463 max = SPDYF_get_fdset(daemon,&rs,&ws,&es, true);
464
465 num_ready = select (max + 1, &rs, &ws, &es, &timeout);
466
467 if(num_ready < 1)
468 return;
469
470 if ( (-1 != (ds = daemon->socket_fd)) &&
471 (FD_ISSET (ds, &rs)) ){
472 SPDYF_session_accept(daemon);
473 }
474
475 next = daemon->sessions_head;
476 while (NULL != (pos = next))
477 {
478 next = pos->next;
479 ds = pos->socket_fd;
480 if (ds != -1)
481 {
482 //fill the read buffer
483 if (FD_ISSET (ds, &rs) || SPDYF_tls_is_pending(pos)){
484 SPDYF_session_read(pos);
485 }
486
487 //do something with the data in read buffer
488 if(SPDY_NO == SPDYF_session_idle(pos))
489 {
490 //the session was closed, cannot write anymore
491 //continue;
492 }
493
494 //write whatever has been put to the response queue
495 //during read or idle operation, something might be put
496 //on the response queue, thus call write operation
497 if (FD_ISSET (ds, &ws)){
498 if(SPDY_NO == SPDYF_session_write(pos, false))
499 {
500 //SPDYF_session_close(pos);
501 //continue;
502 }
503 }
504
505 /* the response queue has been flushed for half closed
506 * connections, so let close them */
507 /*if(pos->read_closed)
508 {
509 SPDYF_session_close(pos);
510 }*/
511 }
512 }
513
514 spdyf_cleanup_sessions(daemon);
515}
diff --git a/src/microspdy/daemon.h b/src/microspdy/daemon.h
new file mode 100644
index 00000000..d3f7f2ff
--- /dev/null
+++ b/src/microspdy/daemon.h
@@ -0,0 +1,121 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file daemon.h
21 * @brief daemon functionality
22 * @author Andrey Uzunov
23 */
24
25#ifndef DAEMON_H
26#define DAEMON_H
27
28#include "platform.h"
29
30
31/**
32 * Start a SPDDY webserver on the given port.
33 *
34 * @param port port to bind to
35 * @param certfile path to the certificate that will be used by server
36 * @param keyfile path to the keyfile for the certificate
37 * @param nscb callback called when a new SPDY session is
38 * established by a client
39 * @param sccb callback called when a client closes the session
40 * @param nrcb callback called when a client sends request
41 * @param npdcb callback called when HTTP POST params are received
42 * after request
43 * @param fnscb callback called when new stream is opened by a client
44 * @param cls extra argument to all of the callbacks without those
45 * specific only for the framing layer
46 * @param fcls extra argument to all of the callbacks, specific only for
47 * the framing layer (those vars starting with 'f').
48 * @param valist va_list of options (type-value pairs,
49 * terminated with SPDY_DAEMON_OPTION_END).
50 * @return NULL on error, handle to daemon on success
51 */
52struct SPDY_Daemon *
53SPDYF_start_daemon_va (uint16_t port,
54 const char *certfile,
55 const char *keyfile,
56 SPDY_NewSessionCallback nscb,
57 SPDY_SessionClosedCallback sccb,
58 SPDY_NewRequestCallback nrcb,
59 SPDY_NewPOSTDataCallback npdcb,
60 SPDYF_NewStreamCallback fnscb,
61 void * cls,
62 void * fcls,
63 va_list valist);
64
65
66/**
67 * Run webserver operations (without blocking unless
68 * in client callbacks). This method must be called in the client event
69 * loop.
70 *
71 * @param daemon daemon to run
72 */
73void
74SPDYF_run (struct SPDY_Daemon *daemon);
75
76
77/**
78 * Obtain timeout value for select for this daemon. The returned value
79 * is how long select
80 * should at most block, not the timeout value set for connections.
81 *
82 * @param daemon daemon to query for timeout
83 * @param timeout set to the timeout (in seconds)
84 * @return SPDY_YES on success, SPDY_NO if no connections exist that
85 * would necessiate the use of a timeout right now
86 */
87int
88SPDYF_get_timeout (struct SPDY_Daemon *daemon,
89 unsigned long long *timeout);
90
91
92/**
93 * Obtain the select sets for this daemon. The idea of SPDYF_get_fdset
94 * is to return such descriptors that the select in the application can
95 * return and SPDY_run can be called only when this is really needed.
96 * That means not all sockets will be added to write_fd_set.
97 *
98 * @param daemon daemon to get sets from
99 * @param read_fd_set read set
100 * @param write_fd_set write set
101 * @param except_fd_set except set
102 * @param all add all session's descriptors to write_fd_set or not
103 * @return largest FD added
104 */
105int
106SPDYF_get_fdset (struct SPDY_Daemon *daemon,
107 fd_set *read_fd_set,
108 fd_set *write_fd_set,
109 fd_set *except_fd_set,
110 bool all);
111
112
113/**
114 * Shutdown the daemon.
115 *
116 * @param daemon daemon to stop
117 */
118void
119SPDYF_stop_daemon (struct SPDY_Daemon *daemon);
120
121#endif
diff --git a/src/microspdy/internal.c b/src/microspdy/internal.c
new file mode 100644
index 00000000..458bcb2f
--- /dev/null
+++ b/src/microspdy/internal.c
@@ -0,0 +1,38 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file internal.c
21 * @brief internal functions and macros for the framing layer
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27
28
29time_t
30SPDYF_monotonic_time(void)
31{
32#ifdef HAVE_CLOCK_GETTIME
33 struct timespec ts;
34 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
35 return ts.tv_sec;
36#endif
37 return time(NULL);
38}
diff --git a/src/microspdy/internal.h b/src/microspdy/internal.h
new file mode 100644
index 00000000..becde9d5
--- /dev/null
+++ b/src/microspdy/internal.h
@@ -0,0 +1,189 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file structures.h
21 * @brief internal functions and macros for the framing layer
22 * @author Andrey Uzunov
23 */
24
25#ifndef INTERNAL_H_H
26#define INTERNAL_H_H
27
28#include "platform.h"
29#include "microspdy.h"
30#include "tls.h"
31
32/* size of read buffers for each connection
33 * must be at least the size of SPDY_MAX_SUPPORTED_FRAME_SIZE */
34#define SPDYF_BUFFER_SIZE 8192
35
36/* number of frames written to the socket at once. After X frames
37 * everything should be run again. In this way the application can
38 * response to more important requests while a big file is still
39 * being transmitted to the client */
40#define SPDYF_NUM_SENT_FRAMES_AT_ONCE 10
41
42
43/**
44 * Handler for fatal errors.
45 */
46extern SPDY_PanicCallback spdyf_panic;
47
48
49/**
50 * Closure argument for "mhd_panic".
51 */
52extern void *spdyf_panic_cls;
53
54
55/**
56 * Trigger 'panic' action based on fatal errors.
57 *
58 * @param msg error message (const char *)
59 */
60#define SPDYF_PANIC(msg) \
61 spdyf_panic (spdyf_panic_cls, __FILE__, __LINE__, msg)
62
63
64/**
65 * Asserts the validity of an expression.
66 *
67 * @param expression (bool)
68 * @param msg message to print on error (const char *)
69 */
70#define SPDYF_ASSERT(expr,msg) \
71 if(!(expr)){\
72 SPDYF_PANIC(msg);\
73 abort();\
74 }
75
76
77/**
78 * Convert 24 bit integer from host byte order to network byte order.
79 *
80 * @param n input value (int32_t)
81 * @return converted value (uint32_t)
82 */
83#if HAVE_BIG_ENDIAN
84#define HTON24(n) n
85#else
86#define HTON24(n) (((((uint32_t)(n) & 0xFF)) << 16)\
87 | (((uint32_t)(n) & 0xFF00))\
88 | ((((uint32_t)(n) & 0xFF0000)) >> 16))
89#endif
90
91
92/**
93 * Convert 24 bit integer from network byte order to host byte order.
94 *
95 * @param n input value (int32_t)
96 * @return converted value (uint32_t)
97 */
98#if HAVE_BIG_ENDIAN
99#define NTOH24(n) n
100#else
101#define NTOH24(n) (((((uint32_t)(n) & 0xFF)) << 16)\
102 | (((uint32_t)(n) & 0xFF00))\
103 | ((((uint32_t)(n) & 0xFF0000)) >> 16))
104#endif
105
106
107/**
108 * Convert 31 bit integer from network byte order to host byte order.
109 *
110 * @param n input value (int32_t)
111 * @return converted value (uint32_t)
112 */
113#if HAVE_BIG_ENDIAN
114#define NTOH31(n) n
115#else
116#define NTOH31(n) (((((uint32_t)(n) & 0x7F)) << 24) | \
117 ((((uint32_t)(n) & 0xFF00)) << 8) | \
118 ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
119 ((((uint32_t)(n) & 0xFF000000)) >> 24))
120#endif
121
122
123/**
124 * Convert 31 bit integer from host byte order to network byte order.
125 *
126 * @param n input value (int32_t)
127 * @return converted value (uint32_t)
128 */
129#if HAVE_BIG_ENDIAN
130#define HTON31(n) n
131#else
132#define HTON31(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
133 ((((uint32_t)(n) & 0xFF00)) << 8) | \
134 ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
135 ((((uint32_t)(n) & 0x7F000000)) >> 24))
136#endif
137
138
139/**
140 * Print formatted debug value.
141 *
142 * @param fmt format (const char *)
143 * @param ... args for format
144 */
145#define SPDYF_DEBUG(fmt, ...) do { \
146 fprintf (stdout, "%s\n%u: ",__FILE__, __LINE__);\
147 fprintf(stdout,fmt,##__VA_ARGS__);\
148 fprintf(stdout,"\n");\
149 fflush(stdout); } while (0)
150
151
152/**
153 * Print stream for debuging.
154 *
155 * @param strm (void *)
156 * @param size (int)
157 */
158#define SPDYF_PRINT_STREAM(strm, size) do { \
159 int ___i;\
160 for(___i=0;___i<size;___i++){\
161 fprintf(stdout,"%x ",*((uint8_t *) strm + ___i));\
162 fflush(stdout);\
163 }\
164 fprintf(stdout,"\n");\
165 } while (0)
166
167
168/**
169 * Print message and raise SIGINT for debug purposes.
170 *
171 * @param msg message (const char *)
172 */
173#define SPDYF_SIGINT(msg) do { \
174 fprintf(stdout,"%i : %s\n", __LINE__,__FILE__);\
175 fprintf(stdout,msg);\
176 fprintf(stdout,"\n");\
177 fflush(stdout);\
178 raise(SIGINT); } while (0)
179
180
181/**
182 * Returns monotonic time, to be used for session timeouts.
183 *
184 * @return time in seconds
185 */
186time_t
187SPDYF_monotonic_time(void);
188
189#endif
diff --git a/src/microspdy/session.c b/src/microspdy/session.c
new file mode 100644
index 00000000..002aeb15
--- /dev/null
+++ b/src/microspdy/session.c
@@ -0,0 +1,1554 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file session.c
21 * @brief TCP connection/SPDY session handling. So far most of the
22 * functions for handling SPDY framing layer are here.
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include "structures.h"
28#include "internal.h"
29#include "session.h"
30#include "compression.h"
31#include "tls.h"
32#include "stream.h"
33
34
35/**
36 * Handler for reading the full SYN_STREAM frame after we know that
37 * the frame is such.
38 * The function waits for the full frame and then changes status
39 * of the session. New stream is created.
40 *
41 * @param session SPDY_Session whose read buffer is used.
42 */
43static void
44spdyf_handler_read_syn_stream (struct SPDY_Session *session)
45{
46 size_t name_value_strm_size = 0;
47 uint compressed_data_size;
48 int ret;
49 void *name_value_strm = NULL;
50 struct SPDYF_Control_Frame *frame;
51 struct SPDY_NameValue *headers;
52
53 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
54 || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
55 "the function is called wrong");
56
57 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
58
59 //handle subheaders
60 if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
61 {
62 if(0 == frame->length)
63 {
64 //protocol error: incomplete frame
65 //we just ignore it since there is no stream id for which to
66 //send RST_STREAM
67 //TODO maybe GOAWAY and closing session is appropriate
68 SPDYF_DEBUG("zero long SYN_STREAM received");
69 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
70 free(frame);
71 return;
72 }
73
74 if(SPDY_YES != SPDYF_stream_new(session))
75 {
76 /* waiting for some more fields to create new stream
77 or something went wrong, SPDYF_stream_new has handled the
78 situation */
79 return;
80 }
81
82 session->current_stream_id = session->streams_head->stream_id;
83 if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
84 {
85 //TODO no need to create stream if this happens
86 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
87 return;
88 }
89 else
90 session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
91 }
92
93 //handle body
94
95 //start reading the compressed name/value pairs (http headers)
96 compressed_data_size = frame->length //everything after length field
97 - 10;//4B stream id, 4B assoc strem id, 2B priority, unused and slot
98
99 if(session->read_buffer_offset - session->read_buffer_beginning < compressed_data_size)
100 {
101 // the full frame is not yet here, try later
102 return;
103 }
104
105 if(compressed_data_size > 0
106 && SPDY_YES != SPDYF_zlib_inflate(&session->zlib_recv_stream,
107 session->read_buffer + session->read_buffer_beginning,
108 compressed_data_size,
109 &name_value_strm,
110 &name_value_strm_size))
111 {
112 /* something went wrong on inflating,
113 * the state of the stream for decompression is unknown
114 * and we may not be able to read anything more received on
115 * this session,
116 * so it is better to close the session */
117 free(name_value_strm);
118 free(frame);
119
120 /* mark the session for closing and close it, when
121 * everything on the output queue is already written */
122 session->status = SPDY_SESSION_STATUS_FLUSHING;
123
124 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
125
126 return;
127 }
128
129 if(0 == name_value_strm_size || 0 == compressed_data_size)
130 {
131 //Protocol error: send RST_STREAM
132 if(SPDY_YES != SPDYF_prepare_rst_stream(session, session->current_stream_id,
133 SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR))
134 {
135 //no memory, try later to send RST
136 return;
137 }
138 }
139
140 ret = SPDYF_name_value_from_stream(name_value_strm, name_value_strm_size, &headers);
141 if(SPDY_NO == ret)
142 {
143 //memory error, try later
144 free(name_value_strm);
145 return;
146 }
147
148 session->streams_head->headers = headers;
149 //inform the application layer for the new stream received
150 if(SPDY_YES != session->daemon->fnew_stream_cb(session->daemon->fcls, session->streams_head))
151 {
152 //memory error, try later
153 free(name_value_strm);
154 return;
155 }
156
157 session->read_buffer_beginning += compressed_data_size;
158 //change state to wait for new frame
159 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
160 free(frame);
161 free(name_value_strm);
162}
163
164
165/**
166 * Handler for reading the GOAWAY frame after we know that
167 * the frame is such.
168 * The function waits for the full frame and then changes status
169 * of the session.
170 *
171 * @param session SPDY_Session whose read buffer is used.
172 */
173static void
174spdyf_handler_read_goaway (struct SPDY_Session *session)
175{
176 struct SPDYF_Control_Frame *frame;
177 uint32_t last_good_stream_id;
178 uint32_t status_int;
179 enum SPDY_GOAWAY_STATUS status;
180
181 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
182 "the function is called wrong");
183
184 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
185
186 if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
187 {
188 //this is a protocol error/attack
189 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
190 return;
191 }
192
193 if(0 != frame->flags || 8 != frame->length)
194 {
195 //this is a protocol error
196 SPDYF_DEBUG("wrong GOAWAY received");
197 //anyway, it will be handled
198 }
199
200 if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
201 {
202 //not all fields are received
203 //try later
204 return;
205 }
206
207 //mark that the session is almost closed
208 session->is_goaway_received = true;
209
210 if(8 == frame->length)
211 {
212 memcpy(&last_good_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
213 last_good_stream_id = NTOH31(last_good_stream_id);
214 session->read_buffer_beginning += 4;
215
216 memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
217 status = ntohl(status_int);
218 session->read_buffer_beginning += 4;
219
220 //TODO do something with last_good
221
222 //SPDYF_DEBUG("Received GOAWAY; status=%i; lastgood=%i",status,last_good_stream_id);
223
224 //do something according to the status
225 //TODO
226 switch(status)
227 {
228 case SPDY_GOAWAY_STATUS_OK:
229 break;
230 case SPDY_GOAWAY_STATUS_PROTOCOL_ERROR:
231 break;
232 case SPDY_GOAWAY_STATUS_INTERNAL_ERROR:
233 break;
234 }
235 }
236
237 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
238 free(frame);
239}
240
241
242/**
243 * Handler for reading RST_STREAM frames. After receiving the frame
244 * the stream moves into closed state and status
245 * of the session is changed. Frames, belonging to this stream, which
246 * are still at the output queue, will be ignored later.
247 *
248 * @param session SPDY_Session whose read buffer is used.
249 */
250static void
251spdyf_handler_read_rst_stream (struct SPDY_Session *session)
252{
253 struct SPDYF_Control_Frame *frame;
254 uint32_t stream_id;
255 int32_t status_int;
256 enum SPDY_RST_STREAM_STATUS status;
257 struct SPDYF_Stream *stream;
258
259 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
260 "the function is called wrong");
261
262 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
263
264 if(0 != frame->flags || 8 != frame->length)
265 {
266 //this is a protocol error
267 SPDYF_DEBUG("wrong RST_STREAM received");
268 //ignore as a large frame
269 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
270 return;
271 }
272
273 if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length)
274 {
275 //not all fields are received
276 //try later
277 return;
278 }
279
280 memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
281 stream_id = NTOH31(stream_id);
282 session->read_buffer_beginning += 4;
283
284 memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4);
285 status = ntohl(status_int);
286 session->read_buffer_beginning += 4;
287
288 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
289 free(frame);
290
291 //mark the stream as closed
292 stream = session->streams_head;
293 while(NULL != stream)
294 {
295 if(stream_id == stream->stream_id)
296 {
297 stream->is_in_closed = true;
298 stream->is_out_closed = true;
299 break;
300 }
301 stream = stream->next;
302 }
303
304 SPDYF_DEBUG("Received RST_STREAM; status=%i; id=%i",status,stream_id);
305
306 //do something according to the status
307 //TODO
308 /*switch(status)
309 {
310 case SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR:
311 break;
312 }*/
313}
314
315
316/**
317 * Handler for reading DATA frames. In requests they are used for POST
318 * arguments.
319 *
320 * @param session SPDY_Session whose read buffer is used.
321 */
322static void
323spdyf_handler_read_data (struct SPDY_Session *session)
324{
325 (void)session;
326 //TODO ignore data frames for now
327 SPDYF_PANIC("POST requests are Not yet implemented!");
328}
329
330
331int
332SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
333{
334 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
335 struct SPDYF_Stream *stream = response_queue->stream;
336 struct SPDYF_Control_Frame control_frame;
337 void *compressed_headers = NULL;
338 size_t compressed_headers_size=0;
339 size_t used_data=0;
340 size_t total_size;
341 uint32_t stream_id_nbo;
342
343 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
344
345 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
346
347 if(SPDY_YES != SPDYF_zlib_deflate(&session->zlib_send_stream,
348 response_queue->data,
349 response_queue->data_size,
350 &used_data,
351 &compressed_headers,
352 &compressed_headers_size))
353 {
354 /* something went wrong on compressing,
355 * the state of the stream for compression is unknown
356 * and we may not be able to send anything more on
357 * this session,
358 * so it is better to close the session right now */
359 session->status = SPDY_SESSION_STATUS_CLOSING;
360
361 free(compressed_headers);
362
363 return SPDY_NO;
364 }
365
366 //TODO do we need this used_Data
367 SPDYF_ASSERT(used_data == response_queue->data_size, "not everything was used by zlib");
368
369 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
370 + 4 // stream id as "subheader"
371 + compressed_headers_size;
372
373 if(NULL == (session->write_buffer = malloc(total_size)))
374 {
375 /* no memory
376 * since we do not save the compressed data anywhere and
377 * the sending zlib stream is already in new state, we must
378 * close the session */
379 session->status = SPDY_SESSION_STATUS_CLOSING;
380
381 free(compressed_headers);
382
383 return SPDY_NO;
384 }
385 session->write_buffer_beginning = 0;
386 session->write_buffer_offset = 0;
387 session->write_buffer_size = total_size;
388
389 control_frame.length = compressed_headers_size + 4; // compressed data + stream_id
390 SPDYF_CONTROL_FRAME_HTON(&control_frame);
391
392 //put frame headers to write buffer
393 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
394 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
395
396 //put stream id to write buffer
397 stream_id_nbo = HTON31(stream->stream_id);
398 memcpy(session->write_buffer + session->write_buffer_offset, &stream_id_nbo, 4);
399 session->write_buffer_offset += 4;
400
401 //put compressed name/value pairs to write buffer
402 memcpy(session->write_buffer + session->write_buffer_offset, compressed_headers, compressed_headers_size);
403 session->write_buffer_offset += compressed_headers_size;
404
405 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
406 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
407
408 //DEBUG CODE, break compression state to see what happens
409/* SPDYF_zlib_deflate(&session->zlib_send_stream,
410 "1234567890",
411 10,
412 &used_data,
413 &compressed_headers,
414 &compressed_headers_size);
415*/
416 free(compressed_headers);
417
418 session->last_replied_to_stream_id = stream->stream_id;
419
420 return SPDY_YES;
421}
422
423
424int
425SPDYF_handler_write_goaway (struct SPDY_Session *session)
426{
427 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
428 struct SPDYF_Control_Frame control_frame;
429 size_t total_size;
430 int last_good_stream_id;
431
432 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
433
434 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
435
436 session->is_goaway_sent = true;
437
438 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
439 + 4 // last good stream id as "subheader"
440 + 4; // status code as "subheader"
441
442 if(NULL == (session->write_buffer = malloc(total_size)))
443 {
444 return SPDY_NO;
445 }
446 session->write_buffer_beginning = 0;
447 session->write_buffer_offset = 0;
448 session->write_buffer_size = total_size;
449
450 control_frame.length = 8; // always for GOAWAY
451 SPDYF_CONTROL_FRAME_HTON(&control_frame);
452
453 //put frame headers to write buffer
454 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
455 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
456
457 //put last good stream id to write buffer
458 last_good_stream_id = HTON31(session->last_replied_to_stream_id);
459 memcpy(session->write_buffer + session->write_buffer_offset, &last_good_stream_id, 4);
460 session->write_buffer_offset += 4;
461
462 //put "data" to write buffer. This is the status
463 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 4);
464 session->write_buffer_offset += 4;
465 //data is not freed by the destroy function so:
466 //free(response_queue->data);
467
468 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
469 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
470
471 return SPDY_YES;
472}
473
474
475int
476SPDYF_handler_write_data (struct SPDY_Session *session)
477{
478 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
479 struct SPDYF_Response_Queue *new_response_queue;
480 size_t total_size;
481 struct SPDYF_Data_Frame data_frame;
482 ssize_t ret;
483 bool more;
484
485 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
486
487 memcpy(&data_frame, response_queue->data_frame, sizeof(data_frame));
488
489 if(NULL == response_queue->response->rcb)
490 {
491 //standard response with data into the struct
492 SPDYF_ASSERT(NULL != response_queue->data, "no data for the response");
493
494 total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
495 + response_queue->data_size;
496
497 if(NULL == (session->write_buffer = malloc(total_size)))
498 {
499 return SPDY_NO;
500 }
501 session->write_buffer_beginning = 0;
502 session->write_buffer_offset = 0;
503 session->write_buffer_size = total_size;
504
505 data_frame.length = response_queue->data_size;
506 SPDYF_DATA_FRAME_HTON(&data_frame);
507
508 //put SPDY headers to the writing buffer
509 memcpy(session->write_buffer + session->write_buffer_offset,&data_frame,sizeof(struct SPDYF_Data_Frame));
510 session->write_buffer_offset += sizeof(struct SPDYF_Data_Frame);
511
512 //put data to the writing buffer
513 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, response_queue->data_size);
514 session->write_buffer_offset += response_queue->data_size;
515 }
516 else
517 {
518 /* response with callbacks. The lib will produce more than 1
519 * data frames
520 */
521
522 total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
523 + SPDY_MAX_SUPPORTED_FRAME_SIZE; //max possible size
524
525 if(NULL == (session->write_buffer = malloc(total_size)))
526 {
527 return SPDY_NO;
528 }
529 session->write_buffer_beginning = 0;
530 session->write_buffer_offset = 0;
531 session->write_buffer_size = total_size;
532
533 ret = response_queue->response->rcb(response_queue->response->rcb_cls,
534 session->write_buffer + sizeof(struct SPDYF_Data_Frame),
535 response_queue->response->rcb_block_size,
536 &more);
537
538 if(ret < 0 || ret > response_queue->response->rcb_block_size)
539 {
540 //TODO send RST_STREAM (app error)
541 //for now close session
542 session->status = SPDY_SESSION_STATUS_CLOSING;
543
544 free(session->write_buffer);
545 return SPDY_NO;
546 }
547 if(0 == ret && more)
548 {
549 //the app couldn't write anything to buf but later will
550 free(session->write_buffer);
551 session->write_buffer = NULL;
552 session->write_buffer_size = 0;
553
554 if(NULL != response_queue->next)
555 {
556 //put the frame at the end of the queue
557 //otherwise - head of line blocking
558 session->response_queue_head = response_queue->next;
559 session->response_queue_head->prev = NULL;
560 session->response_queue_tail->next = response_queue;
561 response_queue->prev = session->response_queue_tail;
562 response_queue->next = NULL;
563 session->response_queue_tail = response_queue;
564 }
565
566 return SPDY_YES;
567 }
568
569 if(more)
570 {
571 //create another response queue object to call the user cb again
572 if(NULL == (new_response_queue = SPDYF_response_queue_create(true,
573 NULL,
574 0,
575 response_queue->response,
576 response_queue->stream,
577 false,
578 response_queue->frqcb,
579 response_queue->frqcb_cls,
580 response_queue->rrcb,
581 response_queue->rrcb_cls)))
582 {
583 //TODO send RST_STREAM
584 //for now close session
585 session->status = SPDY_SESSION_STATUS_CLOSING;
586
587 free(session->write_buffer);
588 return SPDY_NO;
589 }
590
591 //put it at second position on the queue
592 new_response_queue->prev = response_queue;
593 new_response_queue->next = response_queue->next;
594 if(NULL == response_queue->next)
595 {
596 session->response_queue_tail = new_response_queue;
597 }
598 else
599 {
600 response_queue->next->prev = new_response_queue;
601 }
602 response_queue->next = new_response_queue;
603
604 response_queue->frqcb = NULL;
605 response_queue->frqcb_cls = NULL;
606 response_queue->rrcb = NULL;
607 response_queue->rrcb_cls = NULL;
608 }
609 else
610 {
611 data_frame.flags |= SPDY_DATA_FLAG_FIN;
612 }
613
614 data_frame.length = ret;
615 SPDYF_DATA_FRAME_HTON(&data_frame);
616
617 //put SPDY headers to the writing buffer
618 memcpy(session->write_buffer + session->write_buffer_offset,
619 &data_frame,
620 sizeof(struct SPDYF_Data_Frame));
621 session->write_buffer_offset += sizeof(struct SPDYF_Data_Frame);
622 session->write_buffer_offset += ret;
623 session->write_buffer_size = session->write_buffer_offset;
624 }
625
626 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
627 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
628
629 return SPDY_YES;
630}
631
632
633int
634SPDYF_handler_write_rst_stream (struct SPDY_Session *session)
635{
636 struct SPDYF_Response_Queue *response_queue = session->response_queue_head;
637 struct SPDYF_Control_Frame control_frame;
638 size_t total_size;
639
640 SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment");
641
642 memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame));
643
644 total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
645 + 4 // stream id as "subheader"
646 + 4; // status code as "subheader"
647
648 if(NULL == (session->write_buffer = malloc(total_size)))
649 {
650 return SPDY_NO;
651 }
652 session->write_buffer_beginning = 0;
653 session->write_buffer_offset = 0;
654 session->write_buffer_size = total_size;
655
656 control_frame.length = 8; // always for RST_STREAM
657 SPDYF_CONTROL_FRAME_HTON(&control_frame);
658
659 //put frame headers to write buffer
660 memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
661 session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
662
663 //put stream id to write buffer. This is the status
664 memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8);
665 session->write_buffer_offset += 8;
666 //data is not freed by the destroy function so:
667 //free(response_queue->data);
668
669 SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
670 SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2");
671
672 return SPDY_YES;
673}
674
675
676void
677SPDYF_handler_ignore_frame (struct SPDY_Session *session)
678{
679 struct SPDYF_Control_Frame *frame;
680
681 SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
682 || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
683 "the function is called wrong");
684
685
686 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
687
688 //handle subheaders
689 if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
690 {
691 if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
692 {
693 session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
694 return;
695 }
696 else
697 session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
698 }
699
700 //handle body
701
702 if(session->read_buffer_offset - session->read_buffer_beginning
703 >= frame->length)
704 {
705 session->read_buffer_beginning += frame->length;
706 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
707 free(frame);
708 }
709}
710
711
712int
713SPDYF_session_read (struct SPDY_Session *session)
714{
715 int bytes_read;
716 bool reallocate;
717 size_t actual_buf_size;
718
719 if(SPDY_SESSION_STATUS_CLOSING == session->status
720 || SPDY_SESSION_STATUS_FLUSHING == session->status)
721 return SPDY_NO;
722
723 //if the read buffer is full to the end, we need to reallocate space
724 if (session->read_buffer_size == session->read_buffer_offset)
725 {
726 //but only if the state of the session requires it
727 //i.e. no further proceeding is possible without reallocation
728 reallocate = false;
729 actual_buf_size = session->read_buffer_offset
730 - session->read_buffer_beginning;
731 switch(session->status)
732 {
733 case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
734
735 case SPDY_SESSION_STATUS_IGNORE_BYTES:
736 //we need space for a whole control frame header
737 if(actual_buf_size < sizeof(struct SPDYF_Control_Frame))
738 reallocate = true;
739 break;
740
741 case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
742
743 case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
744 //we need as many bytes as set in length field of the
745 //header
746 SPDYF_ASSERT(NULL != session->frame_handler_cls,
747 "no frame for session");
748 if(session->frame_handler != &spdyf_handler_read_data)
749 {
750 if(actual_buf_size
751 < ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length)
752 reallocate = true;
753 }
754 else
755 {
756 if(actual_buf_size
757 < ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length)
758 reallocate = true;
759 }
760 break;
761
762 case SPDY_SESSION_STATUS_CLOSING:
763 case SPDY_SESSION_STATUS_FLUSHING:
764 //nothing needed
765 break;
766 }
767
768 if(reallocate)
769 {
770 //reuse the space in the buffer that was already read by the lib
771 memmove(session->read_buffer,
772 session->read_buffer + session->read_buffer_beginning,
773 session->read_buffer_offset - session->read_buffer_beginning);
774
775 session->read_buffer_offset -= session->read_buffer_beginning;
776 session->read_buffer_beginning = 0;
777 }
778 else
779 {
780 //will read next time
781 //TODO optimize it, memmove more often?
782 return SPDY_NO;
783 }
784 }
785
786 session->last_activity = SPDYF_monotonic_time();
787
788 //actual read from the TLS socket
789 bytes_read = SPDYF_tls_recv(session,
790 session->read_buffer + session->read_buffer_offset,
791 session->read_buffer_size - session->read_buffer_offset);
792
793 switch(bytes_read)
794 {
795 case SPDY_TLS_ERROR_CLOSED:
796 //The TLS connection was closed by the other party, clean
797 //or not
798 shutdown (session->socket_fd, SHUT_RD);
799 session->read_closed = true;
800 session->status = SPDY_SESSION_STATUS_CLOSING;
801 return SPDY_YES;
802
803 case SPDY_TLS_ERROR_ERROR:
804 //any kind of error in the TLS subsystem
805 //try to prepare GOAWAY frame
806 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
807 //try to flush the queue when write is called
808 session->status = SPDY_SESSION_STATUS_FLUSHING;
809 return SPDY_YES;
810
811 case SPDY_TLS_ERROR_AGAIN:
812 //read or write should be called again; leave it for the
813 //next time
814 return SPDY_NO;
815
816 //default:
817 //something was really read from the TLS subsystem
818 //just continue
819 }
820
821 session->read_buffer_offset += bytes_read;
822
823 return SPDY_YES;
824}
825
826
827int
828SPDYF_session_write (struct SPDY_Session *session, bool only_one_frame)
829{
830 int i;
831 int bytes_written;
832 struct SPDYF_Response_Queue *queue_head;
833 struct SPDYF_Response_Queue *response_queue;
834
835 if(SPDY_SESSION_STATUS_CLOSING == session->status)
836 return SPDY_NO;
837
838 for(i=0;
839 only_one_frame
840 ? i < 1
841 : i < SPDYF_NUM_SENT_FRAMES_AT_ONCE;
842 ++i)
843 {
844 //if the buffer is not null, part of the last frame is still
845 //pending to be sent
846 if(NULL == session->write_buffer)
847 {
848 //discard frames on closed streams
849 response_queue = session->response_queue_head;
850
851 while(NULL != response_queue)
852 {
853 //if stream is closed, remove not yet sent frames
854 //associated with it
855 //GOAWAY frames are not associated to streams
856 //and still need to be sent
857 if(NULL == response_queue->stream
858 || !response_queue->stream->is_out_closed)
859 break;
860
861 DLL_remove(session->response_queue_head,session->response_queue_tail,response_queue);
862
863 if(NULL != response_queue->frqcb)
864 {
865 response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_STREAM_CLOSED);
866 }
867
868 SPDYF_response_queue_destroy(response_queue);
869 response_queue = session->response_queue_head;
870 }
871
872 if(NULL == session->response_queue_head)
873 break;//nothing on the queue
874
875 //get next data from queue and put it to the write buffer
876 // to send it
877 if(SPDY_NO == session->response_queue_head->process_response_handler(session))
878 {
879 //error occured and the handler changed or not the
880 //session's status appropriately
881 if(SPDY_SESSION_STATUS_CLOSING == session->status)
882 {
883 //try to send GOAWAY first if the current frame is different
884 if(session->response_queue_head->is_data
885 || SPDY_CONTROL_FRAME_TYPES_GOAWAY
886 != session->response_queue_head->control_frame->type)
887 {
888 session->status = SPDY_SESSION_STATUS_FLUSHING;
889 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, true);
890 SPDYF_session_write(session,true);
891 session->status = SPDY_SESSION_STATUS_CLOSING;
892 }
893 return SPDY_YES;
894 }
895
896 //just return from the loop to return from this function
897 break;
898 }
899
900 //check if something was prepared for writing
901 //on respones with callbacks it is possible that their is no
902 //data available
903 if(0 == session->write_buffer_size)//nothing to write
904 if(response_queue != session->response_queue_head)
905 {
906 //the handler modified the queue
907 continue;
908 }
909 else
910 {
911 //no need to try the same frame again
912 break;
913 }
914 }
915
916 session->last_activity = SPDYF_monotonic_time();
917
918 //actual write to the TLS socket
919 bytes_written = SPDYF_tls_send(session,
920 session->write_buffer + session->write_buffer_beginning,
921 session->write_buffer_offset - session->write_buffer_beginning);
922
923 switch(bytes_written)
924 {
925 case SPDY_TLS_ERROR_CLOSED:
926 //The TLS connection was closed by the other party, clean
927 //or not
928 shutdown (session->socket_fd, SHUT_RD);
929 session->read_closed = true;
930 session->status = SPDY_SESSION_STATUS_CLOSING;
931 return SPDY_YES;
932
933 case SPDY_TLS_ERROR_ERROR:
934 //any kind of error in the TLS subsystem
935 //forbid more writing
936 session->status = SPDY_SESSION_STATUS_CLOSING;
937 return SPDY_YES;
938
939 case SPDY_TLS_ERROR_AGAIN:
940 //read or write should be called again; leave it for the
941 //next time; return from the function as we do not now
942 //whether reading or writing is needed
943 return i>0 ? SPDY_YES : SPDY_NO;
944
945 //default:
946 //something was really read from the TLS subsystem
947 //just continue
948 }
949
950 session->write_buffer_beginning += bytes_written;
951
952 //check if the full buffer was written
953 if(session->write_buffer_beginning == session->write_buffer_size)
954 {
955 //that response is handled, remove it from queue
956 free(session->write_buffer);
957 session->write_buffer = NULL;
958 session->write_buffer_size = 0;
959 queue_head = session->response_queue_head;
960 if(NULL == queue_head->next)
961 {
962 session->response_queue_head = NULL;
963 session->response_queue_tail = NULL;
964 }
965 else
966 {
967 session->response_queue_head = queue_head->next;
968 session->response_queue_head->prev = NULL;
969 }
970
971 //set stream to closed if the frame's fin flag is set
972 SPDYF_stream_set_flags(queue_head);
973
974 if(NULL != queue_head->frqcb)
975 {
976 //application layer callback to notify sending of the response
977 queue_head->frqcb(queue_head->frqcb_cls, queue_head, SPDY_RESPONSE_RESULT_SUCCESS);
978 }
979
980 SPDYF_response_queue_destroy(queue_head);
981 }
982 }
983
984 if(SPDY_SESSION_STATUS_FLUSHING == session->status
985 && NULL == session->response_queue_head)
986 session->status = SPDY_SESSION_STATUS_CLOSING;
987
988 return i>0 ? SPDY_YES : SPDY_NO;
989}
990
991
992int
993SPDYF_session_idle (struct SPDY_Session *session)
994{
995 size_t read_buffer_beginning;
996 size_t frame_length;
997 struct SPDYF_Control_Frame* control_frame;
998 struct SPDYF_Data_Frame *data_frame;
999
1000 //prepare session for closing if timeout is used and already passed
1001 if(SPDY_SESSION_STATUS_CLOSING != session->status
1002 && session->daemon->session_timeout
1003 && (session->last_activity + session->daemon->session_timeout < SPDYF_monotonic_time()))
1004 {
1005 session->status = SPDY_SESSION_STATUS_CLOSING;
1006 //best effort for sending GOAWAY
1007 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
1008 SPDYF_session_write(session,true);
1009 }
1010
1011 switch(session->status)
1012 {
1013 //expect new frame to arrive
1014 case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
1015 session->current_stream_id = 0;
1016 //check if the whole frame header is already here
1017 //both frame types have the same length
1018 if(session->read_buffer_offset - session->read_buffer_beginning
1019 < sizeof(struct SPDYF_Control_Frame))
1020 return SPDY_NO;
1021
1022 /* check the first bit to see if it is data or control frame
1023 * and also if the version is supported */
1024 if(0x80 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning)
1025 && SPDY_VERSION == *((uint8_t *)session->read_buffer + session->read_buffer_beginning + 1))
1026 {
1027 //control frame
1028 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1029 {
1030 SPDYF_DEBUG("No memory");
1031 return SPDY_NO;
1032 }
1033
1034 //get frame headers
1035 memcpy(control_frame,
1036 session->read_buffer + session->read_buffer_beginning,
1037 sizeof(struct SPDYF_Control_Frame));
1038 session->read_buffer_beginning += sizeof(struct SPDYF_Control_Frame);
1039 SPDYF_CONTROL_FRAME_NTOH(control_frame);
1040
1041 session->status = SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER;
1042 //assign different frame handler according to frame type
1043 switch(control_frame->type){
1044 case SPDY_CONTROL_FRAME_TYPES_SYN_STREAM:
1045 session->frame_handler = &spdyf_handler_read_syn_stream;
1046 break;
1047 case SPDY_CONTROL_FRAME_TYPES_GOAWAY:
1048 session->frame_handler = &spdyf_handler_read_goaway;
1049 break;
1050 case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
1051 session->frame_handler = &spdyf_handler_read_rst_stream;
1052 break;
1053 default:
1054 session->frame_handler = &SPDYF_handler_ignore_frame;
1055 }
1056 session->frame_handler_cls = control_frame;
1057 //DO NOT break the outer case
1058 }
1059 else if(0 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning))
1060 {
1061 //needed for POST
1062 //data frame
1063 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
1064 {
1065 SPDYF_DEBUG("No memory");
1066 return SPDY_NO;
1067 }
1068
1069 //get frame headers
1070 memcpy(data_frame,
1071 session->read_buffer + session->read_buffer_beginning,
1072 sizeof(struct SPDYF_Data_Frame));
1073 session->read_buffer_beginning += sizeof(struct SPDYF_Data_Frame);
1074
1075 session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
1076 session->frame_handler = &spdyf_handler_read_data;
1077 session->frame_handler_cls = data_frame;
1078 //DO NOT brake the outer case
1079 }
1080 else
1081 {
1082 SPDYF_DEBUG("another protocol or version received!");
1083
1084 /* According to the draft the lib should send here
1085 * RST_STREAM with status UNSUPPORTED_VERSION. I don't
1086 * see any sense of keeping the session open since
1087 * we don't know how many bytes is the bogus "frame".
1088 * And the latter normally will be HTTP request.
1089 *
1090 */
1091
1092 //shutdown(session->socket_fd, SHUT_RD);
1093 session->status = SPDY_SESSION_STATUS_FLUSHING;
1094 SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_PROTOCOL_ERROR,false);
1095 //SPDYF_session_write(session,false);
1096 /* close connection since the client expects another
1097 protocol from us */
1098 //SPDYF_session_close(session);
1099 return SPDY_YES;
1100 }
1101
1102 //expect specific header fields after the standard header
1103 case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
1104 if(NULL!=session->frame_handler)
1105 {
1106 read_buffer_beginning = session->read_buffer_beginning;
1107 //if everything is ok, the "body" will also be processed
1108 //by the handler
1109 session->frame_handler(session);
1110
1111 if(SPDY_SESSION_STATUS_IGNORE_BYTES == session->status)
1112 {
1113 //check for larger than max supported frame
1114 if(session->frame_handler != &spdyf_handler_read_data)
1115 {
1116 frame_length = ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length;
1117 }
1118 else
1119 {
1120 frame_length = ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length;
1121 }
1122
1123 //if(SPDY_MAX_SUPPORTED_FRAME_SIZE < frame_length)
1124 {
1125 SPDYF_DEBUG("received frame with unsupported size: %zu", frame_length);
1126 //the data being received must be ignored and
1127 //RST_STREAM sent
1128
1129 //ignore bytes that will arive later
1130 session->read_ignore_bytes = frame_length
1131 + read_buffer_beginning
1132 - session->read_buffer_offset;
1133 //ignore what is already in read buffer
1134 session->read_buffer_beginning = session->read_buffer_offset;
1135
1136 SPDYF_prepare_rst_stream(session,
1137 session->current_stream_id, //may be 0 here which is not good
1138 SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE);
1139
1140 //actually the read buffer can be bigger than the
1141 //max supported size
1142 session->status = session->read_ignore_bytes
1143 ? SPDY_SESSION_STATUS_IGNORE_BYTES
1144 : SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
1145
1146 free(session->frame_handler_cls);
1147 }
1148 }
1149 }
1150
1151 if(SPDY_SESSION_STATUS_IGNORE_BYTES != session->status)
1152 {
1153 break;
1154 }
1155
1156 //ignoring data in read buffer
1157 case SPDY_SESSION_STATUS_IGNORE_BYTES:
1158 SPDYF_ASSERT(session->read_ignore_bytes > 0,
1159 "Session is in wrong state");
1160 if(session->read_ignore_bytes
1161 > session->read_buffer_offset - session->read_buffer_beginning)
1162 {
1163 session->read_ignore_bytes -=
1164 session->read_buffer_offset - session->read_buffer_beginning;
1165 session->read_buffer_beginning = session->read_buffer_offset;
1166 }
1167 else
1168 {
1169 session->read_buffer_beginning += session->read_ignore_bytes;
1170 session->read_ignore_bytes = 0;
1171 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
1172 }
1173 break;
1174
1175 //expect frame body (name/value pairs)
1176 case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
1177 if(NULL!=session->frame_handler)
1178 session->frame_handler(session);
1179 break;
1180
1181 case SPDY_SESSION_STATUS_FLUSHING:
1182
1183 return SPDY_NO;
1184
1185 //because of error the session needs to be closed
1186 case SPDY_SESSION_STATUS_CLOSING:
1187 //error should be already sent to the client
1188 SPDYF_session_close(session);
1189 return SPDY_YES;
1190 }
1191
1192 return SPDY_YES;
1193}
1194
1195
1196void
1197SPDYF_session_close (struct SPDY_Session *session)
1198{
1199 struct SPDY_Daemon *daemon = session->daemon;
1200 int by_client = session->read_closed ? SPDY_YES : SPDY_NO;
1201
1202 //shutdown the tls and deinit the tls context
1203 SPDYF_tls_close_session(session);
1204 shutdown (session->socket_fd,
1205 session->read_closed ? SHUT_WR : SHUT_RDWR);
1206 session->read_closed = true;
1207
1208 //remove session from the list
1209 DLL_remove (daemon->sessions_head,
1210 daemon->sessions_tail,
1211 session);
1212 //add the session for the list for cleaning up
1213 DLL_insert (daemon->cleanup_head,
1214 daemon->cleanup_tail,
1215 session);
1216
1217 //call callback for closed session
1218 if(NULL != daemon->session_closed_cb)
1219 {
1220 daemon->session_closed_cb(daemon->cls, session, by_client);
1221 }
1222}
1223
1224
1225int
1226SPDYF_session_accept(struct SPDY_Daemon *daemon)
1227{
1228 int new_socket_fd;
1229 //int fd_flags;
1230 struct SPDY_Session *session = NULL;
1231 socklen_t addr_len;
1232 struct sockaddr *addr;
1233#if HAVE_INET6
1234 struct sockaddr_in6 addr6;
1235
1236 addr = (struct sockaddr *)&addr6;
1237 addr_len = sizeof(addr6);
1238#else
1239 struct sockaddr_in addr4;
1240
1241 addr = (struct sockaddr *)&addr4;
1242 addr_len = sizeof(addr6);
1243#endif
1244
1245 new_socket_fd = accept (daemon->socket_fd, addr, &addr_len);
1246
1247 if(new_socket_fd < 1)
1248 return SPDY_NO;
1249
1250 //setting the socket to be non-blocking
1251 /*
1252 * different handling is needed by libssl if non-blocking is used
1253 *
1254 fd_flags = fcntl (new_socket_fd, F_GETFL);
1255 if ( -1 == fd_flags
1256 || 0 != fcntl (new_socket_fd, F_SETFL, fd_flags | O_NONBLOCK))
1257 {
1258 SPDYF_DEBUG("WARNING: Couldn't set the new connection to be non-blocking");
1259 }
1260 */
1261
1262 if (NULL == (session = malloc (sizeof (struct SPDY_Session))))
1263 {
1264 goto free_and_fail;
1265 }
1266 memset (session, 0, sizeof (struct SPDY_Session));
1267
1268 session->daemon = daemon;
1269 session->socket_fd = new_socket_fd;
1270
1271 //init TLS context, handshake will be done
1272 if(SPDY_YES != SPDYF_tls_new_session(session))
1273 {
1274 goto free_and_fail;
1275 }
1276
1277 //read buffer
1278 session->read_buffer_size = SPDYF_BUFFER_SIZE;
1279 if (NULL == (session->read_buffer = malloc (session->read_buffer_size)))
1280 {
1281 SPDYF_tls_close_session(session);
1282 goto free_and_fail;
1283 }
1284
1285 //address of the client
1286 if (NULL == (session->addr = malloc (addr_len)))
1287 {
1288 SPDYF_tls_close_session(session);
1289 goto free_and_fail;
1290 }
1291 memcpy (session->addr, addr, addr_len);
1292
1293 session->addr_len = addr_len;
1294 session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
1295
1296 //init zlib context for the whole session
1297 if(SPDY_YES != SPDYF_zlib_deflate_init(&session->zlib_send_stream))
1298 {
1299 SPDYF_tls_close_session(session);
1300 goto free_and_fail;
1301 }
1302 if(SPDY_YES != SPDYF_zlib_inflate_init(&session->zlib_recv_stream))
1303 {
1304 SPDYF_tls_close_session(session);
1305 SPDYF_zlib_deflate_end(&session->zlib_send_stream);
1306 goto free_and_fail;
1307 }
1308
1309 //add it to daemon's list
1310 DLL_insert(daemon->sessions_head,daemon->sessions_tail,session);
1311
1312 session->last_activity = SPDYF_monotonic_time();
1313
1314 if(NULL != daemon->new_session_cb)
1315 daemon->new_session_cb(daemon->cls, session);
1316
1317 return SPDY_YES;
1318
1319 //for GOTO
1320 free_and_fail:
1321 /* something failed, so shutdown, close and free memory */
1322 shutdown (new_socket_fd, SHUT_RDWR);
1323 close (new_socket_fd);
1324
1325 if(NULL != session)
1326 {
1327 if(NULL != session->addr)
1328 free (session->addr);
1329 if(NULL != session->read_buffer)
1330 free (session->read_buffer);
1331 free (session);
1332 }
1333 return SPDY_NO;
1334}
1335
1336
1337void
1338SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
1339 struct SPDY_Session *session,
1340 int consider_priority)
1341{
1342 struct SPDYF_Response_Queue *pos;
1343 struct SPDYF_Response_Queue *last;
1344 uint8_t priority;
1345
1346 SPDYF_ASSERT(SPDY_YES != consider_priority || NULL != response_to_queue->stream,
1347 "called with consider_priority but no stream provided");
1348
1349 last = response_to_queue;
1350 while(NULL != last->next)
1351 {
1352 last = last->next;
1353 }
1354
1355 if(SPDY_NO == consider_priority)
1356 {
1357 //put it at the end of the queue
1358 response_to_queue->prev = session->response_queue_tail;
1359 if (NULL == session->response_queue_head)
1360 session->response_queue_head = response_to_queue;
1361 else
1362 session->response_queue_tail->next = response_to_queue;
1363 session->response_queue_tail = last;
1364 return;
1365 }
1366 else if(-1 == consider_priority)
1367 {
1368 //put it at the head of the queue
1369 last->next = session->response_queue_head;
1370 if (NULL == session->response_queue_tail)
1371 session->response_queue_tail = last;
1372 else
1373 session->response_queue_head->prev = response_to_queue;
1374 session->response_queue_head = response_to_queue;
1375 return;
1376 }
1377
1378 if(NULL == session->response_queue_tail)
1379 {
1380 session->response_queue_head = response_to_queue;
1381 session->response_queue_tail = last;
1382 return;
1383 }
1384
1385 //search for the right position to put it
1386 pos = session->response_queue_tail;
1387 priority = response_to_queue->stream->priority;
1388 while(NULL != pos
1389 && pos->stream->priority > priority)
1390 {
1391 pos = pos->prev;
1392 }
1393
1394 if(NULL == pos)
1395 {
1396 //put it on the head
1397 session->response_queue_head->prev = last;
1398 last->next = session->response_queue_head;
1399 session->response_queue_head = response_to_queue;
1400 }
1401 else if(NULL == pos->next)
1402 {
1403 //put it at the end
1404 response_to_queue->prev = pos;
1405 pos->next = response_to_queue;
1406 session->response_queue_tail = last;
1407 }
1408 else
1409 {
1410 response_to_queue->prev = pos;
1411 last->next = pos->next;
1412 pos->next = response_to_queue;
1413 last->next->prev = last;
1414 }
1415}
1416
1417
1418void
1419SPDYF_session_destroy(struct SPDY_Session *session)
1420{
1421 struct SPDYF_Stream *stream;
1422 struct SPDYF_Response_Queue *response_queue;
1423
1424 close (session->socket_fd);
1425 SPDYF_zlib_deflate_end(&session->zlib_send_stream);
1426 SPDYF_zlib_inflate_end(&session->zlib_recv_stream);
1427
1428 //clean up unsent data in the output queue
1429 while (NULL != (response_queue = session->response_queue_head))
1430 {
1431 DLL_remove (session->response_queue_head,
1432 session->response_queue_tail,
1433 response_queue);
1434
1435 if(NULL != response_queue->frqcb)
1436 {
1437 response_queue->frqcb(response_queue->frqcb_cls, response_queue, SPDY_RESPONSE_RESULT_SESSION_CLOSED);
1438 }
1439
1440 SPDYF_response_queue_destroy(response_queue);
1441 }
1442
1443 //clean up the streams belonging to this session
1444 while (NULL != (stream = session->streams_head))
1445 {
1446 DLL_remove (session->streams_head,
1447 session->streams_tail,
1448 stream);
1449
1450 SPDYF_stream_destroy(stream);
1451 }
1452
1453 free(session->addr);
1454 free(session->read_buffer);
1455 free(session->write_buffer);
1456 free(session);
1457}
1458
1459
1460int
1461SPDYF_prepare_goaway (struct SPDY_Session *session,
1462 enum SPDY_GOAWAY_STATUS status,
1463 bool in_front)
1464{
1465 struct SPDYF_Response_Queue *response_to_queue;
1466 struct SPDYF_Control_Frame *control_frame;
1467 uint32_t *data;
1468
1469 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
1470 {
1471 return SPDY_NO;
1472 }
1473 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
1474
1475 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1476 {
1477 free(response_to_queue);
1478 return SPDY_NO;
1479 }
1480 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
1481
1482 if(NULL == (data = malloc(4)))
1483 {
1484 free(control_frame);
1485 free(response_to_queue);
1486 return SPDY_NO;
1487 }
1488 *(data) = htonl(status);
1489
1490 control_frame->control_bit = 1;
1491 control_frame->version = SPDY_VERSION;
1492 control_frame->type = SPDY_CONTROL_FRAME_TYPES_GOAWAY;
1493 control_frame->flags = 0;
1494
1495 response_to_queue->control_frame = control_frame;
1496 response_to_queue->process_response_handler = &SPDYF_handler_write_goaway;
1497 response_to_queue->data = data;
1498 response_to_queue->data_size = 4;
1499
1500 SPDYF_queue_response (response_to_queue,
1501 session,
1502 in_front ? -1 : SPDY_NO);
1503
1504 return SPDY_YES;
1505}
1506
1507
1508int
1509SPDYF_prepare_rst_stream (struct SPDY_Session *session,
1510 uint32_t stream_id,
1511 enum SPDY_RST_STREAM_STATUS status)
1512{
1513 struct SPDYF_Response_Queue *response_to_queue;
1514 struct SPDYF_Control_Frame *control_frame;
1515 uint32_t *data;
1516
1517 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
1518 {
1519 return SPDY_NO;
1520 }
1521 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
1522
1523 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
1524 {
1525 free(response_to_queue);
1526 return SPDY_NO;
1527 }
1528 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
1529
1530 if(NULL == (data = malloc(8)))
1531 {
1532 free(control_frame);
1533 free(response_to_queue);
1534 return SPDY_NO;
1535 }
1536 *(data) = HTON31(stream_id);
1537 *(data + 1) = htonl(status);
1538
1539 control_frame->control_bit = 1;
1540 control_frame->version = SPDY_VERSION;
1541 control_frame->type = SPDY_CONTROL_FRAME_TYPES_RST_STREAM;
1542 control_frame->flags = 0;
1543
1544 response_to_queue->control_frame = control_frame;
1545 response_to_queue->process_response_handler = &SPDYF_handler_write_rst_stream;
1546 response_to_queue->data = data;
1547 response_to_queue->data_size = 8;
1548
1549 SPDYF_queue_response (response_to_queue,
1550 session,
1551 -1);
1552
1553 return SPDY_YES;
1554}
diff --git a/src/microspdy/session.h b/src/microspdy/session.h
new file mode 100644
index 00000000..cdfa8d15
--- /dev/null
+++ b/src/microspdy/session.h
@@ -0,0 +1,248 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file session.h
21 * @brief TCP connection/SPDY session handling
22 * @author Andrey Uzunov
23 */
24
25#ifndef SESSION_H
26#define SESSION_H
27
28#include "platform.h"
29#include "structures.h"
30
31/**
32 * Called by the daemon when the socket for the session has available
33 * data to be read. Reads data from the TLS socket and puts it to the
34 * session's read buffer. The latte
35 *
36 * @param session SPDY_Session for which data will be read.
37 * @return SPDY_YES if something was read or session's status was
38 * changed. It is possible that error occurred but was handled
39 * and the status was therefore changed.
40 * SPDY_NO if nothing happened, e.g. the subsystem wants read/
41 * write to be called again.
42 */
43int
44SPDYF_session_read (struct SPDY_Session *session);
45
46
47/**
48 * Called by the daemon when the socket for the session is ready for some
49 * data to be written to it. For one or more objects on the response
50 * queue tries to fill in the write buffer, based on the frame on the
51 * queue, and to write data to the TLS socket.
52 *
53 * @param session SPDY_Session for which data will be written.
54 * @return TODO document after changes
55 * SPDY_YES if something was written, the status was changed or
56 * response callback was called but did not provide data
57 * @return SPDY_YES if something was written, session's status was
58 * changed or response callback was called but did not provide
59 * data. It is possible that error occurred but was handled
60 * and the status was therefore changed.
61 * SPDY_NO if nothing happened, e.g. the subsystem wants read/
62 * write to be called again. However, it is possible that some
63 * frames were discarded within the call, e.g. frames belonging
64 * to a closed stream.
65 */
66int
67SPDYF_session_write (struct SPDY_Session *session, bool only_one_frame);
68
69
70/**
71 * Called by the daemon on SPDY_run to handle the data in the read and write
72 * buffer of a session. Based on the state and the content of the read
73 * buffer new frames are received and interpreted, appropriate user
74 * callbacks are called and maybe something is put on the response queue
75 * ready to be handled by session_write.
76 *
77 * @param session SPDY_Session which will be handled.
78 * @return SPDY_YES if something from the read buffers was processed,
79 * session's status was changed and/or the session was closed.
80 * SPDY_NO if nothing happened, e.g. the session is in a state,
81 * not allowing processing read buffers.
82 */
83int
84SPDYF_session_idle (struct SPDY_Session *session);
85
86
87/**
88 * This function shutdowns the socket, moves the session structure to
89 * daemon's queue for sessions to be cleaned up.
90 *
91 * @param session SPDY_Session which will be handled.
92 */
93void
94SPDYF_session_close (struct SPDY_Session *session);
95
96
97/**
98 * Called to accept new TCP connection and create SPDY session.
99 *
100 * @param daemon SPDY_Daemon whose listening socket is used.
101 * @return SPDY_NO on any kind of error while accepting new TCP connection
102 * and initializing new SPDY_Session.
103 * SPDY_YES otherwise.
104 */
105int
106SPDYF_session_accept(struct SPDY_Daemon *daemon);
107
108
109/**
110 * Puts SPDYF_Response_Queue object on the queue to be sent to the
111 * client later.
112 *
113 * @param response_to_queue linked list of objects containing SPDY
114 * frame and data to be added to the queue
115 * @param session SPDY session for which the response is sent
116 * @param consider_priority if SPDY_NO, the list will be added to the
117 * end of the queue.
118 * If SPDY_YES, the response will be added after
119 * the last previously added response with priority of the
120 * request grater or equal to that of the current one.
121 * If -1, the object will be put at the head of the queue.
122 */
123void
124SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
125 struct SPDY_Session *session,
126 int consider_priority);
127
128
129/**
130 * Cleans up the TSL context for the session, closes the TCP connection,
131 * cleans up any data pointed by members of the session structure
132 * (buffers, queue of responses, etc.) and frees the memory allocated by
133 * the session itself.
134 */
135void
136SPDYF_session_destroy(struct SPDY_Session *session);
137
138
139/**
140 * Prepares GOAWAY frame to tell the client to stop creating new streams.
141 * The session should be closed soon after this call.
142 *
143 * @param session SPDY session
144 * @param status code for the GOAWAY frame
145 * @param in_front whether or not to put the frame in front of everything
146 * on the response queue
147 * @return SPDY_NO on error (not enough memory) or
148 * SPDY_YES on success
149 */
150int
151SPDYF_prepare_goaway (struct SPDY_Session *session,
152 enum SPDY_GOAWAY_STATUS status,
153 bool in_front);
154
155
156/**
157 * Prepares RST_STREAM frame to terminate a stream. This frame may or
158 * not indicate an error. The frame will be put at the head of the queue.
159 * This means that frames for this stream which are still in the queue
160 * will be discarded soon.
161 *
162 * @param session SPDY session
163 * @param stream_id stream to terminate
164 * @param status code for the RST_STREAM frame
165 * @return SPDY_NO on memory error or
166 * SPDY_YES on success
167 */
168int
169SPDYF_prepare_rst_stream (struct SPDY_Session *session,
170 uint32_t stream_id,
171 enum SPDY_RST_STREAM_STATUS status);
172
173
174/**
175 * Handler called by session_write to fill the write buffer according to
176 * the data frame waiting in the response queue.
177 * When response data is given by user callback, the lib does not know
178 * how many frames are needed. In such case this call produces
179 * another ResponseQueue object and puts it on the queue while the the
180 * user callback says that there will be more data.
181 *
182 * @return SPDY_NO on error (not enough memory or the user calback for
183 * providing response data did something wrong). If
184 * the error is unrecoverable the handler changes session's
185 * status.
186 * SPDY_YES on success
187 */
188int
189SPDYF_handler_write_data (struct SPDY_Session *session);
190
191
192/**
193 * Handler called by session_write to fill the write buffer based on the
194 * control frame (SYN_REPLY) waiting in the response queue.
195 *
196 * @param session SPDY session
197 * @return SPDY_NO on error (zlib state is broken; the session MUST be
198 * closed). If
199 * the error is unrecoverable the handler changes session's
200 * status.
201 * SPDY_YES on success
202 */
203int
204SPDYF_handler_write_syn_reply (struct SPDY_Session *session);
205
206
207/**
208 * Handler called by session_write to fill the write buffer based on the
209 * control frame (GOAWAY) waiting in the response queue.
210 *
211 * @param session SPDY session
212 * @return SPDY_NO on error (not enough memory; by specification the
213 * session must be closed
214 * soon, thus there is no need to handle the error) or
215 * SPDY_YES on success
216 */
217int
218SPDYF_handler_write_goaway (struct SPDY_Session *session);
219
220
221/**
222 * Handler called by session_write to fill the write buffer based on the
223 * control frame (RST_STREAM) waiting in the response queue.
224 *
225 * @param session SPDY session
226 * @return SPDY_NO on error (not enough memory). If
227 * the error is unrecoverable the handler changes session's
228 * status.
229 * SPDY_YES on success
230 */
231int
232SPDYF_handler_write_rst_stream (struct SPDY_Session *session);
233
234
235/**
236 * Carefully ignore the full size of frames which are not yet supported
237 * by the lib.
238 * TODO Ignoring frames containing compressed bodies means that the
239 * compress state will be corrupted on next received frame. According to
240 * the draft the lib SHOULD try to decompress data also in corrupted
241 * frames just to keep right compression state.
242 *
243 * @param session SPDY_Session whose read buffer is used.
244 */
245void
246SPDYF_handler_ignore_frame (struct SPDY_Session *session);
247
248#endif
diff --git a/src/microspdy/stream.c b/src/microspdy/stream.c
new file mode 100644
index 00000000..97fdd6c8
--- /dev/null
+++ b/src/microspdy/stream.c
@@ -0,0 +1,151 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file stream.c
21 * @brief SPDY streams handling
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "structures.h"
27#include "internal.h"
28#include "session.h"
29
30
31int
32SPDYF_stream_new (struct SPDY_Session *session)
33{
34 uint32_t stream_id;
35 uint32_t assoc_stream_id;
36 uint8_t priority;
37 uint8_t slot;
38 size_t buffer_pos = session->read_buffer_beginning;
39 struct SPDYF_Stream *stream;
40 struct SPDYF_Control_Frame *frame;
41
42 if((session->read_buffer_offset - session->read_buffer_beginning) < 10)
43 {
44 //not all fields are received to create new stream
45 return SPDY_NO;
46 }
47
48 frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
49
50 //get stream id of the new stream
51 memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4);
52 stream_id = NTOH31(stream_id);
53 session->read_buffer_beginning += 4;
54 if(stream_id <= session->last_in_stream_id || 0==(stream_id % 2))
55 {
56 //wrong stream id sent by client
57 //GOAWAY with PROTOCOL_ERROR MUST be sent
58 //TODO
59
60 //ignore frame
61 session->frame_handler = &SPDYF_handler_ignore_frame;
62 return SPDY_NO;
63 }
64 else if(session->is_goaway_sent)
65 {
66 //the client is not allowed to create new streams anymore
67 //we MUST ignore the frame
68 session->frame_handler = &SPDYF_handler_ignore_frame;
69 return SPDY_NO;
70 }
71
72 //set highest stream id for session
73 session->last_in_stream_id = stream_id;
74
75 //get assoc stream id of the new stream
76 //this value is used with SPDY PUSH, thus nothing to do with it here
77 memcpy(&assoc_stream_id, session->read_buffer + session->read_buffer_beginning, 4);
78 assoc_stream_id = NTOH31(assoc_stream_id);
79 session->read_buffer_beginning += 4;
80
81 //get stream priority (3 bits)
82 //after it there are 5 bits that are not used
83 priority = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning) >> 5;
84 session->read_buffer_beginning++;
85
86 //get slot (see SPDY draft)
87 slot = *(uint8_t *)(session->read_buffer + session->read_buffer_beginning);
88 session->read_buffer_beginning++;
89
90 if(NULL == (stream = malloc(sizeof(struct SPDYF_Stream))))
91 {
92 SPDYF_DEBUG("No memory");
93 //revert buffer state
94 session->read_buffer_beginning = buffer_pos;
95 return SPDY_NO;
96 }
97 memset(stream,0, sizeof(struct SPDYF_Stream));
98 stream->session = session;
99 stream->stream_id = stream_id;
100 stream->assoc_stream_id = assoc_stream_id;
101 stream->priority = priority;
102 stream->slot = slot;
103 stream->is_in_closed = (frame->flags & SPDY_SYN_STREAM_FLAG_FIN) != 0;
104 stream->flag_unidirectional = (frame->flags & SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0;
105 stream->is_out_closed = stream->flag_unidirectional;
106 stream->is_server_initiator = false;
107
108 //put the stream to the list of streams for the session
109 DLL_insert(session->streams_head, session->streams_tail, stream);
110
111 return SPDY_YES;
112}
113
114
115void
116SPDYF_stream_destroy(struct SPDYF_Stream *stream)
117{
118 SPDY_name_value_destroy(stream->headers);
119 free(stream);
120 stream = NULL;
121}
122
123
124void
125SPDYF_stream_set_flags(struct SPDYF_Response_Queue *response_queue)
126{
127 struct SPDYF_Stream * stream = response_queue->stream;
128
129 if(NULL != response_queue->data_frame)
130 {
131 stream->is_out_closed = (bool)(response_queue->data_frame->flags & SPDY_DATA_FLAG_FIN);
132 }
133 else if(NULL != response_queue->control_frame)
134 {
135 switch(response_queue->control_frame->type)
136 {
137 case SPDY_CONTROL_FRAME_TYPES_SYN_REPLY:
138 stream->is_out_closed = (bool)(response_queue->control_frame->flags & SPDY_SYN_REPLY_FLAG_FIN);
139 break;
140
141 case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
142 if(NULL != stream)
143 {
144 stream->is_out_closed = true;
145 stream->is_in_closed = true;
146 }
147 break;
148
149 }
150 }
151}
diff --git a/src/microspdy/stream.h b/src/microspdy/stream.h
new file mode 100644
index 00000000..a795ad28
--- /dev/null
+++ b/src/microspdy/stream.h
@@ -0,0 +1,65 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file stream.h
21 * @brief SPDY streams handling
22 * @author Andrey Uzunov
23 */
24
25#ifndef STREAM_H
26#define STREAM_H
27
28#include "platform.h"
29
30
31/**
32 * Reads data from session's read buffer and tries to create a new SPDY
33 * stream. This function is called after control frame's header has been
34 * read from the buffer (after the length field). If bogus frame is
35 * received the function changes the read handler of the session and
36 * fails, i.e. there is no need of further error handling by the caller.
37 *
38 * @param session SPDY_Session whose read buffer is being read
39 * @return SPDY_YES if a new SPDY stream request was correctly received
40 * and handled. SPDY_NO if the whole SPDY frame was not yet
41 * received or memory error occurred.
42 */
43int
44SPDYF_stream_new (struct SPDY_Session *session);
45
46
47/**
48 * Destroys stream structure and whatever is in it.
49 *
50 * @param stream SPDY_Stream to destroy
51 */
52void
53SPDYF_stream_destroy(struct SPDYF_Stream *stream);
54
55
56/**
57 * Set stream flags if needed based on the type of the frame that was
58 * just sent (e.g., close stream if it was RST_STREAM).
59 *
60 * @param response_queue sent for this stream
61 */
62void
63SPDYF_stream_set_flags(struct SPDYF_Response_Queue *response_queue);
64
65#endif
diff --git a/src/microspdy/structures.c b/src/microspdy/structures.c
new file mode 100644
index 00000000..b3760be3
--- /dev/null
+++ b/src/microspdy/structures.c
@@ -0,0 +1,612 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file structures.c
21 * @brief Functions for handling most of the structures in defined
22 * in structures.h
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include "structures.h"
28#include "internal.h"
29#include "session.h"
30
31
32struct SPDY_NameValue *
33SPDY_name_value_create ()
34{
35 struct SPDY_NameValue *pair;
36
37 if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
38 return NULL;
39
40 memset (pair, 0, sizeof (struct SPDY_NameValue));
41
42 return pair;
43}
44
45
46int
47SPDY_name_value_add (struct SPDY_NameValue *container,
48 const char *name,
49 const char *value)
50{
51 uint i;
52 uint len;
53 struct SPDY_NameValue *pair;
54 struct SPDY_NameValue *temp;
55 char **temp_value;
56 char *temp_string;
57
58 if(NULL == container || NULL == name || 0 == (len = strlen(name)))
59 return SPDY_INPUT_ERROR;
60
61 for(i=0; i<len; ++i)
62 {
63 if(isupper(name[i]))
64 return SPDY_INPUT_ERROR;
65 }
66
67 if(NULL == container->name && NULL == container->value)
68 {
69 //container is empty/just created
70 if (NULL == (container->name = strdup (name)))
71 {
72 return SPDY_NO;
73 }
74 if (NULL == (container->value = malloc(sizeof(char *))))
75 {
76 free(container->name);
77 return SPDY_NO;
78 }
79 if (NULL == (container->value[0] = strdup (value)))
80 {
81 free(container->value);
82 free(container->name);
83 return SPDY_NO;
84 }
85 container->num_values = 1;
86 return SPDY_YES;
87 }
88
89 pair = container;
90 while(NULL != pair)
91 {
92 if(0 == strcmp(pair->name, name))
93 {
94 //the value will be added to this pair
95 break;
96 }
97 pair = pair->next;
98 }
99
100 if(NULL == pair)
101 {
102 //the name doesn't exist in container, add new pair
103 if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
104 return SPDY_NO;
105
106 memset(pair, 0, sizeof(struct SPDY_NameValue));
107
108 if (NULL == (pair->name = strdup (name)))
109 {
110 free(pair);
111 return SPDY_NO;
112 }
113 if (NULL == (pair->value = malloc(sizeof(char *))))
114 {
115 free(pair->name);
116 free(pair);
117 return SPDY_NO;
118 }
119 if (NULL == (pair->value[0] = strdup (value)))
120 {
121 free(pair->value);
122 free(pair->name);
123 free(pair);
124 return SPDY_NO;
125 }
126 pair->num_values = 1;
127
128 temp = container;
129 while(NULL != temp->next)
130 temp = temp->next;
131 temp->next = pair;
132 pair->prev = temp;
133
134 return SPDY_YES;
135 }
136
137 //check for duplication (case sensitive)
138 for(i=0; i<pair->num_values; ++i)
139 if(0 == strcmp(pair->value[i], value))
140 return SPDY_NO;
141
142 if(strlen(pair->value[0]) > 0)
143 {
144 //the value will be appended to the others for this name
145 if (NULL == (temp_value = malloc((pair->num_values + 1) * sizeof(char *))))
146 {
147 return SPDY_NO;
148 }
149 memcpy(temp_value, pair->value, pair->num_values * sizeof(char *));
150 if (NULL == (temp_value[pair->num_values] = strdup (value)))
151 {
152 free(temp_value);
153 return SPDY_NO;
154 }
155 free(pair->value);
156 pair->value = temp_value;
157 ++pair->num_values;
158 return SPDY_YES;
159 }
160
161 //just replace the empty value
162
163 if (NULL == (temp_string = strdup (value)))
164 {
165 return SPDY_NO;
166 }
167 free(pair->value[0]);
168 pair->value[0] = temp_string;
169
170 return SPDY_YES;
171}
172
173
174const char * const *
175SPDY_name_value_lookup (struct SPDY_NameValue *container,
176 const char *name,
177 int *num_values)
178{
179 struct SPDY_NameValue *temp = container;
180
181 if(NULL == container || NULL == name || NULL == num_values)
182 return NULL;
183 if(NULL == container->name && NULL == container->value)
184 return NULL;
185
186 do
187 {
188 if(strcmp(name, temp->name) == 0)
189 {
190 *num_values = temp->num_values;
191 return (const char * const *)temp->value;
192 }
193
194 temp = temp->next;
195 }
196 while(NULL != temp);
197
198 return NULL;
199}
200
201
202void
203SPDY_name_value_destroy (struct SPDY_NameValue *container)
204{
205 uint i;
206 struct SPDY_NameValue *temp = container;
207
208 while(NULL != temp)
209 {
210 container = container->next;
211 free(temp->name);
212 for(i=0; i<temp->num_values; ++i)
213 free(temp->value[i]);
214 free(temp->value);
215 free(temp);
216 temp=container;
217 }
218}
219
220
221int
222SPDY_name_value_iterate (struct SPDY_NameValue *container,
223 SPDY_NameValueIterator iterator,
224 void *iterator_cls)
225{
226 int count;
227 int ret;
228 struct SPDY_NameValue *temp = container;
229
230 if(NULL == container)
231 return SPDY_INPUT_ERROR;
232
233 //check if container is an empty struct
234 if(NULL == container->name && NULL == container->value)
235 return 0;
236
237 count = 0;
238
239 if(NULL == iterator)
240 {
241 do
242 {
243 ++count;
244 temp=temp->next;
245 }
246 while(NULL != temp);
247
248 return count;
249 }
250
251 //code duplication for avoiding if here
252 do
253 {
254 ++count;
255 ret = iterator(iterator_cls, temp->name, (const char * const *)temp->value, temp->num_values);
256 temp=temp->next;
257 }
258 while(NULL != temp && SPDY_YES == ret);
259
260 return count;
261}
262
263void
264SPDY_destroy_response(struct SPDY_Response *response)
265{
266 free(response->data);
267 free(response->headers);
268 free(response);
269}
270
271
272struct SPDYF_Response_Queue *
273SPDYF_response_queue_create(bool is_data,
274 void *data,
275 size_t data_size,
276 struct SPDY_Response *response,
277 struct SPDYF_Stream *stream,
278 bool closestream,
279 SPDYF_ResponseQueueResultCallback frqcb,
280 void *frqcb_cls,
281 SPDY_ResponseResultCallback rrcb,
282 void *rrcb_cls)
283{
284 struct SPDYF_Response_Queue *head = NULL;
285 struct SPDYF_Response_Queue *prev;
286 struct SPDYF_Response_Queue *response_to_queue;
287 struct SPDYF_Control_Frame *control_frame;
288 struct SPDYF_Data_Frame *data_frame;
289 uint i;
290 bool is_last;
291
292 SPDYF_ASSERT(!is_data
293 || 0 == data_size && NULL != response->rcb
294 || 0 < data_size && NULL == response->rcb,
295 "either data or request->rcb must not be null");
296
297 if(is_data && data_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)
298 {
299 //separate the data in more frames and add them to the queue
300
301 prev=NULL;
302 for(i = 0; i < data_size; i += SPDY_MAX_SUPPORTED_FRAME_SIZE)
303 {
304 is_last = (i + SPDY_MAX_SUPPORTED_FRAME_SIZE) >= data_size;
305
306 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
307 goto free_and_fail;
308
309 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
310 if(0 == i)
311 head = response_to_queue;
312
313 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
314 {
315 free(response_to_queue);
316 goto free_and_fail;
317 }
318 memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
319 data_frame->control_bit = 0;
320 data_frame->stream_id = stream->stream_id;
321 if(is_last && closestream)
322 data_frame->flags |= SPDY_DATA_FLAG_FIN;
323
324 response_to_queue->data_frame = data_frame;
325 response_to_queue->process_response_handler = &SPDYF_handler_write_data;
326 response_to_queue->is_data = is_data;
327 response_to_queue->stream = stream;
328 if(is_last)
329 {
330 response_to_queue->frqcb = frqcb;
331 response_to_queue->frqcb_cls = frqcb_cls;
332 response_to_queue->rrcb = rrcb;
333 response_to_queue->rrcb_cls = rrcb_cls;
334 }
335 response_to_queue->data = data + i;
336 response_to_queue->data_size = is_last
337 ? (data_size - 1) % SPDY_MAX_SUPPORTED_FRAME_SIZE + 1
338 : SPDY_MAX_SUPPORTED_FRAME_SIZE;
339 response_to_queue->response = response;
340
341 response_to_queue->prev = prev;
342 if(NULL != prev)
343 prev->next = response_to_queue;
344 prev = response_to_queue;
345 }
346
347 return head;
348
349 //for GOTO
350 free_and_fail:
351 while(NULL != head)
352 {
353 response_to_queue = head;
354 head = head->next;
355 free(response_to_queue->data_frame);
356 free(response_to_queue);
357 }
358 return NULL;
359 }
360
361 //create only one frame for data, data with callback or control frame
362
363 if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
364 {
365 return NULL;
366 }
367 memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
368
369 if(is_data)
370 {
371 if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
372 {
373 free(response_to_queue);
374 return NULL;
375 }
376 memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
377 data_frame->control_bit = 0;
378 data_frame->stream_id = stream->stream_id;
379 if(closestream && NULL == response->rcb)
380 data_frame->flags |= SPDY_DATA_FLAG_FIN;
381
382 response_to_queue->data_frame = data_frame;
383 response_to_queue->process_response_handler = &SPDYF_handler_write_data;
384 }
385 else
386 {
387 if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
388 {
389 free(response_to_queue);
390 return NULL;
391 }
392 memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
393 control_frame->control_bit = 1;
394 control_frame->version = SPDY_VERSION;
395 control_frame->type = SPDY_CONTROL_FRAME_TYPES_SYN_REPLY;
396 if(closestream)
397 control_frame->flags |= SPDY_SYN_REPLY_FLAG_FIN;
398
399 response_to_queue->control_frame = control_frame;
400 response_to_queue->process_response_handler = &SPDYF_handler_write_syn_reply;
401 }
402
403 response_to_queue->is_data = is_data;
404 response_to_queue->stream = stream;
405 response_to_queue->frqcb = frqcb;
406 response_to_queue->frqcb_cls = frqcb_cls;
407 response_to_queue->rrcb = rrcb;
408 response_to_queue->rrcb_cls = rrcb_cls;
409 response_to_queue->data = data;
410 response_to_queue->data_size = data_size;
411 response_to_queue->response = response;
412
413 return response_to_queue;
414}
415
416
417void
418SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue)
419{
420 //data is not copied to the struct but only linked
421 //but this is not valid for GOAWAY and RST_STREAM
422 if(!response_queue->is_data
423 && (SPDY_CONTROL_FRAME_TYPES_RST_STREAM == response_queue->control_frame->type
424 || SPDY_CONTROL_FRAME_TYPES_GOAWAY == response_queue->control_frame->type))
425 {
426 free(response_queue->data);
427 }
428 if(response_queue->is_data)
429 free(response_queue->data_frame);
430 else
431 free(response_queue->control_frame);
432
433 free(response_queue);
434}
435
436
437ssize_t
438SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
439 int num_containers,
440 void **stream)
441{
442 size_t size;
443 int32_t num_pairs = 0;
444 int32_t value_size;
445 int32_t name_size;
446 int32_t temp;
447 uint i;
448 uint offset;
449 uint value_offset;
450 struct SPDY_NameValue * iterator;
451 int j;
452
453 size = 4; //for num pairs
454
455 for(j=0; j<num_containers; ++j)
456 {
457 iterator = container[j];
458 while(iterator != NULL)
459 {
460 ++num_pairs;
461 size += 4 + strlen(iterator->name); //length + string
462
463 SPDYF_ASSERT(iterator->num_values>0, "num_values is 0");
464
465 size += 4; //value length
466
467 for(i=0; i<iterator->num_values; ++i)
468 {
469 size += strlen(iterator->value[i]); // string
470 if(i/* || !strlen(iterator->value[i])*/) ++size; //NULL separator
471 }
472
473 iterator = iterator->next;
474 }
475}
476
477 if(NULL == (*stream = malloc(size)))
478 {
479 return -1;
480 }
481
482 //put num_pairs to the stream
483 num_pairs = htonl(num_pairs);
484 memcpy(*stream, &num_pairs, 4);
485 offset = 4;
486
487 //put all other headers to the stream
488 for(j=0; j<num_containers; ++j)
489 {
490 iterator = container[j];
491 while(iterator != NULL)
492 {
493 name_size = strlen(iterator->name);
494 temp = htonl(name_size);
495 memcpy(*stream + offset, &temp, 4);
496 offset += 4;
497 strncpy(*stream + offset, iterator->name, name_size);
498 offset += name_size;
499
500 value_offset = offset;
501 offset += 4;
502 for(i=0; i<iterator->num_values; ++i)
503 {
504 if(i /*|| !strlen(iterator->value[0])*/)
505 {
506 memset(*stream + offset, 0, 1);
507 ++offset;
508 if(!i) continue;
509 }
510 strncpy(*stream + offset, iterator->value[i], strlen(iterator->value[i]));
511 offset += strlen(iterator->value[i]);
512 }
513 value_size = offset - value_offset - 4;
514 value_size = htonl(value_size);
515 memcpy(*stream + value_offset, &value_size, 4);
516
517 iterator = iterator->next;
518 }
519}
520
521 SPDYF_ASSERT(offset == size,"offset is wrong");
522
523 return size;
524}
525
526
527int
528SPDYF_name_value_from_stream(void *stream,
529 size_t size,
530 struct SPDY_NameValue ** container)
531{
532 int32_t num_pairs;
533 int32_t value_size;
534 int32_t name_size;
535 int i;
536 uint offset = 0;
537 uint value_end_offset;
538 char *name;
539 char *value;
540
541 if(NULL == (*container = SPDY_name_value_create ()))
542 {
543 return SPDY_NO;
544 }
545
546 //get number of pairs
547 memcpy(&num_pairs, stream, 4);
548 offset = 4;
549 num_pairs = ntohl(num_pairs);
550
551 if(num_pairs > 0)
552 {
553 for(i = 0; i < num_pairs; ++i)
554 {
555 //get name size
556 memcpy(&name_size, stream + offset, 4);
557 offset += 4;
558 name_size = ntohl(name_size);
559 //get name
560 if(NULL == (name = strndup(stream + offset, name_size)))
561 {
562 SPDY_name_value_destroy(*container);
563 return SPDY_NO;
564 }
565 offset+=name_size;
566
567 //get value size
568 memcpy(&value_size, stream + offset, 4);
569 offset += 4;
570 value_size = ntohl(value_size);
571 value_end_offset = offset + value_size;
572 //get value
573 do
574 {
575 if(NULL == (value = strndup(stream + offset, value_size)))
576 {
577 free(name);
578 SPDY_name_value_destroy(*container);
579 return SPDY_NO;
580 }
581 offset += strlen(value);
582 if(offset < value_end_offset)
583 ++offset; //NULL separator
584
585 //add name/value to the struct
586 if(SPDY_YES != SPDY_name_value_add(*container, name, value))
587 {
588 free(name);
589 free(value);
590 SPDY_name_value_destroy(*container);
591 return SPDY_NO;
592 }
593 free(value);
594 }
595 while(offset < value_end_offset);
596
597 free(name);
598
599 if(offset != value_end_offset)
600 {
601 SPDY_name_value_destroy(*container);
602 return SPDY_INPUT_ERROR;
603 }
604 }
605 }
606
607 if(offset == size)
608 return SPDY_YES;
609
610 SPDY_name_value_destroy(*container);
611 return SPDY_INPUT_ERROR;
612}
diff --git a/src/microspdy/structures.h b/src/microspdy/structures.h
new file mode 100644
index 00000000..5fb91889
--- /dev/null
+++ b/src/microspdy/structures.h
@@ -0,0 +1,1128 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file structures.h
21 * @brief internal and public structures -- most of the structs used by
22 * the library are defined here
23 * @author Andrey Uzunov
24 */
25
26#ifndef STRUCTURES_H
27#define STRUCTURES_H
28
29#include "platform.h"
30#include "microspdy.h"
31#include "tls.h"
32
33
34/**
35 * All possible SPDY control frame types. The number is used in the header
36 * of the control frame.
37 */
38enum SPDY_CONTROL_FRAME_TYPES
39{
40 /**
41 * The SYN_STREAM control frame allows the sender to asynchronously
42 * create a stream between the endpoints.
43 */
44 SPDY_CONTROL_FRAME_TYPES_SYN_STREAM = 1,
45
46 /**
47 * SYN_REPLY indicates the acceptance of a stream creation by
48 * the recipient of a SYN_STREAM frame.
49 */
50 SPDY_CONTROL_FRAME_TYPES_SYN_REPLY = 2,
51
52 /**
53 * The RST_STREAM frame allows for abnormal termination of a stream.
54 * When sent by the creator of a stream, it indicates the creator
55 * wishes to cancel the stream. When sent by the recipient of a
56 * stream, it indicates an error or that the recipient did not want
57 * to accept the stream, so the stream should be closed.
58 */
59 SPDY_CONTROL_FRAME_TYPES_RST_STREAM = 3,
60
61 /**
62 * A SETTINGS frame contains a set of id/value pairs for
63 * communicating configuration data about how the two endpoints may
64 * communicate. SETTINGS frames can be sent at any time by either
65 * endpoint, are optionally sent, and are fully asynchronous. When
66 * the server is the sender, the sender can request that
67 * configuration data be persisted by the client across SPDY
68 * sessions and returned to the server in future communications.
69 */
70 SPDY_CONTROL_FRAME_TYPES_SETTINGS = 4,
71
72 /**
73 * The PING control frame is a mechanism for measuring a minimal
74 * round-trip time from the sender. It can be sent from the client
75 * or the server. Recipients of a PING frame should send an
76 * identical frame to the sender as soon as possible (if there is
77 * other pending data waiting to be sent, PING should take highest
78 * priority). Each ping sent by a sender should use a unique ID.
79 */
80 SPDY_CONTROL_FRAME_TYPES_PING = 6,
81
82 /**
83 * The GOAWAY control frame is a mechanism to tell the remote side
84 * of the connection to stop creating streams on this session. It
85 * can be sent from the client or the server.
86 */
87 SPDY_CONTROL_FRAME_TYPES_GOAWAY = 7,
88
89 /**
90 * The HEADERS frame augments a stream with additional headers. It
91 * may be optionally sent on an existing stream at any time.
92 * Specific application of the headers in this frame is
93 * application-dependent. The name/value header block within this
94 * frame is compressed.
95 */
96 SPDY_CONTROL_FRAME_TYPES_HEADERS = 8,
97
98 /**
99 * The WINDOW_UPDATE control frame is used to implement per stream
100 * flow control in SPDY. Flow control in SPDY is per hop, that is,
101 * only between the two endpoints of a SPDY connection. If there are
102 * one or more intermediaries between the client and the origin
103 * server, flow control signals are not explicitly forwarded by the
104 * intermediaries.
105 */
106 SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE = 9,
107
108 /**
109 * The CREDENTIAL control frame is used by the client to send
110 * additional client certificates to the server. A SPDY client may
111 * decide to send requests for resources from different origins on
112 * the same SPDY session if it decides that that server handles both
113 * origins. For example if the IP address associated with both
114 * hostnames matches and the SSL server certificate presented in the
115 * initial handshake is valid for both hostnames. However, because
116 * the SSL connection can contain at most one client certificate,
117 * the client needs a mechanism to send additional client
118 * certificates to the server.
119 */
120 SPDY_CONTROL_FRAME_TYPES_CREDENTIAL = 11
121};
122
123
124/**
125 * SPDY_SESSION_STATUS is used to show the current receiving state
126 * of each session, i.e. what is expected to come now, and how it should
127 * be handled.
128 */
129enum SPDY_SESSION_STATUS
130{
131 /**
132 * The session is in closing state, do not read read anything from
133 * it. Do not write anything to it.
134 */
135 SPDY_SESSION_STATUS_CLOSING = 0,
136
137 /**
138 * Wait for new SPDY frame to come.
139 */
140 SPDY_SESSION_STATUS_WAIT_FOR_HEADER = 1,
141
142 /**
143 * The standard 8 byte header of the SPDY frame was received and
144 * handled. Wait for the specific (sub)headers according to the
145 * frame type.
146 */
147 SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER = 2,
148
149 /**
150 * The specific (sub)headers were received and handled. Wait for the
151 * "body", i.e. wait for the name/value pairs compressed by zlib.
152 */
153 SPDY_SESSION_STATUS_WAIT_FOR_BODY = 3,
154
155 /**
156 * Ignore all the bytes read from the socket, e.g. larger frames.
157 */
158 SPDY_SESSION_STATUS_IGNORE_BYTES= 4,
159
160 /**
161 * The session is in pre-closing state, do not read read anything
162 * from it. In this state the output queue will be written to the
163 * socket.
164 */
165 SPDY_SESSION_STATUS_FLUSHING = 5,
166};
167
168
169/**
170 * Specific flags for the SYN_STREAM control frame.
171 */
172enum SPDY_SYN_STREAM_FLAG
173{
174 /**
175 * The sender won't send any more frames on this stream.
176 */
177 SPDY_SYN_STREAM_FLAG_FIN = 1,
178
179 /**
180 * The sender creates this stream as unidirectional.
181 */
182 SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL = 2
183};
184
185
186/**
187 * Specific flags for the SYN_REPLY control frame.
188 */
189enum SPDY_SYN_REPLY_FLAG
190{
191 /**
192 * The sender won't send any more frames on this stream.
193 */
194 SPDY_SYN_REPLY_FLAG_FIN = 1
195};
196
197
198/**
199 * Specific flags for the data frame.
200 */
201enum SPDY_DATA_FLAG
202{
203 /**
204 * The sender won't send any more frames on this stream.
205 */
206 SPDY_DATA_FLAG_FIN = 1,
207
208 /**
209 * The data in the frame is compressed.
210 * This flag appears only in the draft on ietf.org but not on
211 * chromium.org.
212 */
213 SPDY_DATA_FLAG_COMPRESS = 2
214};
215
216/**
217 * Status code within RST_STREAM control frame.
218 */
219enum SPDY_RST_STREAM_STATUS
220{
221 /**
222 * This is a generic error, and should only be used if a more
223 * specific error is not available.
224 */
225 SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR = 1,
226
227 /**
228 * This is returned when a frame is received for a stream which is
229 * not active.
230 */
231 SPDY_RST_STREAM_STATUS_INVALID_STREAM = 2,
232
233 /**
234 * Indicates that the stream was refused before any processing has
235 * been done on the stream.
236 */
237 SPDY_RST_STREAM_STATUS_REFUSED_STREAM = 3,
238
239 /**
240 * Indicates that the recipient of a stream does not support the
241 * SPDY version requested.
242 */
243 SPDY_RST_STREAM_STATUS_UNSUPPORTED_VERSION = 4,
244
245 /**
246 * Used by the creator of a stream to indicate that the stream is
247 * no longer needed.
248 */
249 SPDY_RST_STREAM_STATUS_CANCEL = 5,
250
251 /**
252 * This is a generic error which can be used when the implementation
253 * has internally failed, not due to anything in the protocol.
254 */
255 SPDY_RST_STREAM_STATUS_INTERNAL_ERROR = 6,
256
257 /**
258 * The endpoint detected that its peer violated the flow control
259 * protocol.
260 */
261 SPDY_RST_STREAM_STATUS_FLOW_CONTROL_ERROR = 7,
262
263 /**
264 * The endpoint received a SYN_REPLY for a stream already open.
265 */
266 SPDY_RST_STREAM_STATUS_STREAM_IN_USE = 8,
267
268 /**
269 * The endpoint received a data or SYN_REPLY frame for a stream
270 * which is half closed.
271 */
272 SPDY_RST_STREAM_STATUS_STREAM_ALREADY_CLOSED = 9,
273
274 /**
275 * The server received a request for a resource whose origin does
276 * not have valid credentials in the client certificate vector.
277 */
278 SPDY_RST_STREAM_STATUS_INVALID_CREDENTIALS = 10,
279
280 /**
281 * The endpoint received a frame which this implementation could not
282 * support. If FRAME_TOO_LARGE is sent for a SYN_STREAM, HEADERS,
283 * or SYN_REPLY frame without fully processing the compressed
284 * portion of those frames, then the compression state will be
285 * out-of-sync with the other endpoint. In this case, senders of
286 * FRAME_TOO_LARGE MUST close the session.
287 */
288 SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE = 11
289};
290
291
292/**
293 * Status code within GOAWAY control frame.
294 */
295enum SPDY_GOAWAY_STATUS
296{
297 /**
298 * This is a normal session teardown.
299 */
300 SPDY_GOAWAY_STATUS_OK = 0,
301
302 /**
303 * This is a generic error, and should only be used if a more
304 * specific error is not available.
305 */
306 SPDY_GOAWAY_STATUS_PROTOCOL_ERROR = 1,
307
308 /**
309 * This is a generic error which can be used when the implementation
310 * has internally failed, not due to anything in the protocol.
311 */
312 SPDY_GOAWAY_STATUS_INTERNAL_ERROR = 11
313};
314
315
316struct SPDYF_Stream;
317
318struct SPDYF_Response_Queue;
319
320/**
321 * Callback for new stream. To be used in the application layer of the
322 * lib.
323 *
324 * @param cls
325 * @param stream the new stream
326 * @return SPDY_YES on success,
327 * SPDY_NO if error occurs
328 */
329typedef int
330(*SPDYF_NewStreamCallback) (void *cls,
331 struct SPDYF_Stream * stream);
332
333
334/**
335 * Callback to be called when the response queue object was handled and
336 * the data was already sent.
337 *
338 * @param cls
339 * @param response_queue the SPDYF_Response_Queue structure which will
340 * be cleaned very soon
341 * @param status shows if actually the response was sent or it was
342 * discarded by the lib for any reason (e.g., closing session,
343 * closing stream, stopping daemon, etc.). It is possible that
344 * status indicates an error but part of the response (in one
345 * or several frames) was sent to the client.
346 */
347typedef void
348(*SPDYF_ResponseQueueResultCallback) (void * cls,
349 struct SPDYF_Response_Queue *response_queue,
350 enum SPDY_RESPONSE_RESULT status);
351
352
353/**
354 * Representation of the control frame's headers, which are common for
355 * all types.
356 */
357struct __attribute__((__packed__)) SPDYF_Control_Frame
358{
359 uint16_t version : 15;
360 uint16_t control_bit : 1; /* always 1 for control frames */
361 uint16_t type;
362 uint32_t flags : 8;
363 uint32_t length : 24;
364};
365
366
367/**
368 * Representation of the data frame's headers.
369 */
370struct __attribute__((__packed__)) SPDYF_Data_Frame
371{
372 uint32_t stream_id : 31;
373 uint32_t control_bit : 1; /* always 0 for data frames */
374 uint32_t flags : 8;
375 uint32_t length : 24;
376};
377
378
379/**
380 * Queue of the responses, to be handled (e.g. compressed) and sent later.
381 */
382struct SPDYF_Response_Queue
383{
384 /**
385 * This is a doubly-linked list.
386 */
387 struct SPDYF_Response_Queue *next;
388
389 /**
390 * This is a doubly-linked list.
391 */
392 struct SPDYF_Response_Queue *prev;
393
394 /**
395 * Stream (Request) for which is the response.
396 */
397 struct SPDYF_Stream *stream;
398
399 /**
400 * Response structure with all the data (uncompressed headers) to be sent.
401 */
402 struct SPDY_Response *response;
403
404 /**
405 * Control frame. The length field should be set after compressing
406 * the headers!
407 */
408 struct SPDYF_Control_Frame *control_frame;
409
410 /**
411 * Data frame. The length field should be set after compressing
412 * the body!
413 */
414 struct SPDYF_Data_Frame *data_frame;
415
416 /**
417 * Data to be sent: name/value pairs in control frames or body in data frames.
418 */
419 void *data;
420
421 /**
422 * Specific handler for different frame types.
423 */
424 int (* process_response_handler)(struct SPDY_Session *session);
425
426 /**
427 * Callback to be called when the last bytes from the response was sent
428 * to the client.
429 */
430 SPDYF_ResponseQueueResultCallback frqcb;
431
432 /**
433 * Closure for frqcb.
434 */
435 void *frqcb_cls;
436
437 /**
438 * Callback to be used by the application layer.
439 */
440 SPDY_ResponseResultCallback rrcb;
441
442 /**
443 * Closure for rcb.
444 */
445 void *rrcb_cls;
446
447 /**
448 * Data size.
449 */
450 size_t data_size;
451
452 /**
453 * True if data frame should be sent. False if control frame should
454 * be sent.
455 */
456 bool is_data;
457};
458
459
460
461/**
462 * Collection of HTTP headers used in requests and responses.
463 */
464struct SPDY_NameValue
465{
466 /**
467 * This is a doubly-linked list.
468 */
469 struct SPDY_NameValue *next;
470
471 /**
472 * This is a doubly-linked list.
473 */
474 struct SPDY_NameValue *prev;
475
476 /**
477 * Null terminated string for name.
478 */
479 char *name;
480
481 /**
482 * Array of Null terminated strings for value. num_values is the
483 * length of the array.
484 */
485 char **value;
486
487 /**
488 * Number of values, this is >= 0.
489 */
490 uint num_values;
491};
492
493
494/**
495 * Represents a SPDY stream
496 */
497struct SPDYF_Stream
498{
499 /**
500 * This is a doubly-linked list.
501 */
502 struct SPDYF_Stream *next;
503
504 /**
505 * This is a doubly-linked list.
506 */
507 struct SPDYF_Stream *prev;
508
509 /**
510 * Reference to the SPDY_Session struct.
511 */
512 struct SPDY_Session *session;
513
514 /**
515 * Name value pairs, sent within the frame which created the stream.
516 */
517 struct SPDY_NameValue *headers;
518
519 /**
520 * This stream's ID.
521 */
522 uint32_t stream_id;
523
524 /**
525 * Stream to which this one is associated.
526 */
527 uint32_t assoc_stream_id;
528
529 /**
530 * Stream priority. 0 is the highest, 7 is the lowest.
531 */
532 uint8_t priority;
533
534 /**
535 * Integer specifying the index in the server's CREDENTIAL vector of
536 * the client certificate to be used for this request The value 0
537 * means no client certificate should be associated with this stream.
538 */
539 uint8_t slot;
540
541 /**
542 * If initially the stream was created as unidirectional.
543 */
544 bool flag_unidirectional;
545
546 /**
547 * If the stream won't be used for receiving frames anymore. The
548 * client has sent FLAG_FIN or the stream was terminated with
549 * RST_STREAM.
550 */
551 bool is_in_closed;
552
553 /**
554 * If the stream won't be used for sending out frames anymore. The
555 * server has sent FLAG_FIN or the stream was terminated with
556 * RST_STREAM.
557 */
558 bool is_out_closed;
559
560 /**
561 * Which entity (server/client) has created the stream.
562 */
563 bool is_server_initiator;
564};
565
566
567/**
568 * Represents a SPDY session which is just a TCP connection
569 */
570struct SPDY_Session
571{
572 /**
573 * zlib stream for decompressing all the name/pair values from the
574 * received frames. All the received compressed data must be
575 * decompressed within one context: this stream. Thus, it should be
576 * unique for the session and initialized at its creation.
577 */
578 z_stream zlib_recv_stream;
579
580 /**
581 * zlib stream for compressing all the name/pair values from the
582 * frames to be sent. All the sent compressed data must be
583 * compressed within one context: this stream. Thus, it should be
584 * unique for the session and initialized at its creation.
585 */
586 z_stream zlib_send_stream;
587
588 /**
589 * This is a doubly-linked list.
590 */
591 struct SPDY_Session *next;
592
593 /**
594 * This is a doubly-linked list.
595 */
596 struct SPDY_Session *prev;
597
598 /**
599 * Reference to the SPDY_Daemon struct.
600 */
601 struct SPDY_Daemon *daemon;
602
603 /**
604 * Foreign address (of length addr_len).
605 */
606 struct sockaddr *addr;
607
608 /**
609 * Head of doubly-linked list of the SPDY streams belonging to the
610 * session.
611 */
612 struct SPDYF_Stream *streams_head;
613
614 /**
615 * Tail of doubly-linked list of the streams.
616 */
617 struct SPDYF_Stream *streams_tail;
618
619 /**
620 * Unique TLS context for the session. Initialized on each creation
621 * (actually when the TCP connection is established).
622 */
623 SPDYF_TLS_SESSION_CONTEXT *tls_context;
624
625 /**
626 * Head of doubly-linked list of the responses.
627 */
628 struct SPDYF_Response_Queue *response_queue_head;
629
630 /**
631 * Tail of doubly-linked list of the responses.
632 */
633 struct SPDYF_Response_Queue *response_queue_tail;
634
635 /**
636 * Buffer for reading requests.
637 */
638 void *read_buffer;
639
640 /**
641 * Buffer for writing responses.
642 */
643 void *write_buffer;
644
645 /**
646 * Specific handler for the frame that is currently being received.
647 */
648 void (*frame_handler) (struct SPDY_Session * session);
649
650 /**
651 * Closure for frame_handler.
652 */
653 void *frame_handler_cls;
654
655 /**
656 * Extra field to be used by the user with set/get func for whatever
657 * purpose he wants.
658 */
659 void *user_cls;
660
661 /**
662 * Number of bytes that the lib must ignore immediately after they
663 * are read from the TLS socket without adding them to the read buf.
664 * This is needed, for instance, when receiving frame bigger than
665 * the buffer to avoid deadlock situations.
666 */
667 size_t read_ignore_bytes;
668
669 /**
670 * Size of read_buffer (in bytes). This value indicates
671 * how many bytes we're willing to read into the buffer;
672 * the real buffer is one byte longer to allow for
673 * adding zero-termination (when needed).
674 */
675 size_t read_buffer_size;
676
677 /**
678 * Position where we currently append data in
679 * read_buffer (last valid position).
680 */
681 size_t read_buffer_offset;
682
683 /**
684 * Position until where everything was already read
685 */
686 size_t read_buffer_beginning;
687
688 /**
689 * Size of write_buffer (in bytes). This value indicates
690 * how many bytes we're willing to prepare for writing.
691 */
692 size_t write_buffer_size;
693
694 /**
695 * Position where we currently append data in
696 * write_buffer (last valid position).
697 */
698 size_t write_buffer_offset;
699
700 /**
701 * Position until where everything was already written to the socket
702 */
703 size_t write_buffer_beginning;
704
705 /**
706 * Last time this connection had any activity
707 * (reading or writing).
708 */
709 time_t last_activity;
710
711 /**
712 * Socket for this connection. Set to -1 if
713 * this connection has died (daemon should clean
714 * up in that case).
715 */
716 int socket_fd;
717
718 /**
719 * Length of the foreign address.
720 */
721 socklen_t addr_len;
722
723 /**
724 * The biggest stream ID for this session for streams initiated
725 * by the client.
726 */
727 uint32_t last_in_stream_id;
728
729 /**
730 * The biggest stream ID for this session for streams initiated
731 * by the server.
732 */
733 uint32_t last_out_stream_id;
734
735 /**
736 * This value is updated whenever SYN_REPLY or RST_STREAM are sent
737 * and is used later in GOAWAY frame.
738 * TODO it is not clear in the draft what happens when streams are
739 * not answered in the order of their IDs. Moreover, why should we
740 * send GOAWAY with the ID of received bogus SYN_STREAM with huge ID?
741 */
742 uint32_t last_replied_to_stream_id;
743
744 /**
745 * Shows the stream id of the currently handled frame. This value is
746 * to be used when sending RST_STREAM in answer to a problematic
747 * frame, e.g. larger than supported.
748 */
749 uint32_t current_stream_id;
750
751 /**
752 * Shows the current receiving state the session, i.e. what is
753 * expected to come now, and how it shold be handled.
754 */
755 enum SPDY_SESSION_STATUS status;
756
757 /**
758 * Has this socket been closed for reading (i.e.
759 * other side closed the connection)? If so,
760 * we must completely close the connection once
761 * we are done sending our response (and stop
762 * trying to read from this socket).
763 */
764 bool read_closed;
765
766 /**
767 * If the server sends GOAWAY, it must ignore all SYN_STREAMS for
768 * this session. Normally the server will soon close the TCP session.
769 */
770 bool is_goaway_sent;
771
772 /**
773 * If the server receives GOAWAY, it must not send new SYN_STREAMS
774 * on this session. Normally the client will soon close the TCP
775 * session.
776 */
777 bool is_goaway_received;
778};
779
780
781/**
782 * State and settings kept for each SPDY daemon.
783 */
784struct SPDY_Daemon
785{
786
787 /**
788 * Tail of doubly-linked list of our current, active sessions.
789 */
790 struct SPDY_Session *sessions_head;
791
792 /**
793 * Tail of doubly-linked list of our current, active sessions.
794 */
795 struct SPDY_Session *sessions_tail;
796
797 /**
798 * Tail of doubly-linked list of connections to clean up.
799 */
800 struct SPDY_Session *cleanup_head;
801
802 /**
803 * Tail of doubly-linked list of connections to clean up.
804 */
805 struct SPDY_Session *cleanup_tail;
806
807 /**
808 * Unique TLS context for the daemon. Initialized on daemon start.
809 */
810 SPDYF_TLS_DAEMON_CONTEXT *tls_context;
811
812 /**
813 * Certificate file of the server. File path is kept here.
814 */
815 char *certfile;
816
817 /**
818 * Key file for the certificate of the server. File path is
819 * kept here.
820 */
821 char *keyfile;
822
823
824 /**
825 * The address to which the listening socket is bound.
826 */
827 struct sockaddr *address;
828
829 /**
830 * Callback called when a new SPDY session is
831 * established by a client
832 */
833 SPDY_NewSessionCallback new_session_cb;
834
835 /**
836 * Callback called when a client closes the session
837 */
838 SPDY_SessionClosedCallback session_closed_cb;
839
840 /**
841 * Callback called when a client sends request
842 */
843 SPDY_NewRequestCallback new_request_cb;
844
845 /**
846 * Callback called when HTTP POST params are received
847 * after request
848 */
849 SPDY_NewPOSTDataCallback new_post_data_cb;
850
851 /**
852 * Closure argument for all the callbacks that can be used by the client.
853 */
854 void *cls;
855
856 /**
857 * Callback called when new stream is created.
858 */
859 SPDYF_NewStreamCallback fnew_stream_cb;
860
861 /**
862 * Closure argument for all the callbacks defined in the framing layer.
863 */
864 void *fcls;
865
866 /**
867 * After how many seconds of inactivity should
868 * connections time out? Zero for no timeout.
869 */
870 time_t session_timeout;
871
872 /**
873 * Listen socket.
874 */
875 int socket_fd;
876
877 /**
878 * Daemon's options.
879 */
880 enum SPDY_DAEMON_OPTION options;
881
882 /**
883 * Daemon's flags.
884 */
885 enum SPDY_DAEMON_FLAG flags;
886
887 /**
888 * Listen port.
889 */
890 uint16_t port;
891};
892
893
894/**
895 * Represents a SPDY response.
896 */
897struct SPDY_Response
898{
899 /**
900 * Raw uncompressed stream of the name/value pairs in SPDY frame
901 * used for the HTTP headers.
902 */
903 void *headers;
904
905 /**
906 * Raw stream of the data to be sent. Equivalent to the body in HTTP
907 * response.
908 */
909 void *data;
910
911 /**
912 * Callback function to be used when the response data is provided
913 * with callbacks. In this case data must be NULL and data_size must
914 * be 0.
915 */
916 SPDY_ResponseCallback rcb;
917
918 /**
919 * Extra argument to rcb.
920 */
921 void *rcb_cls;
922
923 /**
924 * Length of headers.
925 */
926 size_t headers_size;
927
928 /**
929 * Length of data.
930 */
931 size_t data_size;
932
933 /**
934 * The callback func will be called to get that amount of bytes to
935 * put them into a DATA frame. It is either user preffered or
936 * the maximum supported by the lib value.
937 */
938 uint32_t rcb_block_size;
939};
940
941
942/* Macros for handling data and structures */
943
944
945/**
946 * Insert an element at the head of a DLL. Assumes that head, tail and
947 * element are structs with prev and next fields.
948 *
949 * @param head pointer to the head of the DLL (struct ? *)
950 * @param tail pointer to the tail of the DLL (struct ? *)
951 * @param element element to insert (struct ? *)
952 */
953#define DLL_insert(head,tail,element) do { \
954 (element)->next = (head); \
955 (element)->prev = NULL; \
956 if ((tail) == NULL) \
957 (tail) = element; \
958 else \
959 (head)->prev = element; \
960 (head) = (element); } while (0)
961
962
963/**
964 * Remove an element from a DLL. Assumes
965 * that head, tail and element are structs
966 * with prev and next fields.
967 *
968 * @param head pointer to the head of the DLL (struct ? *)
969 * @param tail pointer to the tail of the DLL (struct ? *)
970 * @param element element to remove (struct ? *)
971 */
972#define DLL_remove(head,tail,element) do { \
973 if ((element)->prev == NULL) \
974 (head) = (element)->next; \
975 else \
976 (element)->prev->next = (element)->next; \
977 if ((element)->next == NULL) \
978 (tail) = (element)->prev; \
979 else \
980 (element)->next->prev = (element)->prev; \
981 (element)->next = NULL; \
982 (element)->prev = NULL; } while (0)
983
984
985/**
986 * Convert all integers in a SPDY control frame headers structure from
987 * host byte order to network byte order.
988 *
989 * @param frame input and output structure (struct SPDY_Control_Frame *)
990 */
991#if HAVE_BIG_ENDIAN
992#define SPDYF_CONTROL_FRAME_HTON(frame)
993#else
994#define SPDYF_CONTROL_FRAME_HTON(frame) do { \
995 (*((uint16_t *) frame )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t *) frame ))<<8);\
996 (frame)->type = htons((frame)->type); \
997 (frame)->length = HTON24((frame)->length); \
998 } while (0)
999#endif
1000
1001
1002/**
1003 * Convert all integers in a SPDY control frame headers structure from
1004 * network byte order to host byte order.
1005 *
1006 * @param frame input and output structure (struct SPDY_Control_Frame *)
1007 */
1008#if HAVE_BIG_ENDIAN
1009#define SPDYF_CONTROL_FRAME_NTOH(frame)
1010#else
1011#define SPDYF_CONTROL_FRAME_NTOH(frame) do { \
1012 (*((uint16_t *) frame )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t *) frame ))<<8);\
1013 (frame)->type = ntohs((frame)->type); \
1014 (frame)->length = NTOH24((frame)->length); \
1015 } while (0)
1016#endif
1017
1018
1019/**
1020 * Convert all integers in a SPDY data frame headers structure from
1021 * host byte order to network byte order.
1022 *
1023 * @param frame input and output structure (struct SPDY_Data_Frame *)
1024 */
1025#if HAVE_BIG_ENDIAN
1026#define SPDYF_DATA_FRAME_HTON(frame)
1027#else
1028#define SPDYF_DATA_FRAME_HTON(frame) do { \
1029 *((uint32_t *) frame ) = htonl(*((uint32_t *) frame ));\
1030 (frame)->length = HTON24((frame)->length); \
1031 } while (0)
1032#endif
1033
1034
1035/**
1036 * Convert all integers in a SPDY data frame headers structure from
1037 * network byte order to host byte order.
1038 *
1039 * @param frame input and output structure (struct SPDY_Data_Frame *)
1040 */
1041#if HAVE_BIG_ENDIAN
1042#define SPDYF_DATA_FRAME_NTOH(frame)
1043#else
1044#define SPDYF_DATA_FRAME_NTOH(frame) do { \
1045 *((uint32_t *) frame ) = ntohl(*((uint32_t *) frame ));\
1046 (frame)->length = NTOH24((frame)->length); \
1047 } while (0)
1048#endif
1049
1050
1051/**
1052 * Creates one or more new SPDYF_Response_Queue object to be put on the
1053 * response queue.
1054 *
1055 * @param is_data whether new data frame or new control frame will be
1056 * crerated
1057 * @param data the row stream which will be used as the body of the frame
1058 * @param data_size length of data
1059 * @param response object, part of which is the frame
1060 * @param stream on which data is to be sent
1061 * @param closestream TRUE if the frame must close the stream (with flag)
1062 * @param frqcb callback to notify application layer when the frame
1063 * has been sent or discarded
1064 * @param frqcb_cls closure for frqcb
1065 * @param rrcb callback used by the application layer to notify the
1066 * application when the frame has been sent or discarded.
1067 * frqcb will call it
1068 * @param rrcb_cls closure for rrcb
1069 * @return double linked list of SPDYF_Response_Queue structures: one or
1070 * more frames are returned based on the size of the data
1071 */
1072struct SPDYF_Response_Queue *
1073SPDYF_response_queue_create(bool is_data,
1074 void *data,
1075 size_t data_size,
1076 struct SPDY_Response *response,
1077 struct SPDYF_Stream *stream,
1078 bool closestream,
1079 SPDYF_ResponseQueueResultCallback frqcb,
1080 void *frqcb_cls,
1081 SPDY_ResponseResultCallback rrcb,
1082 void *rrcb_cls);
1083
1084
1085/**
1086 * Destroys SPDYF_Response_Queue structure and whatever is in it.
1087 *
1088 * @param response_queue to destroy
1089 */
1090void
1091SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue);
1092
1093
1094/**
1095 * Transforms raw binary decomressed stream of headers
1096 * into SPDY_NameValue, containing all of the headers and values.
1097 *
1098 * @param stream that is to be transformed
1099 * @param size length of the stream
1100 * @param container will contain the newly created SPDY_NameValue
1101 * container. Should point to NULL.
1102 * @return SPDY_YES on success
1103 * SPDY_NO on memory error
1104 * SPDY_INPUT_ERROR if the provided stream is not valid
1105 */
1106int
1107SPDYF_name_value_from_stream(void *stream,
1108 size_t size,
1109 struct SPDY_NameValue ** container);
1110
1111
1112/**
1113 * Transforms array of objects of name/values tuples, containing HTTP
1114 * headers, into raw binary stream. The resulting stream is ready to
1115 * be compressed and sent.
1116 *
1117 * @param container one or more SPDY_NameValue objects. Each object
1118 * contains multiple number of name/value tuples.
1119 * @param num_containers length of the array
1120 * @param stream will contain the resulting stream. Should point to NULL.
1121 * @return length of stream or value less than 0 indicating error
1122 */
1123ssize_t
1124SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
1125 int num_containers,
1126 void **stream);
1127
1128#endif
diff --git a/src/microspdy/tls.c b/src/microspdy/tls.c
new file mode 100644
index 00000000..521f8f24
--- /dev/null
+++ b/src/microspdy/tls.c
@@ -0,0 +1,255 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file tls.c
21 * @brief TLS handling using libssl. The current code assumes that
22 * blocking I/O is in use.
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include "internal.h"
28#include "session.h"
29#include "tls.h"
30
31
32/**
33 * Callback to advertise spdy ver. 3 in Next Protocol Negotiation
34 *
35 * @param ssl openssl context for a connection
36 * @param out must be set to the raw data that is advertised in NPN
37 * @param outlen must be set to size of out
38 * @param arg
39 * @return SSL_TLSEXT_ERR_OK to do advertising
40 */
41static int
42spdyf_next_protos_advertised_cb (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg)
43{
44 (void)ssl;
45 (void)arg;
46 static unsigned char npn_spdy3[] = {0x06, // length of "spdy/3"
47 0x73,0x70,0x64,0x79,0x2f,0x33};// spdy/3
48
49 *out = npn_spdy3;
50 *outlen = 7; // total length of npn_spdy3
51 return SSL_TLSEXT_ERR_OK;
52}
53
54
55void
56SPDYF_tls_global_init()
57{
58 //error strings are now not used by the lib
59 //SSL_load_error_strings();
60 //init libssl
61 SSL_library_init(); //always returns 1
62 //the table for looking up algos is not used now by the lib
63 //OpenSSL_add_all_algorithms();
64}
65
66
67void
68SPDYF_tls_global_deinit()
69{
70 //if SSL_load_error_strings was called
71 //ERR_free_strings();
72 //if OpenSSL_add_all_algorithms was called
73 //EVP_cleanup();
74}
75
76
77int
78SPDYF_tls_init(struct SPDY_Daemon *daemon)
79{
80 //create ssl context. TLSv1 used
81 if(NULL == (daemon->tls_context = SSL_CTX_new(TLSv1_server_method())))
82 {
83 SPDYF_DEBUG("Couldn't create ssl context");
84 return SPDY_NO;
85 }
86 //set options for tls
87 //TODO DH is not enabled for easier debugging
88 //SSL_CTX_set_options(daemon->tls_context, SSL_OP_SINGLE_DH_USE);
89
90 //TODO here session tickets are disabled for easier debuging with
91 //wireshark when using Chrome
92 //SSL_OP_NO_COMPRESSION disables TLS compression to avoid CRIME attack
93 SSL_CTX_set_options(daemon->tls_context, SSL_OP_NO_TICKET | SSL_OP_NO_COMPRESSION);
94 if(1 != SSL_CTX_use_certificate_file(daemon->tls_context, daemon->certfile , SSL_FILETYPE_PEM))
95 {
96 SPDYF_DEBUG("Couldn't load the cert file");
97 SSL_CTX_free(daemon->tls_context);
98 return SPDY_NO;
99 }
100 if(1 != SSL_CTX_use_PrivateKey_file(daemon->tls_context, daemon->keyfile, SSL_FILETYPE_PEM))
101 {
102 SPDYF_DEBUG("Couldn't load the name file");
103 SSL_CTX_free(daemon->tls_context);
104 return SPDY_NO;
105 }
106 SSL_CTX_set_next_protos_advertised_cb(daemon->tls_context, &spdyf_next_protos_advertised_cb, NULL);
107 //TODO only RC4-SHA is used to make it easy to debug with wireshark
108 if (1 != SSL_CTX_set_cipher_list(daemon->tls_context, "RC4-SHA"))
109 {
110 SPDYF_DEBUG("Couldn't set the desired cipher list");
111 SSL_CTX_free(daemon->tls_context);
112 return SPDY_NO;
113 }
114
115 return SPDY_YES;
116}
117
118
119void
120SPDYF_tls_deinit(struct SPDY_Daemon *daemon)
121{
122 SSL_CTX_free(daemon->tls_context);
123}
124
125
126int
127SPDYF_tls_new_session(struct SPDY_Session *session)
128{
129 int ret;
130
131 if(NULL == (session->tls_context = SSL_new(session->daemon->tls_context)))
132 {
133 SPDYF_DEBUG("Couldn't create ssl structure");
134 return SPDY_NO;
135 }
136 if(1 != (ret = SSL_set_fd(session->tls_context, session->socket_fd)))
137 {
138 SPDYF_DEBUG("SSL_set_fd %i",ret);
139 SSL_free(session->tls_context);
140 session->tls_context = NULL;
141 return SPDY_NO;
142 }
143
144 //for non-blocking I/O SSL_accept may return -1
145 //and this function won't work
146 if(1 != (ret = SSL_accept(session->tls_context)))
147 {
148 SPDYF_DEBUG("SSL_accept %i",ret);
149 SSL_free(session->tls_context);
150 session->tls_context = NULL;
151 return SPDY_NO;
152 }
153 /* alternatively
154 SSL_set_accept_state(session->tls_context);
155 * may be called and then the negotiation will be done on reading
156 */
157
158 return SPDY_YES;
159}
160
161
162void
163SPDYF_tls_close_session(struct SPDY_Session *session)
164{
165 //SSL_shutdown sends TLS "close notify" as in TLS standard.
166 //The function may fail as it waits for the other party to also close
167 //the TLS session. The lib just sends it and will close the socket
168 //after that because the browsers don't seem to care much about
169 //"close notify"
170 SSL_shutdown(session->tls_context);
171
172 SSL_free(session->tls_context);
173}
174
175
176int
177SPDYF_tls_recv(struct SPDY_Session *session,
178 void * buffer,
179 size_t size)
180{
181 int ret;
182 int n = SSL_read(session->tls_context,
183 buffer,
184 size);
185 //if(n > 0) SPDYF_DEBUG("recvd: %i",n);
186 if (n <= 0)
187 {
188 ret = SSL_get_error(session->tls_context, n);
189 switch(ret)
190 {
191 case SSL_ERROR_ZERO_RETURN:
192 return 0;
193
194 case SSL_ERROR_WANT_READ:
195 case SSL_ERROR_WANT_WRITE:
196 return SPDY_TLS_ERROR_AGAIN;
197
198 case SSL_ERROR_SYSCALL:
199 if(EINTR == errno)
200 return SPDY_TLS_ERROR_AGAIN;
201
202 default:
203 return SPDY_TLS_ERROR_ERROR;
204 }
205 }
206
207 return n;
208}
209
210
211int
212SPDYF_tls_send(struct SPDY_Session *session,
213 const void * buffer,
214 size_t size)
215{
216 int ret;
217
218 int n = SSL_write(session->tls_context,
219 buffer,
220 size);
221 //if(n > 0) SPDYF_DEBUG("sent: %i",n);
222 if (n <= 0)
223 {
224 ret = SSL_get_error(session->tls_context, n);
225 switch(ret)
226 {
227 case SSL_ERROR_ZERO_RETURN:
228 return 0;
229
230 case SSL_ERROR_WANT_READ:
231 case SSL_ERROR_WANT_WRITE:
232 return SPDY_TLS_ERROR_AGAIN;
233
234 case SSL_ERROR_SYSCALL:
235 if(EINTR == errno)
236 return SPDY_TLS_ERROR_AGAIN;
237
238 default:
239 return SPDY_TLS_ERROR_ERROR;
240 }
241 }
242
243 return n;
244}
245
246
247int
248SPDYF_tls_is_pending(struct SPDY_Session *session)
249{
250 /* From openssl docs:
251 * BUGS
252SSL_pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). If the SSL object's read_ahead flag is set, additional protocol bytes may have been read containing more TLS/SSL records; these are ignored by SSL_pending().
253 */
254 return SSL_pending(session->tls_context) > 0 ? SPDY_YES : SPDY_NO;
255}
diff --git a/src/microspdy/tls.h b/src/microspdy/tls.h
new file mode 100644
index 00000000..5fb4371a
--- /dev/null
+++ b/src/microspdy/tls.h
@@ -0,0 +1,171 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2012 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file tls.h
21 * @brief TLS handling. openssl with NPN is used, but as long as the
22 * functions conform to this interface file, other libraries
23 * can be used.
24 * @author Andrey Uzunov
25 */
26
27#ifndef TLS_H
28#define TLS_H
29
30#include "platform.h"
31#include <openssl/err.h>
32#include <openssl/ssl.h>
33#include <openssl/rand.h>
34
35/* macros used in other files instead of types.
36 * useful in case of changing openssl to something else */
37#define SPDYF_TLS_SESSION_CONTEXT SSL
38#define SPDYF_TLS_DAEMON_CONTEXT SSL_CTX
39
40
41/**
42 * Used for return code when reading and writing to the TLS socket.
43 */
44enum SPDY_TLS_ERROR
45{
46 /**
47 * The connection was closed by the other party.
48 */
49 SPDY_TLS_ERROR_CLOSED = 0,
50
51 /**
52 * Any kind of error ocurred. The session has to be closed.
53 */
54 SPDY_TLS_ERROR_ERROR = -2,
55
56 /**
57 * The function had to return without processing any data. The whole
58 * cycle of events has to be called again (SPDY_run) as something
59 * either has to be written or read or the the syscall was
60 * interrupted by a signal.
61 */
62 SPDY_TLS_ERROR_AGAIN = -3,
63};
64
65
66/**
67 * Global initializing of openssl. Must be called only once in the program.
68 *
69 */
70void
71SPDYF_tls_global_init();
72
73
74/**
75 * Global deinitializing of openssl for the whole program. Should be called
76 * at the end of the program.
77 *
78 */
79void
80SPDYF_tls_global_deinit();
81
82
83/**
84 * Initializing of openssl for a specific daemon.
85 * Must be called when the daemon starts.
86 *
87 * @param daemon SPDY_Daemon for which openssl will be used. Daemon's
88 * certificate and key file are used.
89 * @return SPDY_YES on success or SPDY_NO on error
90 */
91int
92SPDYF_tls_init(struct SPDY_Daemon *daemon);
93
94
95/**
96 * Deinitializing openssl for a daemon. Should be called
97 * when the deamon is stopped.
98 *
99 * @param daemon SPDY_Daemon which is being stopped
100 */
101void
102SPDYF_tls_deinit(struct SPDY_Daemon *daemon);
103
104
105/**
106 * Initializing openssl for a specific connection. Must be called
107 * after the connection has been accepted.
108 *
109 * @param session SPDY_Session whose socket will be used by openssl
110 * @return SPDY_NO if some openssl funcs fail. SPDY_YES otherwise
111 */
112int
113SPDYF_tls_new_session(struct SPDY_Session *session);
114
115
116/**
117 * Deinitializing openssl for a specific connection. Should be called
118 * closing session's socket.
119 *
120 * @param session SPDY_Session whose socket is used by openssl
121 */
122void
123SPDYF_tls_close_session(struct SPDY_Session *session);
124
125
126/**
127 * Reading from a TLS socket. Reads available data and put it to the
128 * buffer.
129 *
130 * @param session for which data is received
131 * @param buffer where data from the socket will be written to
132 * @param size of the buffer
133 * @return number of bytes (at most size) read from the TLS connection
134 * 0 if the other party has closed the connection
135 * SPDY_TLS_ERROR code on error
136 */
137int
138SPDYF_tls_recv(struct SPDY_Session *session,
139 void * buffer,
140 size_t size);
141
142
143/**
144 * Writing to a TLS socket. Writes the data given into the buffer to the
145 * TLS socket.
146 *
147 * @param session whose context is used
148 * @param buffer from where data will be written to the socket
149 * @param size number of bytes to be taken from the buffer
150 * @return number of bytes (at most size) from the buffer that has been
151 * written to the TLS connection
152 * 0 if the other party has closed the connection
153 * SPDY_TLS_ERROR code on error
154 */
155int
156SPDYF_tls_send(struct SPDY_Session *session,
157 const void * buffer,
158 size_t size);
159
160
161/**
162 * Checks if there is data staying in the buffers of the underlying
163 * system that waits to be read.
164 *
165 * @param session which is checked
166 * @return SPDY_YES if data is pending or SPDY_NO otherwise
167 */
168int
169SPDYF_tls_is_pending(struct SPDY_Session *session);
170
171#endif
diff --git a/src/spdy2http/Makefile.am b/src/spdy2http/Makefile.am
new file mode 100644
index 00000000..a8f2536f
--- /dev/null
+++ b/src/spdy2http/Makefile.am
@@ -0,0 +1,35 @@
1SUBDIRS = .
2
3AM_CFLAGS = -DDATADIR=\"$(top_srcdir)/src/datadir/\"
4
5if USE_COVERAGE
6 AM_CFLAGS += -fprofile-arcs -ftest-coverage
7endif
8
9if USE_PRIVATE_PLIBC_H
10 PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc
11endif
12
13AM_CPPFLAGS = \
14 $(PLIBC_INCLUDE) \
15 -I$(top_srcdir) \
16 -I$(top_srcdir)/src/include \
17 -I$(top_srcdir)/src/applicationlayer \
18$(LIBCURL_CPPFLAGS)
19
20if !HAVE_W32
21PERF_GET_CONCURRENT=perf_get_concurrent
22endif
23
24bin_PROGRAMS = \
25 microspdy2http
26
27microspdy2http_SOURCES = \
28 proxy.c
29microspdy2http_LDADD = \
30 $(top_builddir)/src/microspdy/libmicrospdy.la \
31 -lssl \
32 -lcrypto \
33 -lz \
34 -ldl \
35 -lcurl
diff --git a/src/spdy2http/proxy.c b/src/spdy2http/proxy.c
new file mode 100644
index 00000000..f1513680
--- /dev/null
+++ b/src/spdy2http/proxy.c
@@ -0,0 +1,625 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file proxy.c
21 * @brief Translates incoming SPDY requests to http server on localhost.
22 * Uses libcurl.
23 * @author Andrey Uzunov
24 */
25
26#include "platform.h"
27#include <unistd.h>
28#include <stdlib.h>
29#include <stdint.h>
30#include <stdbool.h>
31#include <string.h>
32#include <stdio.h>
33#include <ctype.h>
34#include <errno.h>
35#include "microspdy.h"
36#include <curl/curl.h>
37#include <assert.h>
38
39
40#define PRINT_INFO(msg) do{\
41 printf("%i:%s\n", __LINE__, msg);\
42 fflush(stdout);\
43 }\
44 while(0)
45
46
47#define PRINT_INFO2(fmt, ...) do{\
48 printf("%i\n", __LINE__);\
49 printf(fmt,##__VA_ARGS__);\
50 printf("\n");\
51 fflush(stdout);\
52 }\
53 while(0)
54
55
56#define CURL_SETOPT(handle, opt, val) do{\
57 int ret; \
58 if(CURLE_OK != (ret = curl_easy_setopt(handle, opt, val))) \
59 { \
60 PRINT_INFO2("curl_easy_setopt failed (%i = %i)", opt, ret); \
61 abort(); \
62 } \
63 }\
64 while(0)
65
66
67int run = 1;
68char* http_host;
69CURLM *multi_handle;
70int still_running = 0; /* keep number of running handles */
71int http10=0;
72
73struct Proxy
74{
75 char *path;
76 struct SPDY_Request *request;
77 struct SPDY_Response *response;
78 CURL *curl_handle;
79 struct curl_slist *curl_headers;
80 struct SPDY_NameValue *headers;
81 char *version;
82 char *status_msg;
83 void *http_body;
84 size_t http_body_size;
85 ssize_t length;
86 int status;
87};
88
89
90ssize_t
91response_callback (void *cls,
92 void *buffer,
93 size_t max,
94 bool *more)
95{
96 int ret;
97 struct Proxy *proxy = (struct Proxy *)cls;
98 void *newbody;
99
100 //printf("response_callback\n");
101
102 assert(0 != proxy->length);
103
104 *more = true;
105 if(!proxy->http_body_size)//nothing to write now
106 return 0;
107
108 if(max >= proxy->http_body_size)
109 {
110 ret = proxy->http_body_size;
111 newbody = NULL;
112 }
113 else
114 {
115 ret = max;
116 if(NULL == (newbody = malloc(proxy->http_body_size - max)))
117 {
118 PRINT_INFO("no memory");
119 return -1;
120 }
121 memcpy(newbody, proxy->http_body + max, proxy->http_body_size - max);
122 }
123 memcpy(buffer, proxy->http_body, ret);
124 free(proxy->http_body);
125 proxy->http_body = newbody;
126 proxy->http_body_size -= ret;
127
128 if(proxy->length >= 0)
129 {
130 proxy->length -= ret;
131 //printf("pr len %i", proxy->length);
132 if(proxy->length <= 0)
133 {
134 *more = false;
135 //last frame
136 proxy->length = 0;
137 }
138 }
139
140 return ret;
141}
142
143
144void
145response_done_callback(void *cls,
146 struct SPDY_Response *response,
147 struct SPDY_Request *request,
148 enum SPDY_RESPONSE_RESULT status,
149 bool streamopened)
150{
151 (void)streamopened;
152 struct Proxy *proxy = (struct Proxy *)cls;
153 int ret;
154
155 //printf("response_done_callback\n");
156
157 //printf("answer for %s was sent\n", (char *)cls);
158
159 if(SPDY_RESPONSE_RESULT_SUCCESS != status)
160 {
161 printf("answer was NOT sent, %i\n",status);
162 }
163 if(CURLM_OK != (ret = curl_multi_remove_handle(multi_handle, proxy->curl_handle)))
164 {
165 PRINT_INFO2("curl_multi_remove_handle failed (%i)", ret);
166 }
167 curl_slist_free_all(proxy->curl_headers);
168 curl_easy_cleanup(proxy->curl_handle);
169
170 SPDY_destroy_request(request);
171 SPDY_destroy_response(response);
172 if(!strcmp("/close",proxy->path)) run = 0;
173 free(proxy->path);
174 free(proxy);
175}
176
177
178static size_t
179curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp)
180{
181 size_t realsize = size * nmemb;
182 struct Proxy *proxy = (struct Proxy *)userp;
183 char *line = (char *)ptr;
184 char *name;
185 char *value;
186 char *status;
187 const char *const*length;
188 int i;
189 int pos;
190
191 //printf("curl_header_cb\n");
192
193 if('\r' == line[0])
194 {
195 //all headers were already handled; prepare spdy frames
196 if(NULL == (proxy->response = SPDY_build_response_with_callback(proxy->status,
197 proxy->status_msg,
198 proxy->version,
199 proxy->headers,
200 &response_callback,
201 proxy,
202 0)))
203 {
204 PRINT_INFO("no response");
205 abort();
206 }
207 if(NULL != (length = SPDY_name_value_lookup(proxy->headers,
208 SPDY_HTTP_HEADER_CONTENT_LENGTH,
209 &i)))
210 proxy->length = atoi(length[0]);
211 else
212 proxy->length = -1;
213 SPDY_name_value_destroy(proxy->headers);
214 free(proxy->status_msg);
215 free(proxy->version);
216
217 if(SPDY_YES != SPDY_queue_response(proxy->request,
218 proxy->response,
219 true,
220 false,
221 &response_done_callback,
222 proxy))
223 {
224 PRINT_INFO("no queue");
225 abort();
226 }
227 //printf("spdy headers queued %i\n");
228
229 return realsize;
230 }
231
232 pos = 0;
233 if(NULL == proxy->version)
234 {
235 //first line from headers
236 //version
237 for(i=pos; i<realsize && ' '!=line[i]; ++i);
238 if(i == realsize)
239 {
240 PRINT_INFO("error on parsing headers");
241 abort();
242 }
243 if(NULL == (proxy->version = strndup(line, i - pos)))
244 {
245 PRINT_INFO("no memory");
246 abort();
247 }
248 pos = i+1;
249
250 //status (number)
251 for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i]; ++i);
252 if(NULL == (status = strndup(&(line[pos]), i - pos)))
253 {
254 PRINT_INFO("no memory");
255 abort();
256 }
257 proxy->status = atoi(status);
258 free(status);
259 if(i<realsize && '\r'!=line[i])
260 {
261 //status (message)
262 pos = i+1;
263 for(i=pos; i<realsize && '\r'!=line[i]; ++i);
264 if(NULL == (proxy->status_msg = strndup(&(line[pos]), i - pos)))
265 {
266 PRINT_INFO("no memory");
267 abort();
268 }
269 }
270 return realsize;
271 }
272
273 //other lines
274 //header name
275 for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i]; ++i)
276 line[i] = tolower(line[i]); //spdy requires lower case
277 if(NULL == (name = strndup(line, i - pos)))
278 {
279 PRINT_INFO("no memory");
280 abort();
281 }
282 if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name)
283 || 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name))
284 {
285 //forbidden in spdy, ignore
286 free(name);
287 return realsize;
288 }
289 if(i == realsize || '\r'==line[i])
290 {
291 //no value. is it possible?
292 if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, ""))
293 {
294 PRINT_INFO("SPDY_name_value_add failed");
295 abort();
296 }
297 return realsize;
298 }
299
300 //header value
301 pos = i+1;
302 while(pos<realsize && isspace(line[pos])) ++pos; //remove leading space
303 for(i=pos; i<realsize && '\r'!=line[i]; ++i);
304 if(NULL == (value = strndup(&(line[pos]), i - pos)))
305 {
306 PRINT_INFO("no memory");
307 abort();
308 }
309 if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, value))
310 {
311 PRINT_INFO("SPDY_name_value_add failed");
312 abort();
313 }
314 free(name);
315 free(value);
316
317 return realsize;
318}
319
320
321static size_t
322curl_write_cb(void *contents, size_t size, size_t nmemb, void *userp)
323{
324 size_t realsize = size * nmemb;
325 struct Proxy *proxy = (struct Proxy *)userp;
326
327 //printf("curl_write_cb %i\n", realsize);
328
329 if(NULL == proxy->http_body)
330 proxy->http_body = malloc(realsize);
331 else
332 proxy->http_body = realloc(proxy->http_body, proxy->http_body_size + realsize);
333 if(NULL == proxy->http_body)
334 {
335 PRINT_INFO("not enough memory (realloc returned NULL)");
336 return 0;
337 }
338
339 memcpy(proxy->http_body + proxy->http_body_size, contents, realsize);
340 proxy->http_body_size += realsize;
341
342 return realsize;
343}
344
345
346int
347iterate_cb (void *cls, const char *name, const char * const * value, int num_values)
348{
349 struct Proxy *proxy = (struct Proxy *)cls;
350 struct curl_slist **curl_headers = (&(proxy->curl_headers));
351 char *line;
352 int line_len = strlen(name) + 3; //+ ": \0"
353 int i;
354
355 for(i=0; i<num_values; ++i)
356 {
357 if(i) line_len += 2; //", "
358 line_len += strlen(value[i]);
359 }
360
361 if(NULL == (line = malloc(line_len)))
362 {
363 //no recovory
364 PRINT_INFO("no memory");
365 abort();
366 }
367 line[0] = 0;
368
369 strcat(line, name);
370 strcat(line, ": ");
371 //all spdy header names are lower case;
372 //for simplicity here we just capitalize the first letter
373 line[0] = toupper(line[0]);
374
375 for(i=0; i<num_values; ++i)
376 {
377 if(i) strcat(line, ", ");
378 strcat(line, value[i]);
379 }
380 if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line)))
381 {
382 PRINT_INFO("curl_slist_append failed");
383 abort();
384 }
385 free(line);
386
387 return SPDY_YES;
388}
389
390
391void
392standard_request_handler(void *cls,
393 struct SPDY_Request * request,
394 uint8_t priority,
395 const char *method,
396 const char *path,
397 const char *version,
398 const char *host,
399 const char *scheme,
400 struct SPDY_NameValue * headers)
401{
402 (void)cls;
403 (void)priority;
404 (void)host;
405 (void)scheme;
406
407 char *url;
408 struct Proxy *proxy;
409 int ret;
410
411 //printf("received request for '%s %s %s'\n", method, path, version);
412 if(NULL == (proxy = malloc(sizeof(struct Proxy))))
413 {
414 PRINT_INFO("No memory");
415 abort();
416 }
417 memset(proxy, 0, sizeof(struct Proxy));
418 proxy->request = request;
419 if(NULL == (proxy->headers = SPDY_name_value_create()))
420 {
421 PRINT_INFO("No memory");
422 abort();
423 }
424
425 if(-1 == asprintf(&url,"%s%s%s","http://", http_host, path))
426 {
427 PRINT_INFO("No memory");
428 abort();
429 }
430
431 if(NULL == (proxy->path = strdup(path)))
432 {
433 PRINT_INFO("No memory");
434 abort();
435 }
436
437 SPDY_name_value_iterate(headers, &iterate_cb, proxy);
438
439 if(NULL == (proxy->curl_handle = curl_easy_init()))
440 {
441 PRINT_INFO("curl_easy_init failed");
442 abort();
443 }
444
445 //CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1);
446 CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, url);
447 free(url);
448 if(http10)
449 CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
450 CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
451 CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy);
452 CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERFUNCTION, curl_header_cb);
453 CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERDATA, proxy);
454 CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTPHEADER, proxy->curl_headers);
455 CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
456 CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
457
458 if(CURLM_OK != (ret = curl_multi_add_handle(multi_handle, proxy->curl_handle)))
459 {
460 PRINT_INFO2("curl_multi_add_handle failed (%i)", ret);
461 abort();
462 }
463
464 if(CURLM_OK != (ret = curl_multi_perform(multi_handle, &still_running))
465 && CURLM_CALL_MULTI_PERFORM != ret)
466 {
467 PRINT_INFO2("curl_multi_perform failed (%i)", ret);
468 abort();
469 }
470}
471
472int
473main (int argc, char *const *argv)
474{
475 unsigned long long timeoutlong=0;
476 long curl_timeo = -1;
477 struct timeval timeout;
478 int ret;
479 fd_set rs;
480 fd_set ws;
481 fd_set es;
482 fd_set curl_rs;
483 fd_set curl_ws;
484 fd_set curl_es;
485 int maxfd = -1;
486 struct SPDY_Daemon *daemon;
487
488 //signal(SIGPIPE, SIG_IGN);
489
490 if(argc != 6)
491 {
492 printf("Usage: %s cert-file key-file host port http/1.0(yes/no)\n", argv[0]);
493 return 1;
494 }
495
496 SPDY_init();
497
498 daemon = SPDY_start_daemon(atoi(argv[4]),
499 argv[1],
500 argv[2],
501 NULL,
502 NULL,
503 &standard_request_handler,
504 NULL,
505 NULL,
506 SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
507 1800,
508 SPDY_DAEMON_OPTION_END);
509
510 if(NULL==daemon){
511 printf("no daemon\n");
512 return 1;
513 }
514
515 multi_handle = curl_multi_init();
516
517 if(NULL==multi_handle){
518 PRINT_INFO("no multi_handle");
519 abort();
520 }
521
522 if(!strcmp("yes", argv[5]))
523 http10 = 1;
524
525 http_host = argv[3];
526 timeout.tv_usec = 0;
527
528 do
529 {
530 //printf("still %i\n", still_running);
531 FD_ZERO(&rs);
532 FD_ZERO(&ws);
533 FD_ZERO(&es);
534 FD_ZERO(&curl_rs);
535 FD_ZERO(&curl_ws);
536 FD_ZERO(&curl_es);
537
538 if(still_running > 0)
539 timeout.tv_sec = 0; //return immediately
540 else
541 {
542 ret = SPDY_get_timeout(daemon, &timeoutlong);
543 if(SPDY_NO == ret)
544 timeout.tv_sec = 1;
545 else
546 timeout.tv_sec = timeoutlong;
547 }
548 timeout.tv_usec = 0;
549
550 maxfd = SPDY_get_fdset (daemon,
551 &rs,
552 &ws,
553 &es);
554 assert(-1 != maxfd);
555
556 ret = select(maxfd+1, &rs, &ws, &es, &timeout);
557
558 switch(ret) {
559 case -1:
560 PRINT_INFO2("select error: %i", errno);
561 break;
562 case 0:
563 break;
564 default:
565 SPDY_run(daemon);
566 break;
567 }
568
569 timeout.tv_sec = 0;
570 if(still_running > 0)
571 {
572 if(CURLM_OK != (ret = curl_multi_timeout(multi_handle, &curl_timeo)))
573 {
574 PRINT_INFO2("curl_multi_timeout failed (%i)", ret);
575 abort();
576 }
577 if(curl_timeo >= 0 && curl_timeo < 500)
578 timeout.tv_usec = curl_timeo * 1000;
579 else
580 timeout.tv_usec = 500000;
581 }
582 else continue;
583 //else timeout.tv_usec = 500000;
584
585 if(CURLM_OK != (ret = curl_multi_fdset(multi_handle, &curl_rs, &curl_ws, &curl_es, &maxfd)))
586 {
587 PRINT_INFO2("curl_multi_fdset failed (%i)", ret);
588 abort();
589 }
590 if(-1 == maxfd)
591 {
592 PRINT_INFO("maxfd is -1");
593 //continue;
594 ret = 0;
595 }
596 else
597 ret = select(maxfd+1, &curl_rs, &curl_ws, &curl_es, &timeout);
598
599 switch(ret) {
600 case -1:
601 PRINT_INFO2("select error: %i", errno);
602 break;
603 case 0: /* timeout */
604 //break or not
605 default: /* action */
606 if(CURLM_OK != (ret = curl_multi_perform(multi_handle, &still_running))
607 && CURLM_CALL_MULTI_PERFORM != ret)
608 {
609 PRINT_INFO2("curl_multi_perform failed (%i)", ret);
610 abort();
611 }
612 break;
613 }
614 }
615 while(run);
616
617 curl_multi_cleanup(multi_handle);
618
619 SPDY_stop_daemon(daemon);
620
621 SPDY_deinit();
622
623 return 0;
624}
625