[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r27030 - in libmicrohttpd: . doc m4 src src/datadir src/exa
From: |
gnunet |
Subject: |
[GNUnet-SVN] r27030 - in libmicrohttpd: . doc m4 src src/datadir src/examples src/include src/microspdy src/spdy2http |
Date: |
Sun, 5 May 2013 21:21:40 +0200 |
Author: grothoff
Date: 2013-05-05 21:21:40 +0200 (Sun, 05 May 2013)
New Revision: 27030
Added:
libmicrohttpd/doc/spdy-draft.txt
libmicrohttpd/libmicrospdy.pc.in
libmicrohttpd/m4/openssl.m4
libmicrohttpd/src/datadir/
libmicrohttpd/src/datadir/cert-and-key-for-wireshark.pem
libmicrohttpd/src/datadir/cert-and-key.pem
libmicrohttpd/src/examples/spdy_event_loop.c
libmicrohttpd/src/examples/spdy_fileserver.c
libmicrohttpd/src/examples/spdy_response_with_callback.c
libmicrohttpd/src/include/microspdy.h
libmicrohttpd/src/microspdy/
libmicrohttpd/src/microspdy/EXPORT.sym
libmicrohttpd/src/microspdy/Makefile.am
libmicrohttpd/src/microspdy/alstructures.c
libmicrohttpd/src/microspdy/alstructures.h
libmicrohttpd/src/microspdy/applicationlayer.c
libmicrohttpd/src/microspdy/applicationlayer.h
libmicrohttpd/src/microspdy/compression.c
libmicrohttpd/src/microspdy/compression.h
libmicrohttpd/src/microspdy/daemon.c
libmicrohttpd/src/microspdy/daemon.h
libmicrohttpd/src/microspdy/internal.c
libmicrohttpd/src/microspdy/internal.h
libmicrohttpd/src/microspdy/session.c
libmicrohttpd/src/microspdy/session.h
libmicrohttpd/src/microspdy/stream.c
libmicrohttpd/src/microspdy/stream.h
libmicrohttpd/src/microspdy/structures.c
libmicrohttpd/src/microspdy/structures.h
libmicrohttpd/src/microspdy/tls.c
libmicrohttpd/src/microspdy/tls.h
libmicrohttpd/src/spdy2http/
libmicrohttpd/src/spdy2http/Makefile.am
libmicrohttpd/src/spdy2http/proxy.c
Modified:
libmicrohttpd/AUTHORS
libmicrohttpd/Makefile.am
libmicrohttpd/README
libmicrohttpd/configure.ac
libmicrohttpd/doc/Makefile.am
libmicrohttpd/src/Makefile.am
libmicrohttpd/src/examples/Makefile.am
libmicrohttpd/src/include/Makefile.am
Log:
merging libmicrospdy into tree
Modified: libmicrohttpd/AUTHORS
===================================================================
--- libmicrohttpd/AUTHORS 2013-05-05 18:48:18 UTC (rev 27029)
+++ libmicrohttpd/AUTHORS 2013-05-05 19:21:40 UTC (rev 27030)
@@ -1,5 +1,6 @@
Primary developers:
Christian Grothoff <address@hidden> (maintainer)
+Andrey Uzunov <address@hidden> (maintainer for libmicrospdy)
Nils Durner <address@hidden> (W32 port)
Sagie Amir (TLS/SSL support using GNUtls)
Richard Alimi <address@hidden> (performance)
Modified: libmicrohttpd/Makefile.am
===================================================================
--- libmicrohttpd/Makefile.am 2013-05-05 18:48:18 UTC (rev 27029)
+++ libmicrohttpd/Makefile.am 2013-05-05 19:21:40 UTC (rev 27030)
@@ -1,6 +1,6 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = contrib src doc m4 .
-EXTRA_DIST = acinclude.m4 libmicrohttpd.pc.in
+EXTRA_DIST = acinclude.m4 libmicrohttpd.pc.in libmicrospdy.pc.in
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmicrohttpd.pc
Modified: libmicrohttpd/README
===================================================================
--- libmicrohttpd/README 2013-05-05 18:48:18 UTC (rev 27029)
+++ libmicrohttpd/README 2013-05-05 19:21:40 UTC (rev 27030)
@@ -7,7 +7,12 @@
protocol. The main application must still provide the application
logic to generate the content.
+Additionally, a second, still very experimental library is provided
+for SPDY/HTTP 2.0 support. libmicrospdy provides a compact API and
+implementation of SPDY server. libmicrospdy currently only implements
+version 3 of SPDY and accepts only TLS connections.
+
Installation
============
@@ -20,6 +25,21 @@
error messages.
+Requirements for libmicrospdy
+=============================
+
+The following packages are needed to build libmicrospdy:
+
+* zlib
+* OpenSSL >= 1.0.1
+
+To run the test cases, involving requests, version of Spdylay, supporting
+SPDY v3, is required. Spdylay is still under development and can be
+found here:
+
+http://spdylay.sourceforge.net/
+
+
Configure options
=================
@@ -53,58 +73,93 @@
after you are done using MHD.
-Notes on compiling on z/OS:
----------------------------
-
-After extracting the archive, run
-
-iconv -f UTF-8 -t IBM-1047 contrib/ascebc > /tmp/ascebc.sh
-chmod +x /tmp/ascebc.sh
-for n in `find * -type f`
-do
- /tmp/ascebc.sh $n
-done
-
-to convert all source files to EBCDIC. Note that you must run
-"configure" from the directory where the configure script is
-located. Otherwise, configure will fail to find the
-"contrib/xcc" script (which is a wrapper around the z/OS c89
-compiler).
-
-
Development Status
==================
-This is a beta release. Below we list things that should be
-implemented (in order of importance) before we can claim to be
-reasonably complete.
+This is a beta release for libmicrohttpd. Before declaring the
+library stable, we should implement support for HTTP "Upgrade"
+requests and have testcases for the following features:
-
-Untested features:
-==================
-- add testcases for http/1.1 pipelining (need
- to figure out how to ensure curl pipelines
+- HTTP/1.1 pipelining (need to figure out how to ensure curl pipelines
-- and it seems libcurl has issues with pipelining,
see http://curl.haxx.se/mail/lib-2007-12/0248.html)
-- add testcases for resource limit enforcement
-- add testcases for client queuing early response,
- suppressing 100 CONTINUE
-- extend testcase for chunked encoding to validate
- handling of footers
+- resource limit enforcement
+- client queuing early response, suppressing 100 CONTINUE
+- chunked encoding to validate handling of footers
- more testing for SSL support
- MHD basic and digest authentication
-
-Functions not covered by "make check":
-======================================
+In particular, the following functions are not covered by 'make check':
- mhd_panic_std (daemon.c); special case (abort)
- parse_options (daemon.c)
- MHD_set_panic_func (daemon.c)
- MHD_get_version (daemon.c)
+This is an early alpha release for libmicrospdy. The following things
+should be implemented (in order of importance) before we can claim to
+be reasonably complete:
+- Change session timeout to use not seconds but something more precise
+- SPDY RST_STREAM sending on each possible error (DONE?)
+- SPDY_close_session
+- Find the best way for closing still opened stream (new call or existing)
+- SPDY_is_stream_opened
+- SPDY PING (used often by browsers)
+- SPDY WINDOW_UPDATE - used often by browsers
+- SPDY Settings
+- SPDY PUSH
+- SPDY HEADERS
+- HTTP POST over SPDY and receiving DATA frames
+- HTTP PUT over SPDY
+- SPDY Credentials
+
+Additional ideas for features include:
+- Individual callbacks for each session
+- Individual timeout for each session
+- Setting number of frames that can be written to the output at once.
+ A big number means faster sending of a big resource, but the other
+ sessions will wait longer.
+
+Unimplemented API functions of libmicrospdy:
+- SPDY_settings_create ();
+- SPDY_settings_add (...);
+- SPDY_settings_lookup (...);
+- SPDY_settings_iterate (...);
+- SPDY_settings_destroy (...);
+- SPDY_close_session(...);
+- SPDY_send_ping(...);
+- SPDY_send_settings (...);
+
+In particular, we should write tests for:
+- Enqueueing responses while considering request priorities.
+
+
+
+
+
Missing documentation:
======================
-- manual:
+- libmicrohttpd manual:
* document details on porting MHD (plibc, z/OS)
+- libmicrospdy manual:
+ * missing entirely
+
+
+Notes on compiling on z/OS:
+===========================
+
+After extracting the archive, run
+
+iconv -f UTF-8 -t IBM-1047 contrib/ascebc > /tmp/ascebc.sh
+chmod +x /tmp/ascebc.sh
+for n in `find * -type f`
+do
+ /tmp/ascebc.sh $n
+done
+
+to convert all source files to EBCDIC. Note that you must run
+"configure" from the directory where the configure script is
+located. Otherwise, configure will fail to find the
+"contrib/xcc" script (which is a wrapper around the z/OS c89
+compiler).
Modified: libmicrohttpd/configure.ac
===================================================================
--- libmicrohttpd/configure.ac 2013-05-05 18:48:18 UTC (rev 27029)
+++ libmicrohttpd/configure.ac 2013-05-05 19:21:40 UTC (rev 27030)
@@ -34,6 +34,14 @@
AC_SUBST(LIB_VERSION_REVISION)
AC_SUBST(LIB_VERSION_AGE)
+LIBSPDY_VERSION_CURRENT=0
+LIBSPDY_VERSION_REVISION=0
+LIBSPDY_VERSION_AGE=0
+AC_SUBST(LIBSPDY_VERSION_CURRENT)
+AC_SUBST(LIBSPDY_VERSION_REVISION)
+AC_SUBST(LIBSPDY_VERSION_AGE)
+
+
if test `uname -s` = "OS/390"
then
# configure binaries for z/OS
@@ -263,6 +271,39 @@
AM_CONDITIONAL(HAVE_MAGIC, false))],
AM_CONDITIONAL(HAVE_MAGIC, false))
+
+# optional: libmicrospdy support. Enabled by default
+AC_MSG_CHECKING(whether to support libmicrospdy)
+AC_ARG_ENABLE([spdy],
+ AS_HELP_STRING([--disable-spdy],
+ [disable libmicrospdy]),
+ [enable_spdy=${enableval}],
+ [enable_spdy=yes])
+if test "$enable_spdy" = "yes"
+then
+ AC_DEFINE([SPDY_SUPPORT],[1],[include libmicrospdy support])
+else
+ AC_DEFINE([SPDY_SUPPORT],[0],[disable libmicrospdy support])
+fi
+AC_MSG_RESULT($enable_spdy)
+AM_CONDITIONAL(ENABLE_SPDY, [test "x$enable_spdy" != "xno"])
+
+spdy_OPENSSL
+# for pkg-config
+SPDY_LIBDEPS=""
+
+
+AC_SUBST(SPDY_LIB_LDFLAGS)
+# for pkg-config
+AC_SUBST(SPDY_LIBDEPS)
+
+AM_CONDITIONAL(ENABLE_MINITASN1, [test -n " " ] )
+AM_CONDITIONAL(ENABLE_OPENSSL, [test -n "" ] )
+AM_CONDITIONAL(HAVE_LD_OUTPUT_DEF, [test -n "" ] )
+AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, [test -n "" ] )
+
+
+
LIBS=$SAVE_LIBS
AM_CONDITIONAL(HAVE_CURL, test x$curl = x1)
@@ -450,9 +491,12 @@
src/include/Makefile
src/include/plibc/Makefile
src/microhttpd/Makefile
+src/microspdy/Makefile
+src/spdy2http/Makefile
src/examples/Makefile
src/testcurl/Makefile
src/testcurl/https/Makefile
+src/testspdy/Makefile
src/testzzuf/Makefile])
AC_OUTPUT
Modified: libmicrohttpd/doc/Makefile.am
===================================================================
--- libmicrohttpd/doc/Makefile.am 2013-05-05 18:48:18 UTC (rev 27029)
+++ libmicrohttpd/doc/Makefile.am 2013-05-05 19:21:40 UTC (rev 27030)
@@ -25,4 +25,5 @@
lgpl.texi \
ecos.texi
-EXTRA_DIST = $(man_MANS) Doxyfile $(microhttpd_TEXINFOS)
+EXTRA_DIST = $(man_MANS) Doxyfile $(microhttpd_TEXINFOS) spdy-draft.txt
+
Added: libmicrohttpd/doc/spdy-draft.txt
===================================================================
--- libmicrohttpd/doc/spdy-draft.txt (rev 0)
+++ libmicrohttpd/doc/spdy-draft.txt 2013-05-05 19:21:40 UTC (rev 27030)
@@ -0,0 +1,2856 @@
+
+
+
+Network Working Group M. Belshe
+Internet-Draft Twist
+Expires: August 4, 2012 R. Peon
+ Google, Inc
+ Feb 2012
+
+
+ SPDY Protocol
+ draft-mbelshe-httpbis-spdy-00
+
+Abstract
+
+ This document describes SPDY, a protocol designed for low-latency
+ transport of content over the World Wide Web. SPDY introduces two
+ layers of protocol. The lower layer is a general purpose framing
+ layer which can be used atop a reliable transport (likely TCP) for
+ multiplexed, prioritized, and compressed data communication of many
+ concurrent streams. The upper layer of the protocol provides HTTP-
+ like RFC2616 [RFC2616] semantics for compatibility with existing HTTP
+ application servers.
+
+Status of this Memo
+
+ This Internet-Draft is submitted in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF). Note that other groups may also distribute
+ working documents as Internet-Drafts. The list of current Internet-
+ Drafts is at http://datatracker.ietf.org/drafts/current/.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ This Internet-Draft will expire on August 4, 2012.
+
+Copyright Notice
+
+ Copyright (c) 2012 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 1]
+
+Internet-Draft SPDY Feb 2012
+
+
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+
+Table of Contents
+
+ 1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.1. Document Organization . . . . . . . . . . . . . . . . . . 4
+ 1.2. Definitions . . . . . . . . . . . . . . . . . . . . . . . 5
+ 2. SPDY Framing Layer . . . . . . . . . . . . . . . . . . . . . . 6
+ 2.1. Session (Connections) . . . . . . . . . . . . . . . . . . 6
+ 2.2. Framing . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 2.2.1. Control frames . . . . . . . . . . . . . . . . . . . . 6
+ 2.2.2. Data frames . . . . . . . . . . . . . . . . . . . . . 7
+ 2.3. Streams . . . . . . . . . . . . . . . . . . . . . . . . . 8
+ 2.3.1. Stream frames . . . . . . . . . . . . . . . . . . . . 9
+ 2.3.2. Stream creation . . . . . . . . . . . . . . . . . . . 9
+ 2.3.3. Stream priority . . . . . . . . . . . . . . . . . . . 10
+ 2.3.4. Stream headers . . . . . . . . . . . . . . . . . . . . 10
+ 2.3.5. Stream data exchange . . . . . . . . . . . . . . . . . 10
+ 2.3.6. Stream half-close . . . . . . . . . . . . . . . . . . 10
+ 2.3.7. Stream close . . . . . . . . . . . . . . . . . . . . . 11
+ 2.4. Error Handling . . . . . . . . . . . . . . . . . . . . . . 11
+ 2.4.1. Session Error Handling . . . . . . . . . . . . . . . . 11
+ 2.4.2. Stream Error Handling . . . . . . . . . . . . . . . . 12
+ 2.5. Data flow . . . . . . . . . . . . . . . . . . . . . . . . 12
+ 2.6. Control frame types . . . . . . . . . . . . . . . . . . . 12
+ 2.6.1. SYN_STREAM . . . . . . . . . . . . . . . . . . . . . . 12
+ 2.6.2. SYN_REPLY . . . . . . . . . . . . . . . . . . . . . . 14
+ 2.6.3. RST_STREAM . . . . . . . . . . . . . . . . . . . . . . 15
+ 2.6.4. SETTINGS . . . . . . . . . . . . . . . . . . . . . . . 16
+ 2.6.5. PING . . . . . . . . . . . . . . . . . . . . . . . . . 19
+ 2.6.6. GOAWAY . . . . . . . . . . . . . . . . . . . . . . . . 20
+ 2.6.7. HEADERS . . . . . . . . . . . . . . . . . . . . . . . 21
+ 2.6.8. WINDOW_UPDATE . . . . . . . . . . . . . . . . . . . . 22
+ 2.6.9. CREDENTIAL . . . . . . . . . . . . . . . . . . . . . . 24
+ 2.6.10. Name/Value Header Block . . . . . . . . . . . . . . . 26
+ 3. HTTP Layering over SPDY . . . . . . . . . . . . . . . . . . . 33
+ 3.1. Connection Management . . . . . . . . . . . . . . . . . . 33
+ 3.1.1. Use of GOAWAY . . . . . . . . . . . . . . . . . . . . 33
+ 3.2. HTTP Request/Response . . . . . . . . . . . . . . . . . . 34
+ 3.2.1. Request . . . . . . . . . . . . . . . . . . . . . . . 34
+ 3.2.2. Response . . . . . . . . . . . . . . . . . . . . . . . 35
+ 3.2.3. Authentication . . . . . . . . . . . . . . . . . . . . 36
+ 3.3. Server Push Transactions . . . . . . . . . . . . . . . . . 37
+ 3.3.1. Server implementation . . . . . . . . . . . . . . . . 38
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 2]
+
+Internet-Draft SPDY Feb 2012
+
+
+ 3.3.2. Client implementation . . . . . . . . . . . . . . . . 39
+ 4. Design Rationale and Notes . . . . . . . . . . . . . . . . . . 40
+ 4.1. Separation of Framing Layer and Application Layer . . . . 40
+ 4.2. Error handling - Framing Layer . . . . . . . . . . . . . . 40
+ 4.3. One Connection Per Domain . . . . . . . . . . . . . . . . 40
+ 4.4. Fixed vs Variable Length Fields . . . . . . . . . . . . . 41
+ 4.5. Compression Context(s) . . . . . . . . . . . . . . . . . . 41
+ 4.6. Unidirectional streams . . . . . . . . . . . . . . . . . . 42
+ 4.7. Data Compression . . . . . . . . . . . . . . . . . . . . . 42
+ 4.8. Server Push . . . . . . . . . . . . . . . . . . . . . . . 42
+ 5. Security Considerations . . . . . . . . . . . . . . . . . . . 43
+ 5.1. Use of Same-origin constraints . . . . . . . . . . . . . . 43
+ 5.2. HTTP Headers and SPDY Headers . . . . . . . . . . . . . . 43
+ 5.3. Cross-Protocol Attacks . . . . . . . . . . . . . . . . . . 43
+ 5.4. Server Push Implicit Headers . . . . . . . . . . . . . . . 43
+ 6. Privacy Considerations . . . . . . . . . . . . . . . . . . . . 44
+ 6.1. Long Lived Connections . . . . . . . . . . . . . . . . . . 44
+ 6.2. SETTINGS frame . . . . . . . . . . . . . . . . . . . . . . 44
+ 7. Incompatibilities with SPDY draft #2 . . . . . . . . . . . . . 45
+ 8. Requirements Notation . . . . . . . . . . . . . . . . . . . . 46
+ 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 47
+ 10. Normative References . . . . . . . . . . . . . . . . . . . . . 48
+ Appendix A. Changes . . . . . . . . . . . . . . . . . . . . . . . 50
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 51
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 3]
+
+Internet-Draft SPDY Feb 2012
+
+
+1. Overview
+
+ One of the bottlenecks of HTTP implementations is that HTTP relies on
+ multiple connections for concurrency. This causes several problems,
+ including additional round trips for connection setup, slow-start
+ delays, and connection rationing by the client, where it tries to
+ avoid opening too many connections to any single server. HTTP
+ pipelining helps some, but only achieves partial multiplexing. In
+ addition, pipelining has proven non-deployable in existing browsers
+ due to intermediary interference.
+
+ SPDY adds a framing layer for multiplexing multiple, concurrent
+ streams across a single TCP connection (or any reliable transport
+ stream). The framing layer is optimized for HTTP-like request-
+ response streams, such that applications which run over HTTP today
+ can work over SPDY with little or no change on behalf of the web
+ application writer.
+
+ The SPDY session offers four improvements over HTTP:
+
+ Multiplexed requests: There is no limit to the number of requests
+ that can be issued concurrently over a single SPDY connection.
+
+ Prioritized requests: Clients can request certain resources to be
+ delivered first. This avoids the problem of congesting the
+ network channel with non-critical resources when a high-priority
+ request is pending.
+
+ Compressed headers: Clients today send a significant amount of
+ redundant data in the form of HTTP headers. Because a single web
+ page may require 50 or 100 subrequests, this data is significant.
+
+ Server pushed streams: Server Push enables content to be pushed
+ from servers to clients without a request.
+
+ SPDY attempts to preserve the existing semantics of HTTP. All
+ features such as cookies, ETags, Vary headers, Content-Encoding
+ negotiations, etc work as they do with HTTP; SPDY only replaces the
+ way the data is written to the network.
+
+1.1. Document Organization
+
+ The SPDY Specification is split into two parts: a framing layer
+ (Section 2), which multiplexes a TCP connection into independent,
+ length-prefixed frames, and an HTTP layer (Section 3), which
+ specifies the mechanism for overlaying HTTP request/response pairs on
+ top of the framing layer. While some of the framing layer concepts
+ are isolated from the HTTP layer, building a generic framing layer
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 4]
+
+Internet-Draft SPDY Feb 2012
+
+
+ has not been a goal. The framing layer is tailored to the needs of
+ the HTTP protocol and server push.
+
+1.2. Definitions
+
+ client: The endpoint initiating the SPDY session.
+
+ connection: A transport-level connection between two endpoints.
+
+ endpoint: Either the client or server of a connection.
+
+ frame: A header-prefixed sequence of bytes sent over a SPDY
+ session.
+
+ server: The endpoint which did not initiate the SPDY session.
+
+ session: A synonym for a connection.
+
+ session error: An error on the SPDY session.
+
+ stream: A bi-directional flow of bytes across a virtual channel
+ within a SPDY session.
+
+ stream error: An error on an individual SPDY stream.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 5]
+
+Internet-Draft SPDY Feb 2012
+
+
+2. SPDY Framing Layer
+
+2.1. Session (Connections)
+
+ The SPDY framing layer (or "session") runs atop a reliable transport
+ layer such as TCP [RFC0793]. The client is the TCP connection
+ initiator. SPDY connections are persistent connections.
+
+ For best performance, it is expected that clients will not close open
+ connections until the user navigates away from all web pages
+ referencing a connection, or until the server closes the connection.
+ Servers are encouraged to leave connections open for as long as
+ possible, but can terminate idle connections if necessary. When
+ either endpoint closes the transport-level connection, it MUST first
+ send a GOAWAY (Section 2.6.6) frame so that the endpoints can
+ reliably determine if requests finished before the close.
+
+2.2. Framing
+
+ Once the connection is established, clients and servers exchange
+ framed messages. There are two types of frames: control frames
+ (Section 2.2.1) and data frames (Section 2.2.2). Frames always have
+ a common header which is 8 bytes in length.
+
+ The first bit is a control bit indicating whether a frame is a
+ control frame or data frame. Control frames carry a version number,
+ a frame type, flags, and a length. Data frames contain the stream
+ ID, flags, and the length for the payload carried after the common
+ header. The simple header is designed to make reading and writing of
+ frames easy.
+
+ All integer values, including length, version, and type, are in
+ network byte order. SPDY does not enforce alignment of types in
+ dynamically sized frames.
+
+2.2.1. Control frames
+
+ +----------------------------------+
+ |C| Version(15bits) | Type(16bits) |
+ +----------------------------------+
+ | Flags (8) | Length (24 bits) |
+ +----------------------------------+
+ | Data |
+ +----------------------------------+
+
+ Control bit: The 'C' bit is a single bit indicating if this is a
+ control message. For control frames this value is always 1.
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 6]
+
+Internet-Draft SPDY Feb 2012
+
+
+ Version: The version number of the SPDY protocol. This document
+ describes SPDY version 3.
+
+ Type: The type of control frame. See Control Frames for the complete
+ list of control frames.
+
+ Flags: Flags related to this frame. Flags for control frames and
+ data frames are different.
+
+ Length: An unsigned 24-bit value representing the number of bytes
+ after the length field.
+
+ Data: data associated with this control frame. The format and length
+ of this data is controlled by the control frame type.
+
+ Control frame processing requirements:
+
+ Note that full length control frames (16MB) can be large for
+ implementations running on resource-limited hardware. In such
+ cases, implementations MAY limit the maximum length frame
+ supported. However, all implementations MUST be able to receive
+ control frames of at least 8192 octets in length.
+
+2.2.2. Data frames
+
+ +----------------------------------+
+ |C| Stream-ID (31bits) |
+ +----------------------------------+
+ | Flags (8) | Length (24 bits) |
+ +----------------------------------+
+ | Data |
+ +----------------------------------+
+
+ Control bit: For data frames this value is always 0.
+
+ Stream-ID: A 31-bit value identifying the stream.
+
+ Flags: Flags related to this frame. Valid flags are:
+
+ 0x01 = FLAG_FIN - signifies that this frame represents the last
+ frame to be transmitted on this stream. See Stream Close
+ (Section 2.3.7) below.
+
+ 0x02 = FLAG_COMPRESS - indicates that the data in this frame has
+ been compressed.
+
+ Length: An unsigned 24-bit value representing the number of bytes
+ after the length field. The total size of a data frame is 8 bytes +
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 7]
+
+Internet-Draft SPDY Feb 2012
+
+
+ length. It is valid to have a zero-length data frame.
+
+ Data: The variable-length data payload; the length was defined in the
+ length field.
+
+ Data frame processing requirements:
+
+ If an endpoint receives a data frame for a stream-id which is not
+ open and the endpoint has not sent a GOAWAY (Section 2.6.6) frame,
+ it MUST send issue a stream error (Section 2.4.2) with the error
+ code INVALID_STREAM for the stream-id.
+
+ If the endpoint which created the stream receives a data frame
+ before receiving a SYN_REPLY on that stream, it is a protocol
+ error, and the recipient MUST issue a stream error (Section 2.4.2)
+ with the status code PROTOCOL_ERROR for the stream-id.
+
+ Implementors note: If an endpoint receives multiple data frames
+ for invalid stream-ids, it MAY close the session.
+
+ All SPDY endpoints MUST accept compressed data frames.
+ Compression of data frames is always done using zlib compression.
+ Each stream initializes and uses its own compression context
+ dedicated to use within that stream. Endpoints are encouraged to
+ use application level compression rather than SPDY stream level
+ compression.
+
+ Each SPDY stream sending compressed frames creates its own zlib
+ context for that stream, and these compression contexts MUST be
+ distinct from the compression contexts used with SYN_STREAM/
+ SYN_REPLY/HEADER compression. (Thus, if both endpoints of a
+ stream are compressing data on the stream, there will be two zlib
+ contexts, one for sending and one for receiving).
+
+2.3. Streams
+
+ Streams are independent sequences of bi-directional data divided into
+ frames with several properties:
+
+ Streams may be created by either the client or server.
+
+ Streams optionally carry a set of name/value header pairs.
+
+ Streams can concurrently send data interleaved with other streams.
+
+ Streams may be cancelled.
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 8]
+
+Internet-Draft SPDY Feb 2012
+
+
+2.3.1. Stream frames
+
+ SPDY defines 3 control frames to manage the lifecycle of a stream:
+
+ SYN_STREAM - Open a new stream
+
+ SYN_REPLY - Remote acknowledgement of a new, open stream
+
+ RST_STREAM - Close a stream
+
+2.3.2. Stream creation
+
+ A stream is created by sending a control frame with the type set to
+ SYN_STREAM (Section 2.6.1). If the server is initiating the stream,
+ the Stream-ID must be even. If the client is initiating the stream,
+ the Stream-ID must be odd. 0 is not a valid Stream-ID. Stream-IDs
+ from each side of the connection must increase monotonically as new
+ streams are created. E.g. Stream 2 may be created after stream 3,
+ but stream 7 must not be created after stream 9. Stream IDs do not
+ wrap: when a client or server cannot create a new stream id without
+ exceeding a 31 bit value, it MUST NOT create a new stream.
+
+ The stream-id MUST increase with each new stream. If an endpoint
+ receives a SYN_STREAM with a stream id which is less than any
+ previously received SYN_STREAM, it MUST issue a session error
+ (Section 2.4.1) with the status PROTOCOL_ERROR.
+
+ It is a protocol error to send two SYN_STREAMs with the same
+ stream-id. If a recipient receives a second SYN_STREAM for the same
+ stream, it MUST issue a stream error (Section 2.4.2) with the status
+ code PROTOCOL_ERROR.
+
+ Upon receipt of a SYN_STREAM, the recipient can reject the stream by
+ sending a stream error (Section 2.4.2) with the error code
+ REFUSED_STREAM. Note, however, that the creating endpoint may have
+ already sent additional frames for that stream which cannot be
+ immediately stopped.
+
+ Once the stream is created, the creator may immediately send HEADERS
+ or DATA frames for that stream, without needing to wait for the
+ recipient to acknowledge.
+
+2.3.2.1. Unidirectional streams
+
+ When an endpoint creates a stream with the FLAG_UNIDIRECTIONAL flag
+ set, it creates a unidirectional stream which the creating endpoint
+ can use to send frames, but the receiving endpoint cannot. The
+ receiving endpoint is implicitly already in the half-closed
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 9]
+
+Internet-Draft SPDY Feb 2012
+
+
+ (Section 2.3.6) state.
+
+2.3.2.2. Bidirectional streams
+
+ SYN_STREAM frames which do not use the FLAG_UNIDIRECTIONAL flag are
+ bidirectional streams. Both endpoints can send data on a bi-
+ directional stream.
+
+2.3.3. Stream priority
+
+ The creator of a stream assigns a priority for that stream. Priority
+ is represented as an integer from 0 to 7. 0 represents the highest
+ priority and 7 represents the lowest priority.
+
+ The sender and recipient SHOULD use best-effort to process streams in
+ the order of highest priority to lowest priority.
+
+2.3.4. Stream headers
+
+ Streams carry optional sets of name/value pair headers which carry
+ metadata about the stream. After the stream has been created, and as
+ long as the sender is not closed (Section 2.3.7) or half-closed
+ (Section 2.3.6), each side may send HEADERS frame(s) containing the
+ header data. Header data can be sent in multiple HEADERS frames, and
+ HEADERS frames may be interleaved with data frames.
+
+2.3.5. Stream data exchange
+
+ Once a stream is created, it can be used to send arbitrary amounts of
+ data. Generally this means that a series of data frames will be sent
+ on the stream until a frame containing the FLAG_FIN flag is set. The
+ FLAG_FIN can be set on a SYN_STREAM (Section 2.6.1), SYN_REPLY
+ (Section 2.6.2), HEADERS (Section 2.6.7) or a DATA (Section 2.2.2)
+ frame. Once the FLAG_FIN has been sent, the stream is considered to
+ be half-closed.
+
+2.3.6. Stream half-close
+
+ When one side of the stream sends a frame with the FLAG_FIN flag set,
+ the stream is half-closed from that endpoint. The sender of the
+ FLAG_FIN MUST NOT send further frames on that stream. When both
+ sides have half-closed, the stream is closed.
+
+ If an endpoint receives a data frame after the stream is half-closed
+ from the sender (e.g. the endpoint has already received a prior frame
+ for the stream with the FIN flag set), it MUST send a RST_STREAM to
+ the sender with the status STREAM_ALREADY_CLOSED.
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 10]
+
+Internet-Draft SPDY Feb 2012
+
+
+2.3.7. Stream close
+
+ There are 3 ways that streams can be terminated:
+
+ Normal termination: Normal stream termination occurs when both
+ sender and recipient have half-closed the stream by sending a
+ FLAG_FIN.
+
+ Abrupt termination: Either the client or server can send a
+ RST_STREAM control frame at any time. A RST_STREAM contains an
+ error code to indicate the reason for failure. When a RST_STREAM
+ is sent from the stream originator, it indicates a failure to
+ complete the stream and that no further data will be sent on the
+ stream. When a RST_STREAM is sent from the stream recipient, the
+ sender, upon receipt, should stop sending any data on the stream.
+ The stream recipient should be aware that there is a race between
+ data already in transit from the sender and the time the
+ RST_STREAM is received. See Stream Error Handling (Section 2.4.2)
+
+ TCP connection teardown: If the TCP connection is torn down while
+ un-closed streams exist, then the endpoint must assume that the
+ stream was abnormally interrupted and may be incomplete.
+
+ If an endpoint receives a data frame after the stream is closed, it
+ must send a RST_STREAM to the sender with the status PROTOCOL_ERROR.
+
+2.4. Error Handling
+
+ The SPDY framing layer has only two types of errors, and they are
+ always handled consistently. Any reference in this specification to
+ "issue a session error" refers to Section 2.4.1. Any reference to
+ "issue a stream error" refers to Section 2.4.2.
+
+2.4.1. Session Error Handling
+
+ A session error is any error which prevents further processing of the
+ framing layer or which corrupts the session compression state. When
+ a session error occurs, the endpoint encountering the error MUST
+ first send a GOAWAY (Section 2.6.6) frame with the stream id of most
+ recently received stream from the remote endpoint, and the error code
+ for why the session is terminating. After sending the GOAWAY frame,
+ the endpoint MUST close the TCP connection.
+
+ Note that the session compression state is dependent upon both
+ endpoints always processing all compressed data. If an endpoint
+ partially processes a frame containing compressed data without
+ updating compression state properly, future control frames which use
+ compression will be always be errored. Implementations SHOULD always
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 11]
+
+Internet-Draft SPDY Feb 2012
+
+
+ try to process compressed data so that errors which could be handled
+ as stream errors do not become session errors.
+
+ Note that because this GOAWAY is sent during a session error case, it
+ is possible that the GOAWAY will not be reliably received by the
+ receiving endpoint. It is a best-effort attempt to communicate with
+ the remote about why the session is going down.
+
+2.4.2. Stream Error Handling
+
+ A stream error is an error related to a specific stream-id which does
+ not affect processing of other streams at the framing layer. Upon a
+ stream error, the endpoint MUST send a RST_STREAM (Section 2.6.3)
+ frame which contains the stream id of the stream where the error
+ occurred and the error status which caused the error. After sending
+ the RST_STREAM, the stream is closed to the sending endpoint. After
+ sending the RST_STREAM, if the sender receives any frames other than
+ a RST_STREAM for that stream id, it will result in sending additional
+ RST_STREAM frames. An endpoint MUST NOT send a RST_STREAM in
+ response to an RST_STREAM, as doing so would lead to RST_STREAM
+ loops. Sending a RST_STREAM does not cause the SPDY session to be
+ closed.
+
+ If an endpoint has multiple RST_STREAM frames to send in succession
+ for the same stream-id and the same error code, it MAY coalesce them
+ into a single RST_STREAM frame. (This can happen if a stream is
+ closed, but the remote sends multiple data frames. There is no
+ reason to send a RST_STREAM for each frame in succession).
+
+2.5. Data flow
+
+ Because TCP provides a single stream of data on which SPDY
+ multiplexes multiple logical streams, clients and servers must
+ intelligently interleave data messages for concurrent sessions.
+
+2.6. Control frame types
+
+2.6.1. SYN_STREAM
+
+ The SYN_STREAM control frame allows the sender to asynchronously
+ create a stream between the endpoints. See Stream Creation
+ (Section 2.3.2)
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 12]
+
+Internet-Draft SPDY Feb 2012
+
+
++------------------------------------+
+|1| version | 1 |
++------------------------------------+
+| Flags (8) | Length (24 bits) |
++------------------------------------+
+|X| Stream-ID (31bits) |
++------------------------------------+
+|X| Associated-To-Stream-ID (31bits) |
++------------------------------------+
+| Pri|Unused | Slot | |
++-------------------+ |
+| Number of Name/Value pairs (int32) | <+
++------------------------------------+ |
+| Length of name (int32) | | This section is the "Name/Value
++------------------------------------+ | Header Block", and is compressed.
+| Name (string) | |
++------------------------------------+ |
+| Length of value (int32) | |
++------------------------------------+ |
+| Value (string) | |
++------------------------------------+ |
+| (repeats) | <+
+
+ Flags: Flags related to this frame. Valid flags are:
+
+ 0x01 = FLAG_FIN - marks this frame as the last frame to be
+ transmitted on this stream and puts the sender in the half-closed
+ (Section 2.3.6) state.
+
+ 0x02 = FLAG_UNIDIRECTIONAL - a stream created with this flag puts
+ the recipient in the half-closed (Section 2.3.6) state.
+
+ Length: The length is the number of bytes which follow the length
+ field in the frame. For SYN_STREAM frames, this is 10 bytes plus the
+ length of the compressed Name/Value block.
+
+ Stream-ID: The 31-bit identifier for this stream. This stream-id
+ will be used in frames which are part of this stream.
+
+ Associated-To-Stream-ID: The 31-bit identifier for a stream which
+ this stream is associated to. If this stream is independent of all
+ other streams, it should be 0.
+
+ Priority: A 3-bit priority (Section 2.3.3) field.
+
+ Unused: 5 bits of unused space, reserved for future use.
+
+ Slot: An 8 bit unsigned integer specifying the index in the server's
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 13]
+
+Internet-Draft SPDY Feb 2012
+
+
+ CREDENTIAL vector of the client certificate to be used for this
+ request. see CREDENTIAL frame (Section 2.6.9). The value 0 means no
+ client certificate should be associated with this stream.
+
+ Name/Value Header Block: A set of name/value pairs carried as part of
+ the SYN_STREAM. see Name/Value Header Block (Section 2.6.10).
+
+ If an endpoint receives a SYN_STREAM which is larger than the
+ implementation supports, it MAY send a RST_STREAM with error code
+ FRAME_TOO_LARGE. All implementations MUST support the minimum size
+ limits defined in the Control Frames section (Section 2.2.1).
+
+2.6.2. SYN_REPLY
+
+ SYN_REPLY indicates the acceptance of a stream creation by the
+ recipient of a SYN_STREAM frame.
+
++------------------------------------+
+|1| version | 2 |
++------------------------------------+
+| Flags (8) | Length (24 bits) |
++------------------------------------+
+|X| Stream-ID (31bits) |
++------------------------------------+
+| Number of Name/Value pairs (int32) | <+
++------------------------------------+ |
+| Length of name (int32) | | This section is the "Name/Value
++------------------------------------+ | Header Block", and is compressed.
+| Name (string) | |
++------------------------------------+ |
+| Length of value (int32) | |
++------------------------------------+ |
+| Value (string) | |
++------------------------------------+ |
+| (repeats) | <+
+
+ Flags: Flags related to this frame. Valid flags are:
+
+ 0x01 = FLAG_FIN - marks this frame as the last frame to be
+ transmitted on this stream and puts the sender in the half-closed
+ (Section 2.3.6) state.
+
+ Length: The length is the number of bytes which follow the length
+ field in the frame. For SYN_REPLY frames, this is 4 bytes plus the
+ length of the compressed Name/Value block.
+
+ Stream-ID: The 31-bit identifier for this stream.
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 14]
+
+Internet-Draft SPDY Feb 2012
+
+
+ If an endpoint receives multiple SYN_REPLY frames for the same active
+ stream ID, it MUST issue a stream error (Section 2.4.2) with the
+ error code STREAM_IN_USE.
+
+ Name/Value Header Block: A set of name/value pairs carried as part of
+ the SYN_STREAM. see Name/Value Header Block (Section 2.6.10).
+
+ If an endpoint receives a SYN_REPLY which is larger than the
+ implementation supports, it MAY send a RST_STREAM with error code
+ FRAME_TOO_LARGE. All implementations MUST support the minimum size
+ limits defined in the Control Frames section (Section 2.2.1).
+
+2.6.3. RST_STREAM
+
+ The RST_STREAM frame allows for abnormal termination of a stream.
+ When sent by the creator of a stream, it indicates the creator wishes
+ to cancel the stream. When sent by the recipient of a stream, it
+ indicates an error or that the recipient did not want to accept the
+ stream, so the stream should be closed.
+
+ +----------------------------------+
+ |1| version | 3 |
+ +----------------------------------+
+ | Flags (8) | 8 |
+ +----------------------------------+
+ |X| Stream-ID (31bits) |
+ +----------------------------------+
+ | Status code |
+ +----------------------------------+
+
+ Flags: Flags related to this frame. RST_STREAM does not define any
+ flags. This value must be 0.
+
+ Length: An unsigned 24-bit value representing the number of bytes
+ after the length field. For RST_STREAM control frames, this value is
+ always 8.
+
+ Stream-ID: The 31-bit identifier for this stream.
+
+ Status code: (32 bits) An indicator for why the stream is being
+ terminated.The following status codes are defined:
+
+ 1 - PROTOCOL_ERROR. This is a generic error, and should only be
+ used if a more specific error is not available.
+
+ 2 - INVALID_STREAM. This is returned when a frame is received for
+ a stream which is not active.
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 15]
+
+Internet-Draft SPDY Feb 2012
+
+
+ 3 - REFUSED_STREAM. Indicates that the stream was refused before
+ any processing has been done on the stream.
+
+ 4 - UNSUPPORTED_VERSION. Indicates that the recipient of a stream
+ does not support the SPDY version requested.
+
+ 5 - CANCEL. Used by the creator of a stream to indicate that the
+ stream is no longer needed.
+
+ 6 - INTERNAL_ERROR. This is a generic error which can be used
+ when the implementation has internally failed, not due to anything
+ in the protocol.
+
+ 7 - FLOW_CONTROL_ERROR. The endpoint detected that its peer
+ violated the flow control protocol.
+
+ 8 - STREAM_IN_USE. The endpoint received a SYN_REPLY for a stream
+ already open.
+
+ 9 - STREAM_ALREADY_CLOSED. The endpoint received a data or
+ SYN_REPLY frame for a stream which is half closed.
+
+ 10 - INVALID_CREDENTIALS. The server received a request for a
+ resource whose origin does not have valid credentials in the
+ client certificate vector.
+
+ 11 - FRAME_TOO_LARGE. The endpoint received a frame which this
+ implementation could not support. If FRAME_TOO_LARGE is sent for
+ a SYN_STREAM, HEADERS, or SYN_REPLY frame without fully processing
+ the compressed portion of those frames, then the compression state
+ will be out-of-sync with the other endpoint. In this case,
+ senders of FRAME_TOO_LARGE MUST close the session.
+
+ Note: 0 is not a valid status code for a RST_STREAM.
+
+ After receiving a RST_STREAM on a stream, the recipient must not send
+ additional frames for that stream, and the stream moves into the
+ closed state.
+
+2.6.4. SETTINGS
+
+ A SETTINGS frame contains a set of id/value pairs for communicating
+ configuration data about how the two endpoints may communicate.
+ SETTINGS frames can be sent at any time by either endpoint, are
+ optionally sent, and are fully asynchronous. When the server is the
+ sender, the sender can request that configuration data be persisted
+ by the client across SPDY sessions and returned to the server in
+ future communications.
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 16]
+
+Internet-Draft SPDY Feb 2012
+
+
+ Persistence of SETTINGS ID/Value pairs is done on a per origin/IP
+ pair (the "origin" is the set of scheme, host, and port from the URI.
+ See [RFC6454]). That is, when a client connects to a server, and the
+ server persists settings within the client, the client SHOULD return
+ the persisted settings on future connections to the same origin AND
+ IP address and TCP port. Clients MUST NOT request servers to use the
+ persistence features of the SETTINGS frames, and servers MUST ignore
+ persistence related flags sent by a client.
+
+ +----------------------------------+
+ |1| version | 4 |
+ +----------------------------------+
+ | Flags (8) | Length (24 bits) |
+ +----------------------------------+
+ | Number of entries |
+ +----------------------------------+
+ | ID/Value Pairs |
+ | ... |
+
+ Control bit: The control bit is always 1 for this message.
+
+ Version: The SPDY version number.
+
+ Type: The message type for a SETTINGS message is 4.
+
+ Flags: FLAG_SETTINGS_CLEAR_SETTINGS (0x1): When set, the client
+ should clear any previously persisted SETTINGS ID/Value pairs. If
+ this frame contains ID/Value pairs with the
+ FLAG_SETTINGS_PERSIST_VALUE set, then the client will first clear its
+ existing, persisted settings, and then persist the values with the
+ flag set which are contained within this frame. Because persistence
+ is only implemented on the client, this flag can only be used when
+ the sender is the server.
+
+ Length: An unsigned 24-bit value representing the number of bytes
+ after the length field. The total size of a SETTINGS frame is 8
+ bytes + length.
+
+ Number of entries: A 32-bit value representing the number of ID/value
+ pairs in this message.
+
+ ID: A 32-bit ID number, comprised of 8 bits of flags and 24 bits of
+ unique ID.
+
+ ID.flags:
+
+ FLAG_SETTINGS_PERSIST_VALUE (0x1): When set, the sender of this
+ SETTINGS frame is requesting that the recipient persist the ID/
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 17]
+
+Internet-Draft SPDY Feb 2012
+
+
+ Value and return it in future SETTINGS frames sent from the
+ sender to this recipient. Because persistence is only
+ implemented on the client, this flag is only sent by the
+ server.
+
+ FLAG_SETTINGS_PERSISTED (0x2): When set, the sender is
+ notifying the recipient that this ID/Value pair was previously
+ sent to the sender by the recipient with the
+ FLAG_SETTINGS_PERSIST_VALUE, and the sender is returning it.
+ Because persistence is only implemented on the client, this
+ flag is only sent by the client.
+
+ Defined IDs:
+
+ 1 - SETTINGS_UPLOAD_BANDWIDTH allows the sender to send its
+ expected upload bandwidth on this channel. This number is an
+ estimate. The value should be the integral number of kilobytes
+ per second that the sender predicts as an expected maximum
+ upload channel capacity.
+
+ 2 - SETTINGS_DOWNLOAD_BANDWIDTH allows the sender to send its
+ expected download bandwidth on this channel. This number is an
+ estimate. The value should be the integral number of kilobytes
+ per second that the sender predicts as an expected maximum
+ download channel capacity.
+
+ 3 - SETTINGS_ROUND_TRIP_TIME allows the sender to send its
+ expected round-trip-time on this channel. The round trip time
+ is defined as the minimum amount of time to send a control
+ frame from this client to the remote and receive a response.
+ The value is represented in milliseconds.
+
+ 4 - SETTINGS_MAX_CONCURRENT_STREAMS allows the sender to inform
+ the remote endpoint the maximum number of concurrent streams
+ which it will allow. By default there is no limit. For
+ implementors it is recommended that this value be no smaller
+ than 100.
+
+ 5 - SETTINGS_CURRENT_CWND allows the sender to inform the
+ remote endpoint of the current TCP CWND value.
+
+ 6 - SETTINGS_DOWNLOAD_RETRANS_RATE allows the sender to inform
+ the remote endpoint the retransmission rate (bytes
+ retransmitted / total bytes transmitted).
+
+ 7 - SETTINGS_INITIAL_WINDOW_SIZE allows the sender to inform
+ the remote endpoint the initial window size (in bytes) for new
+ streams.
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 18]
+
+Internet-Draft SPDY Feb 2012
+
+
+ 8 - SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE allows the server
+ to inform the client if the new size of the client certificate
+ vector.
+
+ Value: A 32-bit value.
+
+ The message is intentionally extensible for future information which
+ may improve client-server communications. The sender does not need
+ to send every type of ID/value. It must only send those for which it
+ has accurate values to convey. When multiple ID/value pairs are
+ sent, they should be sent in order of lowest id to highest id. A
+ single SETTINGS frame MUST not contain multiple values for the same
+ ID. If the recipient of a SETTINGS frame discovers multiple values
+ for the same ID, it MUST ignore all values except the first one.
+
+ A server may send multiple SETTINGS frames containing different ID/
+ Value pairs. When the same ID/Value is sent twice, the most recent
+ value overrides any previously sent values. If the server sends IDs
+ 1, 2, and 3 with the FLAG_SETTINGS_PERSIST_VALUE in a first SETTINGS
+ frame, and then sends IDs 4 and 5 with the
+ FLAG_SETTINGS_PERSIST_VALUE, when the client returns the persisted
+ state on its next SETTINGS frame, it SHOULD send all 5 settings (1,
+ 2, 3, 4, and 5 in this example) to the server.
+
+2.6.5. PING
+
+ The PING control frame is a mechanism for measuring a minimal round-
+ trip time from the sender. It can be sent from the client or the
+ server. Recipients of a PING frame should send an identical frame to
+ the sender as soon as possible (if there is other pending data
+ waiting to be sent, PING should take highest priority). Each ping
+ sent by a sender should use a unique ID.
+
+ +----------------------------------+
+ |1| version | 6 |
+ +----------------------------------+
+ | 0 (flags) | 4 (length) |
+ +----------------------------------|
+ | 32-bit ID |
+ +----------------------------------+
+
+ Control bit: The control bit is always 1 for this message.
+
+ Version: The SPDY version number.
+
+ Type: The message type for a PING message is 6.
+
+ Length: This frame is always 4 bytes long.
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 19]
+
+Internet-Draft SPDY Feb 2012
+
+
+ ID: A unique ID for this ping, represented as an unsigned 32 bit
+ value. When the client initiates a ping, it must use an odd numbered
+ ID. When the server initiates a ping, it must use an even numbered
+ ping. Use of odd/even IDs is required in order to avoid accidental
+ looping on PINGs (where each side initiates an identical PING at the
+ same time).
+
+ Note: If a sender uses all possible PING ids (e.g. has sent all 2^31
+ possible IDs), it can wrap and start re-using IDs.
+
+ If a server receives an even numbered PING which it did not initiate,
+ it must ignore the PING. If a client receives an odd numbered PING
+ which it did not initiate, it must ignore the PING.
+
+2.6.6. GOAWAY
+
+ The GOAWAY control frame is a mechanism to tell the remote side of
+ the connection to stop creating streams on this session. It can be
+ sent from the client or the server. Once sent, the sender will not
+ respond to any new SYN_STREAMs on this session. Recipients of a
+ GOAWAY frame must not send additional streams on this session,
+ although a new session can be established for new streams. The
+ purpose of this message is to allow an endpoint to gracefully stop
+ accepting new streams (perhaps for a reboot or maintenance), while
+ still finishing processing of previously established streams.
+
+ There is an inherent race condition between an endpoint sending
+ SYN_STREAMs and the remote sending a GOAWAY message. To deal with
+ this case, the GOAWAY contains a last-stream-id indicating the
+ stream-id of the last stream which was created on the sending
+ endpoint in this session. If the receiver of the GOAWAY sent new
+ SYN_STREAMs for sessions after this last-stream-id, they were not
+ processed by the server and the receiver may treat the stream as
+ though it had never been created at all (hence the receiver may want
+ to re-create the stream later on a new session).
+
+ Endpoints should always send a GOAWAY message before closing a
+ connection so that the remote can know whether a stream has been
+ partially processed or not. (For example, if an HTTP client sends a
+ POST at the same time that a server closes a connection, the client
+ cannot know if the server started to process that POST request if the
+ server does not send a GOAWAY frame to indicate where it stopped
+ working).
+
+ After sending a GOAWAY message, the sender must ignore all SYN_STREAM
+ frames for new streams.
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 20]
+
+Internet-Draft SPDY Feb 2012
+
+
+ +----------------------------------+
+ |1| version | 7 |
+ +----------------------------------+
+ | 0 (flags) | 8 (length) |
+ +----------------------------------|
+ |X| Last-good-stream-ID (31 bits) |
+ +----------------------------------+
+ | Status code |
+ +----------------------------------+
+
+ Control bit: The control bit is always 1 for this message.
+
+ Version: The SPDY version number.
+
+ Type: The message type for a GOAWAY message is 7.
+
+ Length: This frame is always 8 bytes long.
+
+ Last-good-stream-Id: The last stream id which was replied to (with
+ either a SYN_REPLY or RST_STREAM) by the sender of the GOAWAY
+ message. If no streams were replied to, this value MUST be 0.
+
+ Status: The reason for closing the session.
+
+ 0 - OK. This is a normal session teardown.
+
+ 1 - PROTOCOL_ERROR. This is a generic error, and should only be
+ used if a more specific error is not available.
+
+ 11 - INTERNAL_ERROR. This is a generic error which can be used
+ when the implementation has internally failed, not due to anything
+ in the protocol.
+
+2.6.7. HEADERS
+
+ The HEADERS frame augments a stream with additional headers. It may
+ be optionally sent on an existing stream at any time. Specific
+ application of the headers in this frame is application-dependent.
+ The name/value header block within this frame is compressed.
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 21]
+
+Internet-Draft SPDY Feb 2012
+
+
++------------------------------------+
+|1| version | 8 |
++------------------------------------+
+| Flags (8) | Length (24 bits) |
++------------------------------------+
+|X| Stream-ID (31bits) |
++------------------------------------+
+| Number of Name/Value pairs (int32) | <+
++------------------------------------+ |
+| Length of name (int32) | | This section is the "Name/Value
++------------------------------------+ | Header Block", and is compressed.
+| Name (string) | |
++------------------------------------+ |
+| Length of value (int32) | |
++------------------------------------+ |
+| Value (string) | |
++------------------------------------+ |
+| (repeats) | <+
+
+ Flags: Flags related to this frame. Valid flags are:
+
+ 0x01 = FLAG_FIN - marks this frame as the last frame to be
+ transmitted on this stream and puts the sender in the half-closed
+ (Section 2.3.6) state.
+
+ Length: An unsigned 24 bit value representing the number of bytes
+ after the length field. The minimum length of the length field is 4
+ (when the number of name value pairs is 0).
+
+ Stream-ID: The stream this HEADERS block is associated with.
+
+ Name/Value Header Block: A set of name/value pairs carried as part of
+ the SYN_STREAM. see Name/Value Header Block (Section 2.6.10).
+
+2.6.8. WINDOW_UPDATE
+
+ The WINDOW_UPDATE control frame is used to implement per stream flow
+ control in SPDY. Flow control in SPDY is per hop, that is, only
+ between the two endpoints of a SPDY connection. If there are one or
+ more intermediaries between the client and the origin server, flow
+ control signals are not explicitly forwarded by the intermediaries.
+ (However, throttling of data transfer by any recipient may have the
+ effect of indirectly propagating flow control information upstream
+ back to the original sender.) Flow control only applies to the data
+ portion of data frames. Recipients must buffer all control frames.
+ If a recipient fails to buffer an entire control frame, it MUST issue
+ a stream error (Section 2.4.2) with the status code
+ FLOW_CONTROL_ERROR for the stream.
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 22]
+
+Internet-Draft SPDY Feb 2012
+
+
+ Flow control in SPDY is implemented by a data transfer window kept by
+ the sender of each stream. The data transfer window is a simple
+ uint32 that indicates how many bytes of data the sender can transmit.
+ After a stream is created, but before any data frames have been
+ transmitted, the sender begins with the initial window size. This
+ window size is a measure of the buffering capability of the
+ recipient. The sender must not send a data frame with data length
+ greater than the transfer window size. After sending each data
+ frame, the sender decrements its transfer window size by the amount
+ of data transmitted. When the window size becomes less than or equal
+ to 0, the sender must pause transmitting data frames. At the other
+ end of the stream, the recipient sends a WINDOW_UPDATE control back
+ to notify the sender that it has consumed some data and freed up
+ buffer space to receive more data.
+
+ +----------------------------------+
+ |1| version | 9 |
+ +----------------------------------+
+ | 0 (flags) | 8 (length) |
+ +----------------------------------+
+ |X| Stream-ID (31-bits) |
+ +----------------------------------+
+ |X| Delta-Window-Size (31-bits) |
+ +----------------------------------+
+
+ Control bit: The control bit is always 1 for this message.
+
+ Version: The SPDY version number.
+
+ Type: The message type for a WINDOW_UPDATE message is 9.
+
+ Length: The length field is always 8 for this frame (there are 8
+ bytes after the length field).
+
+ Stream-ID: The stream ID that this WINDOW_UPDATE control frame is
+ for.
+
+ Delta-Window-Size: The additional number of bytes that the sender can
+ transmit in addition to existing remaining window size. The legal
+ range for this field is 1 to 2^31 - 1 (0x7fffffff) bytes.
+
+ The window size as kept by the sender must never exceed 2^31
+ (although it can become negative in one special case). If a sender
+ receives a WINDOW_UPDATE that causes the its window size to exceed
+ this limit, it must send RST_STREAM with status code
+ FLOW_CONTROL_ERROR to terminate the stream.
+
+ When a SPDY connection is first established, the default initial
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 23]
+
+Internet-Draft SPDY Feb 2012
+
+
+ window size for all streams is 64KB. An endpoint can use the
+ SETTINGS control frame to adjust the initial window size for the
+ connection. That is, its peer can start out using the 64KB default
+ initial window size when sending data frames before receiving the
+ SETTINGS. Because SETTINGS is asynchronous, there may be a race
+ condition if the recipient wants to decrease the initial window size,
+ but its peer immediately sends 64KB on the creation of a new
+ connection, before waiting for the SETTINGS to arrive. This is one
+ case where the window size kept by the sender will become negative.
+ Once the sender detects this condition, it must stop sending data
+ frames and wait for the recipient to catch up. The recipient has two
+ choices:
+
+ immediately send RST_STREAM with FLOW_CONTROL_ERROR status code.
+
+ allow the head of line blocking (as there is only one stream for
+ the session and the amount of data in flight is bounded by the
+ default initial window size), and send WINDOW_UPDATE as it
+ consumes data.
+
+ In the case of option 2, both sides must compute the window size
+ based on the initial window size in the SETTINGS. For example, if
+ the recipient sets the initial window size to be 16KB, and the sender
+ sends 64KB immediately on connection establishment, the sender will
+ discover its window size is -48KB on receipt of the SETTINGS. As the
+ recipient consumes the first 16KB, it must send a WINDOW_UPDATE of
+ 16KB back to the sender. This interaction continues until the
+ sender's window size becomes positive again, and it can resume
+ transmitting data frames.
+
+ After the recipient reads in a data frame with FLAG_FIN that marks
+ the end of the data stream, it should not send WINDOW_UPDATE frames
+ as it consumes the last data frame. A sender should ignore all the
+ WINDOW_UPDATE frames associated with the stream after it send the
+ last frame for the stream.
+
+ The data frames from the sender and the WINDOW_UPDATE frames from the
+ recipient are completely asynchronous with respect to each other.
+ This property allows a recipient to aggressively update the window
+ size kept by the sender to prevent the stream from stalling.
+
+2.6.9. CREDENTIAL
+
+ The CREDENTIAL control frame is used by the client to send additional
+ client certificates to the server. A SPDY client may decide to send
+ requests for resources from different origins on the same SPDY
+ session if it decides that that server handles both origins. For
+ example if the IP address associated with both hostnames matches and
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 24]
+
+Internet-Draft SPDY Feb 2012
+
+
+ the SSL server certificate presented in the initial handshake is
+ valid for both hostnames. However, because the SSL connection can
+ contain at most one client certificate, the client needs a mechanism
+ to send additional client certificates to the server.
+
+ The server is required to maintain a vector of client certificates
+ associated with a SPDY session. When the client needs to send a
+ client certificate to the server, it will send a CREDENTIAL frame
+ that specifies the index of the slot in which to store the
+ certificate as well as proof that the client posesses the
+ corresponding private key. The initial size of this vector must be
+ 8. If the client provides a client certificate during the first TLS
+ handshake, the contents of this certificate must be copied into the
+ first slot (index 1) in the CREDENTIAL vector, though it may be
+ overwritten by subsequent CREDENTIAL frames. The server must
+ exclusively use the CREDNETIAL vector when evaluating the client
+ certificates associated with an origin. The server may change the
+ size of this vector by sending a SETTINGS frame with the setting
+ SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE value specified. In the
+ event that the new size is smaller than the current size, truncation
+ occurs preserving lower-index slots as possible.
+
+ TLS renegotiation with client authentication is incompatible with
+ SPDY given the multiplexed nature of SPDY. Specifically, imagine
+ that the client has 2 requests outstanding to the server for two
+ different pages (in different tabs). When the renegotiation + client
+ certificate request comes in, the browser is unable to determine
+ which resource triggered the client certificate request, in order to
+ prompt the user accordingly.
+
+ +----------------------------------+
+ |1|000000000000001|0000000000001011|
+ +----------------------------------+
+ | flags (8) | Length (24 bits) |
+ +----------------------------------+
+ | Slot (16 bits) | |
+ +-----------------+ |
+ | Proof Length (32 bits) |
+ +----------------------------------+
+ | Proof |
+ +----------------------------------+ <+
+ | Certificate Length (32 bits) | |
+ +----------------------------------+ | Repeated until end of frame
+ | Certificate | |
+ +----------------------------------+ <+
+
+ Slot: The index in the server's client certificate vector where this
+ certificate should be stored. If there is already a certificate
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 25]
+
+Internet-Draft SPDY Feb 2012
+
+
+ stored at this index, it will be overwritten. The index is one
+ based, not zero based; zero is an invalid slot index.
+
+ Proof: Cryptographic proof that the client has possession of the
+ private key associated with the certificate. The format is a TLS
+ digitally-signed element
+ (http://tools.ietf.org/html/rfc5246#section-4.7). The signature
+ algorithm must be the same as that used in the CertificateVerify
+ message. However, since the MD5+SHA1 signature type used in TLS 1.0
+ connections can not be correctly encoded in a digitally-signed
+ element, SHA1 must be used when MD5+SHA1 was used in the SSL
+ connection. The signature is calculated over a 32 byte TLS extractor
+ value (http://tools.ietf.org/html/rfc5705) with a label of "EXPORTER
+ SPDY certificate proof" using the empty string as context. ForRSA
+ certificates the signature would be a PKCS#1 v1.5 signature. For
+ ECDSA, it would be an ECDSA-Sig-Value
+ (http://tools.ietf.org/html/rfc5480#appendix-A). For a 1024-bit RSA
+ key, the CREDENTIAL message would be ~500 bytes.
+
+ Certificate: The certificate chain, starting with the leaf
+ certificate. Each certificate must be encoded as a 32 bit length,
+ followed by a DER encoded certificate. The certificate must be of
+ the same type (RSA, ECDSA, etc) as the client certificate associated
+ with the SSL connection.
+
+ If the server receives a request for a resource with unacceptable
+ credential (either missing or invalid), it must reply with a
+ RST_STREAM frame with the status code INVALID_CREDENTIALS. Upon
+ receipt of a RST_STREAM frame with INVALID_CREDENTIALS, the client
+ should initiate a new stream directly to the requested origin and
+ resend the request. Note, SPDY does not allow the server to request
+ different client authentication for different resources in the same
+ origin.
+
+ If the server receives an invalid CREDENTIAL frame, it MUST respond
+ with a GOAWAY frame and shutdown the session.
+
+2.6.10. Name/Value Header Block
+
+ The Name/Value Header Block is found in the SYN_STREAM, SYN_REPLY and
+ HEADERS control frames, and shares a common format:
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 26]
+
+Internet-Draft SPDY Feb 2012
+
+
+ +------------------------------------+
+ | Number of Name/Value pairs (int32) |
+ +------------------------------------+
+ | Length of name (int32) |
+ +------------------------------------+
+ | Name (string) |
+ +------------------------------------+
+ | Length of value (int32) |
+ +------------------------------------+
+ | Value (string) |
+ +------------------------------------+
+ | (repeats) |
+
+ Number of Name/Value pairs: The number of repeating name/value pairs
+ following this field.
+
+ List of Name/Value pairs:
+
+ Length of Name: a 32-bit value containing the number of octets in
+ the name field. Note that in practice, this length must not
+ exceed 2^24, as that is the maximum size of a SPDY frame.
+
+ Name: 0 or more octets, 8-bit sequences of data, excluding 0.
+
+ Length of Value: a 32-bit value containing the number of octets in
+ the value field. Note that in practice, this length must not
+ exceed 2^24, as that is the maximum size of a SPDY frame.
+
+ Value: 0 or more octets, 8-bit sequences of data, excluding 0.
+
+ Each header name must have at least one value. Header names are
+ encoded using the US-ASCII character set [ASCII] and must be all
+ lower case. The length of each name must be greater than zero. A
+ recipient of a zero-length name MUST issue a stream error
+ (Section 2.4.2) with the status code PROTOCOL_ERROR for the
+ stream-id.
+
+ Duplicate header names are not allowed. To send two identically
+ named headers, send a header with two values, where the values are
+ separated by a single NUL (0) byte. A header value can either be
+ empty (e.g. the length is zero) or it can contain multiple, NUL-
+ separated values, each with length greater than zero. The value
+ never starts nor ends with a NUL character. Recipients of illegal
+ value fields MUST issue a stream error (Section 2.4.2) with the
+ status code PROTOCOL_ERROR for the stream-id.
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 27]
+
+Internet-Draft SPDY Feb 2012
+
+
+2.6.10.1. Compression
+
+ The Name/Value Header Block is a section of the SYN_STREAM,
+ SYN_REPLY, and HEADERS frames used to carry header meta-data. This
+ block is always compressed using zlib compression. Within this
+ specification, any reference to 'zlib' is referring to the ZLIB
+ Compressed Data Format Specification Version 3.3 as part of RFC1950.
+ [RFC1950]
+
+ For each HEADERS compression instance, the initial state is
+ initialized using the following dictionary [UDELCOMPRESSION]:
+
+ const unsigned char SPDY_dictionary_txt[] = {
+ 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, \\ - - - - o p t i
+ 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, \\ o n s - - - - h
+ 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, \\ e a d - - - - p
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, \\ o s t - - - - p
+ 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, \\ u t - - - - d e
+ 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, \\ l e t e - - - -
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, \\ t r a c e - - -
+ 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, \\ - a c c e p t -
+ 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, \\ - - - a c c e p
+ 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, \\ t - c h a r s e
+ 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, \\ t - - - - a c c
+ 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, \\ e p t - e n c o
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, \\ d i n g - - - -
+ 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, \\ a c c e p t - l
+ 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, \\ a n g u a g e -
+ 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, \\ - - - a c c e p
+ 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, \\ t - r a n g e s
+ 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, \\ - - - - a g e -
+ 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, \\ - - - a l l o w
+ 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, \\ - - - - a u t h
+ 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, \\ o r i z a t i o
+ 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, \\ n - - - - c a c
+ 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, \\ h e - c o n t r
+ 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, \\ o l - - - - c o
+ 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, \\ n n e c t i o n
+ 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, \\ e n t - b a s e
+ 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, \\ e n t - e n c o
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, \\ d i n g - - - -
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, \\ c o n t e n t -
+ 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, \\ l a n g u a g e
+ 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, \\ e n t - l e n g
+ 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, \\ t h - - - - c o
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 28]
+
+Internet-Draft SPDY Feb 2012
+
+
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, \\ n t e n t - l o
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, \\ c a t i o n - -
+ 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \\ - - c o n t e n
+ 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, \\ t - m d 5 - - -
+ 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, \\ - c o n t e n t
+ 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, \\ - r a n g e - -
+ 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \\ - - c o n t e n
+ 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, \\ t - t y p e - -
+ 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, \\ - - d a t e - -
+ 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, \\ - - e t a g - -
+ 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, \\ - - e x p e c t
+ 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, \\ - - - - e x p i
+ 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, \\ r e s - - - - f
+ 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, \\ r o m - - - - h
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, \\ o s t - - - - i
+ 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, \\ f - m a t c h -
+ 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, \\ - - - i f - m o
+ 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, \\ d i f i e d - s
+ 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, \\ i n c e - - - -
+ 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, \\ i f - n o n e -
+ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, \\ m a t c h - - -
+ 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, \\ - i f - r a n g
+ 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, \\ e - - - - i f -
+ 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, \\ u n m o d i f i
+ 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, \\ e d - s i n c e
+ 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, \\ - - - - l a s t
+ 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, \\ - m o d i f i e
+ 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, \\ d - - - - l o c
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, \\ a t i o n - - -
+ 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, \\ - m a x - f o r
+ 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, \\ w a r d s - - -
+ 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, \\ - p r a g m a -
+ 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, \\ - - - p r o x y
+ 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, \\ - a u t h e n t
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, \\ i c a t e - - -
+ 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, \\ - p r o x y - a
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, \\ u t h o r i z a
+ 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, \\ t i o n - - - -
+ 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, \\ r a n g e - - -
+ 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, \\ - r e f e r e r
+ 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, \\ - - - - r e t r
+ 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, \\ y - a f t e r -
+ 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, \\ - - - s e r v e
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, \\ r - - - - t e -
+ 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, \\ - - - t r a i l
+ 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, \\ e r - - - - t r
+ 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, \\ a n s f e r - e
+ 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, \\ n c o d i n g -
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 29]
+
+Internet-Draft SPDY Feb 2012
+
+
+ 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, \\ - - - u p g r a
+ 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, \\ d e - - - - u s
+ 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, \\ e r - a g e n t
+ 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, \\ - - - - v a r y
+ 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, \\ - - - - v i a -
+ 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, \\ - - - w a r n i
+ 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, \\ n g - - - - w w
+ 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, \\ w - a u t h e n
+ 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, \\ t i c a t e - -
+ 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, \\ - - m e t h o d
+ 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, \\ - - - - g e t -
+ 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, \\ - - - s t a t u
+ 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, \\ s - - - - 2 0 0
+ 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, \\ - O K - - - - v
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, \\ e r s i o n - -
+ 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, \\ - - H T T P - 1
+ 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, \\ - 1 - - - - u r
+ 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, \\ l - - - - p u b
+ 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, \\ l i c - - - - s
+ 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, \\ e t - c o o k i
+ 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, \\ e - - - - k e e
+ 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, \\ p - a l i v e -
+ 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, \\ - - - o r i g i
+ 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, \\ n 1 0 0 1 0 1 2
+ 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, \\ 0 1 2 0 2 2 0 5
+ 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, \\ 2 0 6 3 0 0 3 0
+ 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, \\ 2 3 0 3 3 0 4 3
+ 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, \\ 0 5 3 0 6 3 0 7
+ 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, \\ 4 0 2 4 0 5 4 0
+ 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, \\ 6 4 0 7 4 0 8 4
+ 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, \\ 0 9 4 1 0 4 1 1
+ 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, \\ 4 1 2 4 1 3 4 1
+ 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, \\ 4 4 1 5 4 1 6 4
+ 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, \\ 1 7 5 0 2 5 0 4
+ 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, \\ 5 0 5 2 0 3 - N
+ 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, \\ o n - A u t h o
+ 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, \\ r i t a t i v e
+ 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, \\ - I n f o r m a
+ 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, \\ t i o n 2 0 4 -
+ 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, \\ N o - C o n t e
+ 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, \\ n t 3 0 1 - M o
+ 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, \\ v e d - P e r m
+ 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, \\ a n e n t l y 4
+ 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, \\ 0 0 - B a d - R
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, \\ e q u e s t 4 0
+ 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, \\ 1 - U n a u t h
+ 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, \\ o r i z e d 4 0
+ 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, \\ 3 - F o r b i d
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 30]
+
+Internet-Draft SPDY Feb 2012
+
+
+ 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, \\ d e n 4 0 4 - N
+ 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, \\ o t - F o u n d
+ 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, \\ 5 0 0 - I n t e
+ 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, \\ r n a l - S e r
+ 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, \\ v e r - E r r o
+ 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, \\ r 5 0 1 - N o t
+ 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, \\ - I m p l e m e
+ 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, \\ n t e d 5 0 3 -
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, \\ S e r v i c e -
+ 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, \\ U n a v a i l a
+ 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, \\ b l e J a n - F
+ 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, \\ e b - M a r - A
+ 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, \\ p r - M a y - J
+ 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, \\ u n - J u l - A
+ 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, \\ u g - S e p t -
+ 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, \\ O c t - N o v -
+ 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, \\ D e c - 0 0 - 0
+ 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, \\ 0 - 0 0 - M o n
+ 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, \\ - - T u e - - W
+ 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, \\ e d - - T h u -
+ 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, \\ - F r i - - S a
+ 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, \\ t - - S u n - -
+ 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, \\ G M T c h u n k
+ 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, \\ e d - t e x t -
+ 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, \\ h t m l - i m a
+ 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, \\ g e - p n g - i
+ 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, \\ m a g e - j p g
+ 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, \\ - i m a g e - g
+ 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, \\ i f - a p p l i
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, \\ c a t i o n - x
+ 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, \\ m l - a p p l i
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, \\ c a t i o n - x
+ 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, \\ h t m l - x m l
+ 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, \\ - t e x t - p l
+ 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, \\ a i n - t e x t
+ 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, \\ - j a v a s c r
+ 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, \\ i p t - p u b l
+ 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, \\ i c p r i v a t
+ 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, \\ e m a x - a g e
+ 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, \\ - g z i p - d e
+ 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, \\ f l a t e - s d
+ 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, \\ c h c h a r s e
+ 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, \\ t - u t f - 8 c
+ 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, \\ h a r s e t - i
+ 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, \\ s o - 8 8 5 9 -
+ 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, \\ 1 - u t f - - -
+ 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e \\ - e n q - 0 -
+ };
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 31]
+
+Internet-Draft SPDY Feb 2012
+
+
+ The entire contents of the name/value header block is compressed
+ using zlib. There is a single zlib stream for all name value pairs
+ in one direction on a connection. SPDY uses a SYNC_FLUSH between
+ each compressed frame.
+
+ Implementation notes: the compression engine can be tuned to favor
+ speed or size. Optimizing for size increases memory use and CPU
+ consumption. Because header blocks are generally small, implementors
+ may want to reduce the window-size of the compression engine from the
+ default 15bits (a 32KB window) to more like 11bits (a 2KB window).
+ The exact setting is chosen by the compressor, the decompressor will
+ work with any setting.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 32]
+
+Internet-Draft SPDY Feb 2012
+
+
+3. HTTP Layering over SPDY
+
+ SPDY is intended to be as compatible as possible with current web-
+ based applications. This means that, from the perspective of the
+ server business logic or application API, the features of HTTP are
+ unchanged. To achieve this, all of the application request and
+ response header semantics are preserved, although the syntax of
+ conveying those semantics has changed. Thus, the rules from the
+ HTTP/1.1 specification in RFC2616 [RFC2616] apply with the changes in
+ the sections below.
+
+3.1. Connection Management
+
+ Clients SHOULD NOT open more than one SPDY session to a given origin
+ [RFC6454] concurrently.
+
+ Note that it is possible for one SPDY session to be finishing (e.g. a
+ GOAWAY message has been sent, but not all streams have finished),
+ while another SPDY session is starting.
+
+3.1.1. Use of GOAWAY
+
+ SPDY provides a GOAWAY message which can be used when closing a
+ connection from either the client or server. Without a server GOAWAY
+ message, HTTP has a race condition where the client sends a request
+ (a new SYN_STREAM) just as the server is closing the connection, and
+ the client cannot know if the server received the stream or not. By
+ using the last-stream-id in the GOAWAY, servers can indicate to the
+ client if a request was processed or not.
+
+ Note that some servers will choose to send the GOAWAY and immediately
+ terminate the connection without waiting for active streams to
+ finish. The client will be able to determine this because SPDY
+ streams are determinstically closed. This abrupt termination will
+ force the client to heuristically decide whether to retry the pending
+ requests. Clients always need to be capable of dealing with this
+ case because they must deal with accidental connection termination
+ cases, which are the same as the server never having sent a GOAWAY.
+
+ More sophisticated servers will use GOAWAY to implement a graceful
+ teardown. They will send the GOAWAY and provide some time for the
+ active streams to finish before terminating the connection.
+
+ If a SPDY client closes the connection, it should also send a GOAWAY
+ message. This allows the server to know if any server-push streams
+ were received by the client.
+
+ If the endpoint closing the connection has not received any
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 33]
+
+Internet-Draft SPDY Feb 2012
+
+
+ SYN_STREAMs from the remote, the GOAWAY will contain a last-stream-id
+ of 0.
+
+3.2. HTTP Request/Response
+
+3.2.1. Request
+
+ The client initiates a request by sending a SYN_STREAM frame. For
+ requests which do not contain a body, the SYN_STREAM frame MUST set
+ the FLAG_FIN, indicating that the client intends to send no further
+ data on this stream. For requests which do contain a body, the
+ SYN_STREAM will not contain the FLAG_FIN, and the body will follow
+ the SYN_STREAM in a series of DATA frames. The last DATA frame will
+ set the FLAG_FIN to indicate the end of the body.
+
+ The SYN_STREAM Name/Value section will contain all of the HTTP
+ headers which are associated with an HTTP request. The header block
+ in SPDY is mostly unchanged from today's HTTP header block, with the
+ following differences:
+
+ The first line of the request is unfolded into name/value pairs
+ like other HTTP headers and MUST be present:
+
+ ":method" - the HTTP method for this request (e.g. "GET",
+ "POST", "HEAD", etc)
+
+ ":path" - the url-path for this url with "/" prefixed. (See
+ RFC1738 [RFC1738]). For example, for
+ "http://www.google.com/search?q=dogs" the path would be
+ "/search?q=dogs".
+
+ ":version" - the HTTP version of this request (e.g.
+ "HTTP/1.1")
+
+ In addition, the following two name/value pairs must also be
+ present in every request:
+
+ ":host" - the hostport (See RFC1738 [RFC1738]) portion of the
+ URL for this request (e.g. "www.google.com:1234"). This header
+ is the same as the HTTP 'Host' header.
+
+ ":scheme" - the scheme portion of the URL for this request
+ (e.g. "https"))
+
+ Header names are all lowercase.
+
+ The Connection, Host, Keep-Alive, Proxy-Connection, and Transfer-
+ Encoding headers are not valid and MUST not be sent.
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 34]
+
+Internet-Draft SPDY Feb 2012
+
+
+ User-agents MUST support gzip compression. Regardless of the
+ Accept-Encoding sent by the user-agent, the server may always send
+ content encoded with gzip or deflate encoding.
+
+ If a server receives a request where the sum of the data frame
+ payload lengths does not equal the size of the Content-Length
+ header, the server MUST return a 400 (Bad Request) error.
+
+ POST-specific changes:
+
+ Although POSTs are inherently chunked, POST requests SHOULD
+ also be accompanied by a Content-Length header. There are two
+ reasons for this: First, it assists with upload progress meters
+ for an improved user experience. But second, we know from
+ early versions of SPDY that failure to send a content length
+ header is incompatible with many existing HTTP server
+ implementations. Existing user-agents do not omit the Content-
+ Length header, and server implementations have come to depend
+ upon this.
+
+ The user-agent is free to prioritize requests as it sees fit. If the
+ user-agent cannot make progress without receiving a resource, it
+ should attempt to raise the priority of that resource. Resources
+ such as images, SHOULD generally use the lowest priority.
+
+ If a client sends a SYN_STREAM without all of the method, host, path,
+ scheme, and version headers, the server MUST reply with a HTTP 400
+ Bad Request reply.
+
+3.2.2. Response
+
+ The server responds to a client request with a SYN_REPLY frame.
+ Symmetric to the client's upload stream, server will send data after
+ the SYN_REPLY frame via a series of DATA frames, and the last data
+ frame will contain the FLAG_FIN to indicate successful end-of-stream.
+ If a response (like a 202 or 204 response) contains no body, the
+ SYN_REPLY frame may contain the FLAG_FIN flag to indicate no further
+ data will be sent on the stream.
+
+ The response status line is unfolded into name/value pairs like
+ other HTTP headers and must be present:
+
+ ":status" - The HTTP response status code (e.g. "200" or "200
+ OK")
+
+ ":version" - The HTTP response version (e.g. "HTTP/1.1")
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 35]
+
+Internet-Draft SPDY Feb 2012
+
+
+ All header names must be lowercase.
+
+ The Connection, Keep-Alive, Proxy-Connection, and Transfer-
+ Encoding headers are not valid and MUST not be sent.
+
+ Responses MAY be accompanied by a Content-Length header for
+ advisory purposes. (e.g. for UI progress meters)
+
+ If a client receives a response where the sum of the data frame
+ payload lengths does not equal the size of the Content-Length
+ header, the client MUST ignore the content length header.
+
+ If a client receives a SYN_REPLY without a status or without a
+ version header, the client must reply with a RST_STREAM frame
+ indicating a PROTOCOL ERROR.
+
+3.2.3. Authentication
+
+ When a client sends a request to an origin server that requires
+ authentication, the server can reply with a "401 Unauthorized"
+ response, and include a WWW-Authenticate challenge header that
+ defines the authentication scheme to be used. The client then
+ retries the request with an Authorization header appropriate to the
+ specified authentication scheme.
+
+ There are four options for proxy authentication, Basic, Digest, NTLM
+ and Negotiate (SPNEGO). The first two options were defined in
+ RFC2617 [RFC2617], and are stateless. The second two options were
+ developed by Microsoft and specified in RFC4559 [RFC4559], and are
+ stateful; otherwise known as multi-round authentication, or
+ connection authentication.
+
+3.2.3.1. Stateless Authentication
+
+ Stateless Authentication over SPDY is identical to how it is
+ performed over HTTP. If multiple SPDY streams are concurrently sent
+ to a single server, each will authenticate independently, similar to
+ how two HTTP connections would independently authenticate to a proxy
+ server.
+
+3.2.3.2. Stateful Authentication
+
+ Unfortunately, the stateful authentication mechanisms were
+ implemented and defined in a such a way that directly violates
+ RFC2617 - they do not include a "realm" as part of the request. This
+ is problematic in SPDY because it makes it impossible for a client to
+ disambiguate two concurrent server authentication challenges.
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 36]
+
+Internet-Draft SPDY Feb 2012
+
+
+ To deal with this case, SPDY servers using Stateful Authentication
+ MUST implement one of two changes:
+
+ Servers can add a "realm=<desired realm>" header so that the two
+ authentication requests can be disambiguated and run concurrently.
+ Unfortunately, given how these mechanisms work, this is probably
+ not practical.
+
+ Upon sending the first stateful challenge response, the server
+ MUST buffer and defer all further frames which are not part of
+ completing the challenge until the challenge has completed.
+ Completing the authentication challenge may take multiple round
+ trips. Once the client receives a "401 Authenticate" response for
+ a stateful authentication type, it MUST stop sending new requests
+ to the server until the authentication has completed by receiving
+ a non-401 response on at least one stream.
+
+3.3. Server Push Transactions
+
+ SPDY enables a server to send multiple replies to a client for a
+ single request. The rationale for this feature is that sometimes a
+ server knows that it will need to send multiple resources in response
+ to a single request. Without server push features, the client must
+ first download the primary resource, then discover the secondary
+ resource(s), and request them. Pushing of resources avoids the
+ round-trip delay, but also creates a potential race where a server
+ can be pushing content which a user-agent is in the process of
+ requesting. The following mechanics attempt to prevent the race
+ condition while enabling the performance benefit.
+
+ Browsers receiving a pushed response MUST validate that the server is
+ authorized to push the URL using the browser same-origin [RFC6454]
+ policy. For example, a SPDY connection to www.foo.com is generally
+ not permitted to push a response for www.evil.com.
+
+ If the browser accepts a pushed response (e.g. it does not send a
+ RST_STREAM), the browser MUST attempt to cache the pushed response in
+ same way that it would cache any other response. This means
+ validating the response headers and inserting into the disk cache.
+
+ Because pushed responses have no request, they have no request
+ headers associated with them. At the framing layer, SPDY pushed
+ streams contain an "associated-stream-id" which indicates the
+ requested stream for which the pushed stream is related. The pushed
+ stream inherits all of the headers from the associated-stream-id with
+ the exception of ":host", ":scheme", and ":path", which are provided
+ as part of the pushed response stream headers. The browser MUST
+ store these inherited and implied request headers with the cached
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 37]
+
+Internet-Draft SPDY Feb 2012
+
+
+ resource.
+
+ Implementation note: With server push, it is theoretically possible
+ for servers to push unreasonable amounts of content or resources to
+ the user-agent. Browsers MUST implement throttles to protect against
+ unreasonable push attacks.
+
+3.3.1. Server implementation
+
+ When the server intends to push a resource to the user-agent, it
+ opens a new stream by sending a unidirectional SYN_STREAM. The
+ SYN_STREAM MUST include an Associated-To-Stream-ID, and MUST set the
+ FLAG_UNIDIRECTIONAL flag. The SYN_STREAM MUST include headers for
+ ":scheme", ":host", ":path", which represent the URL for the resource
+ being pushed. Subsequent headers may follow in HEADERS frames. The
+ purpose of the association is so that the user-agent can
+ differentiate which request induced the pushed stream; without it, if
+ the user-agent had two tabs open to the same page, each pushing
+ unique content under a fixed URL, the user-agent would not be able to
+ differentiate the requests.
+
+ The Associated-To-Stream-ID must be the ID of an existing, open
+ stream. The reason for this restriction is to have a clear endpoint
+ for pushed content. If the user-agent requested a resource on stream
+ 11, the server replies on stream 11. It can push any number of
+ additional streams to the client before sending a FLAG_FIN on stream
+ 11. However, once the originating stream is closed no further push
+ streams may be associated with it. The pushed streams do not need to
+ be closed (FIN set) before the originating stream is closed, they
+ only need to be created before the originating stream closes.
+
+ It is illegal for a server to push a resource with the Associated-To-
+ Stream-ID of 0.
+
+ To minimize race conditions with the client, the SYN_STREAM for the
+ pushed resources MUST be sent prior to sending any content which
+ could allow the client to discover the pushed resource and request
+ it.
+
+ The server MUST only push resources which would have been returned
+ from a GET request.
+
+ Note: If the server does not have all of the Name/Value Response
+ headers available at the time it issues the HEADERS frame for the
+ pushed resource, it may later use an additional HEADERS frame to
+ augment the name/value pairs to be associated with the pushed stream.
+ The subsequent HEADERS frame(s) must not contain a header for
+ ':host', ':scheme', or ':path' (e.g. the server can't change the
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 38]
+
+Internet-Draft SPDY Feb 2012
+
+
+ identity of the resource to be pushed). The HEADERS frame must not
+ contain duplicate headers with a previously sent HEADERS frame. The
+ server must send a HEADERS frame including the scheme/host/port
+ headers before sending any data frames on the stream.
+
+3.3.2. Client implementation
+
+ When fetching a resource the client has 3 possibilities:
+
+ the resource is not being pushed
+
+ the resource is being pushed, but the data has not yet arrived
+
+ the resource is being pushed, and the data has started to arrive
+
+ When a SYN_STREAM and HEADERS frame which contains an Associated-To-
+ Stream-ID is received, the client must not issue GET requests for the
+ resource in the pushed stream, and instead wait for the pushed stream
+ to arrive.
+
+ If a client receives a server push stream with stream-id 0, it MUST
+ issue a session error (Section 2.4.1) with the status code
+ PROTOCOL_ERROR.
+
+ When a client receives a SYN_STREAM from the server without a the
+ ':host', ':scheme', and ':path' headers in the Name/Value section, it
+ MUST reply with a RST_STREAM with error code HTTP_PROTOCOL_ERROR.
+
+ To cancel individual server push streams, the client can issue a
+ stream error (Section 2.4.2) with error code CANCEL. Upon receipt,
+ the server MUST stop sending on this stream immediately (this is an
+ Abrupt termination).
+
+ To cancel all server push streams related to a request, the client
+ may issue a stream error (Section 2.4.2) with error code CANCEL on
+ the associated-stream-id. By cancelling that stream, the server MUST
+ immediately stop sending frames for any streams with
+ in-association-to for the original stream.
+
+ If the server sends a HEADER frame containing duplicate headers with
+ a previous HEADERS frame for the same stream, the client must issue a
+ stream error (Section 2.4.2) with error code PROTOCOL ERROR.
+
+ If the server sends a HEADERS frame after sending a data frame for
+ the same stream, the client MAY ignore the HEADERS frame. Ignoring
+ the HEADERS frame after a data frame prevents handling of HTTP's
+ trailing headers
+ (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40).
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 39]
+
+Internet-Draft SPDY Feb 2012
+
+
+4. Design Rationale and Notes
+
+ Authors' notes: The notes in this section have no bearing on the SPDY
+ protocol as specified within this document, and none of these notes
+ should be considered authoritative about how the protocol works.
+ However, these notes may prove useful in future debates about how to
+ resolve protocol ambiguities or how to evolve the protocol going
+ forward. They may be removed before the final draft.
+
+4.1. Separation of Framing Layer and Application Layer
+
+ Readers may note that this specification sometimes blends the framing
+ layer (Section 2) with requirements of a specific application - HTTP
+ (Section 3). This is reflected in the request/response nature of the
+ streams, the definition of the HEADERS and compression contexts which
+ are very similar to HTTP, and other areas as well.
+
+ This blending is intentional - the primary goal of this protocol is
+ to create a low-latency protocol for use with HTTP. Isolating the
+ two layers is convenient for description of the protocol and how it
+ relates to existing HTTP implementations. However, the ability to
+ reuse the SPDY framing layer is a non goal.
+
+4.2. Error handling - Framing Layer
+
+ Error handling at the SPDY layer splits errors into two groups: Those
+ that affect an individual SPDY stream, and those that do not.
+
+ When an error is confined to a single stream, but general framing is
+ in tact, SPDY attempts to use the RST_STREAM as a mechanism to
+ invalidate the stream but move forward without aborting the
+ connection altogether.
+
+ For errors occuring outside of a single stream context, SPDY assumes
+ the entire session is hosed. In this case, the endpoint detecting
+ the error should initiate a connection close.
+
+4.3. One Connection Per Domain
+
+ SPDY attempts to use fewer connections than other protocols have
+ traditionally used. The rationale for this behavior is because it is
+ very difficult to provide a consistent level of service (e.g. TCP
+ slow-start), prioritization, or optimal compression when the client
+ is connecting to the server through multiple channels.
+
+ Through lab measurements, we have seen consistent latency benefits by
+ using fewer connections from the client. The overall number of
+ packets sent by SPDY can be as much as 40% less than HTTP. Handling
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 40]
+
+Internet-Draft SPDY Feb 2012
+
+
+ large numbers of concurrent connections on the server also does
+ become a scalability problem, and SPDY reduces this load.
+
+ The use of multiple connections is not without benefit, however.
+ Because SPDY multiplexes multiple, independent streams onto a single
+ stream, it creates a potential for head-of-line blocking problems at
+ the transport level. In tests so far, the negative effects of head-
+ of-line blocking (especially in the presence of packet loss) is
+ outweighed by the benefits of compression and prioritization.
+
+4.4. Fixed vs Variable Length Fields
+
+ SPDY favors use of fixed length 32bit fields in cases where smaller,
+ variable length encodings could have been used. To some, this seems
+ like a tragic waste of bandwidth. SPDY choses the simple encoding
+ for speed and simplicity.
+
+ The goal of SPDY is to reduce latency on the network. The overhead
+ of SPDY frames is generally quite low. Each data frame is only an 8
+ byte overhead for a 1452 byte payload (~0.6%). At the time of this
+ writing, bandwidth is already plentiful, and there is a strong trend
+ indicating that bandwidth will continue to increase. With an average
+ worldwide bandwidth of 1Mbps, and assuming that a variable length
+ encoding could reduce the overhead by 50%, the latency saved by using
+ a variable length encoding would be less than 100 nanoseconds. More
+ interesting are the effects when the larger encodings force a packet
+ boundary, in which case a round-trip could be induced. However, by
+ addressing other aspects of SPDY and TCP interactions, we believe
+ this is completely mitigated.
+
+4.5. Compression Context(s)
+
+ When isolating the compression contexts used for communicating with
+ multiple origins, we had a few choices to make. We could have
+ maintained a map (or list) of compression contexts usable for each
+ origin. The basic case is easy - each HEADERS frame would need to
+ identify the context to use for that frame. However, compression
+ contexts are not cheap, so the lifecycle of each context would need
+ to be bounded. For proxy servers, where we could churn through many
+ contexts, this would be a concern. We considered using a static set
+ of contexts, say 16 of them, which would bound the memory use. We
+ also considered dynamic contexts, which could be created on the fly,
+ and would need to be subsequently destroyed. All of these are
+ complicated, and ultimately we decided that such a mechanism creates
+ too many problems to solve.
+
+ Alternatively, we've chosen the simple approach, which is to simply
+ provide a flag for resetting the compression context. For the common
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 41]
+
+Internet-Draft SPDY Feb 2012
+
+
+ case (no proxy), this fine because most requests are to the same
+ origin and we never need to reset the context. For cases where we
+ are using two different origins over a single SPDY session, we simply
+ reset the compression state between each transition.
+
+4.6. Unidirectional streams
+
+ Many readers notice that unidirectional streams are both a bit
+ confusing in concept and also somewhat redundant. If the recipient
+ of a stream doesn't wish to send data on a stream, it could simply
+ send a SYN_REPLY with the FLAG_FIN bit set. The FLAG_UNIDIRECTIONAL
+ is, therefore, not necessary.
+
+ It is true that we don't need the UNIDIRECTIONAL markings. It is
+ added because it avoids the recipient of pushed streams from needing
+ to send a set of empty frames (e.g. the SYN_STREAM w/ FLAG_FIN) which
+ otherwise serve no purpose.
+
+4.7. Data Compression
+
+ Generic compression of data portion of the streams (as opposed to
+ compression of the headers) without knowing the content of the stream
+ is redundant. There is no value in compressing a stream which is
+ already compressed. Because of this, SPDY does allow data
+ compression to be optional. We included it because study of existing
+ websites shows that many sites are not using compression as they
+ should, and users suffer because of it. We wanted a mechanism where,
+ at the SPDY layer, site administrators could simply force compression
+ - it is better to compress twice than to not compress.
+
+ Overall, however, with this feature being optional and sometimes
+ redundant, it is unclear if it is useful at all. We will likely
+ remove it from the specification.
+
+4.8. Server Push
+
+ A subtle but important point is that server push streams must be
+ declared before the associated stream is closed. The reason for this
+ is so that proxies have a lifetime for which they can discard
+ information about previous streams. If a pushed stream could
+ associate itself with an already-closed stream, then endpoints would
+ not have a specific lifecycle for when they could disavow knowledge
+ of the streams which went before.
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 42]
+
+Internet-Draft SPDY Feb 2012
+
+
+5. Security Considerations
+
+5.1. Use of Same-origin constraints
+
+ This specification uses the same-origin policy [RFC6454] in all cases
+ where verification of content is required.
+
+5.2. HTTP Headers and SPDY Headers
+
+ At the application level, HTTP uses name/value pairs in its headers.
+ Because SPDY merges the existing HTTP headers with SPDY headers,
+ there is a possibility that some HTTP applications already use a
+ particular header name. To avoid any conflicts, all headers
+ introduced for layering HTTP over SPDY are prefixed with ":". ":" is
+ not a valid sequence in HTTP header naming, preventing any possible
+ conflict.
+
+5.3. Cross-Protocol Attacks
+
+ By utilizing TLS, we believe that SPDY introduces no new cross-
+ protocol attacks. TLS encrypts the contents of all transmission
+ (except the handshake itself), making it difficult for attackers to
+ control the data which could be used in a cross-protocol attack.
+
+5.4. Server Push Implicit Headers
+
+ Pushed resources do not have an associated request. In order for
+ existing HTTP cache control validations (such as the Vary header) to
+ work, however, all cached resources must have a set of request
+ headers. For this reason, browsers MUST be careful to inherit
+ request headers from the associated stream for the push. This
+ includes the 'Cookie' header.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 43]
+
+Internet-Draft SPDY Feb 2012
+
+
+6. Privacy Considerations
+
+6.1. Long Lived Connections
+
+ SPDY aims to keep connections open longer between clients and servers
+ in order to reduce the latency when a user makes a request. The
+ maintenance of these connections over time could be used to expose
+ private information. For example, a user using a browser hours after
+ the previous user stopped using that browser may be able to learn
+ about what the previous user was doing. This is a problem with HTTP
+ in its current form as well, however the short lived connections make
+ it less of a risk.
+
+6.2. SETTINGS frame
+
+ The SPDY SETTINGS frame allows servers to store out-of-band
+ transmitted information about the communication between client and
+ server on the client. Although this is intended only to be used to
+ reduce latency, renegade servers could use it as a mechanism to store
+ identifying information about the client in future requests.
+
+ Clients implementing privacy modes, such as Google Chrome's
+ "incognito mode", may wish to disable client-persisted SETTINGS
+ storage.
+
+ Clients MUST clear persisted SETTINGS information when clearing the
+ cookies.
+
+ TODO: Put range maximums on each type of setting to limit
+ inappropriate uses.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 44]
+
+Internet-Draft SPDY Feb 2012
+
+
+7. Incompatibilities with SPDY draft #2
+
+ Here is a list of the major changes between this draft and draft #2.
+
+ Addition of flow control
+
+ Increased 16 bit length fields in SYN_STREAM and SYN_REPLY to 32
+ bits.
+
+ Changed definition of compression for DATA frames
+
+ Updated compression dictionary
+
+ Fixed off-by-one on the compression dictionary for headers
+
+ Increased priority field from 2bits to 3bits.
+
+ Removed NOOP frame
+
+ Split the request "url" into "scheme", "host", and "path"
+
+ Added the requirement that POSTs contain content-length.
+
+ Removed wasted 16bits of unused space from the end of the
+ SYN_REPLY and HEADERS frames.
+
+ Fixed bug: Priorities were described backward (0 was lowest
+ instead of highest).
+
+ Fixed bug: Name/Value header counts were duplicated in both the
+ Name Value header block and also the containing frame.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 45]
+
+Internet-Draft SPDY Feb 2012
+
+
+8. Requirements Notation
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 46]
+
+Internet-Draft SPDY Feb 2012
+
+
+9. Acknowledgements
+
+ Many individuals have contributed to the design and evolution of
+ SPDY: Adam Langley, Wan-Teh Chang, Jim Morrison, Mark Nottingham,
+ Alyssa Wilk, Costin Manolache, William Chan, Vitaliy Lvin, Joe Chan,
+ Adam Barth, Ryan Hamilton, Gavin Peters, Kent Alstad, Kevin Lindsay,
+ Paul Amer, Fan Yang, Jonathan Leighton
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 47]
+
+Internet-Draft SPDY Feb 2012
+
+
+10. Normative References
+
+ [RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
+ RFC 793, September 1981.
+
+ [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform
+ Resource Locators (URL)", RFC 1738, December 1994.
+
+ [RFC1950] Deutsch, L. and J-L. Gailly, "ZLIB Compressed Data Format
+ Specification version 3.3", RFC 1950, May 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2285] Mandeville, R., "Benchmarking Terminology for LAN
+ Switching Devices", RFC 2285, February 1998.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A., and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication",
+ RFC 2617, June 1999.
+
+ [RFC4559] Jaganathan, K., Zhu, L., and J. Brezak, "SPNEGO-based
+ Kerberos and NTLM HTTP Authentication in Microsoft
+ Windows", RFC 4559, June 2006.
+
+ [RFC4366] Blake-Wilson, S., Nystrom, M., Hopwood, D., Mikkelsen, J.,
+ and T. Wright, "Transport Layer Security (TLS)
+ Extensions", RFC 4366, April 2006.
+
+ [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
+ (TLS) Protocol Version 1.2", RFC 5246, August 2008.
+
+ [RFC6454] Barth, A., "The Web Origin Concept", RFC 6454,
+ December 2011.
+
+ [TLSNPN] Langley, A., "TLS Next Protocol Negotiation",
+ <http://tools.ietf.org/html/
+ draft-agl-tls-nextprotoneg-01>.
+
+ [ASCII] "US-ASCII. Coded Character Set - 7-Bit American Standard
+ Code for Information Interchange. Standard ANSI X3.4-1986,
+ ANSI, 1986.".
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 48]
+
+Internet-Draft SPDY Feb 2012
+
+
+ [UDELCOMPRESSION]
+ Yang, F., Amer, P., and J. Leighton, "A Methodology to
+ Derive SPDY's Initial Dictionary for Zlib Compression",
+ <http://www.eecis.udel.edu/~amer/PEL/poc/pdf/
+ SPDY-Fan.pdf>.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 49]
+
+Internet-Draft SPDY Feb 2012
+
+
+Appendix A. Changes
+
+ To be removed by RFC Editor before publication
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 50]
+
+Internet-Draft SPDY Feb 2012
+
+
+Authors' Addresses
+
+ Mike Belshe
+ Twist
+
+ Email: address@hidden
+
+
+ Roberto Peon
+ Google, Inc
+
+ Email: address@hidden
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Belshe & Peon Expires August 4, 2012 [Page 51]
+
Added: libmicrohttpd/libmicrospdy.pc.in
===================================================================
--- libmicrohttpd/libmicrospdy.pc.in (rev 0)
+++ libmicrohttpd/libmicrospdy.pc.in 2013-05-05 19:21:40 UTC (rev 27030)
@@ -0,0 +1,13 @@
address@hidden@
address@hidden@
address@hidden@
address@hidden@
+
+Name: libmicrospdy
+Description: A library for creating an embedded SPDY server
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -lmicrospdy
+Libs.private: @SPDY_LIBDEPS@
+Cflags: -I${includedir}
Added: libmicrohttpd/m4/openssl.m4
===================================================================
--- libmicrohttpd/m4/openssl.m4 (rev 0)
+++ libmicrohttpd/m4/openssl.m4 2013-05-05 19:21:40 UTC (rev 27030)
@@ -0,0 +1,69 @@
+dnl Check to find the OpenSSL headers/libraries
+
+AC_DEFUN([spdy_OPENSSL],
+[
+ AC_ARG_WITH(openssl,
+ AS_HELP_STRING([--with-openssl=DIR], [OpenSSL base directory, or:]),
+ [openssl="$withval"
+ CPPFLAGS="$CPPFLAGS -I$withval/include"
+ LDFLAGS="$LDFLAGS -L$withval/lib"]
+ )
+
+ AC_ARG_WITH(openssl-include,
+ AS_HELP_STRING([--with-openssl-include=DIR], [OpenSSL headers directory
(without trailing /openssl)]),
+ [openssl_include="$withval"
+ CPPFLAGS="$CPPFLAGS -I$withval"]
+ )
+
+ AC_ARG_WITH(openssl-lib,
+ AS_HELP_STRING([--with-openssl-lib=DIR], [OpenSSL library directory]),
+ [openssl_lib="$withval"
+ LDFLAGS="$LDFLAGS -L$withval"]
+ )
+
+ AC_CHECK_HEADERS(openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h
openssl/sha.h openssl/pem.h openssl/engine.h,
+ [],
+ [AC_MSG_WARN([OpenSSL header files not found.]); break]
+ )
+
+case $host_os in
+ *mingw*)
+ AC_CHECK_LIB(crypto, SHA1_Init,
+ [LIBS="$LIBS -lcrypto -lgdi32"],
+ [AC_MSG_WARN([OpenSSL libraries not found.])]
+ )
+ ;;
+ *)
+
+ AC_CHECK_LIB(crypto, SHA1_Init,
+ [LIBS="$LIBS -lcrypto"],
+ [AC_MSG_WARN([OpenSSL libraries not found.])]
+ )
+
+ AC_CHECK_FUNC(dlopen,
+ [],
+ [AC_CHECK_LIB(dl, dlopen,
+ [LIBS="$LIBS -ldl"],
+ [AC_MSG_WARN([OpenSSL depends on libdl.]); break]
+ )]
+ )
+
+ AC_CHECK_FUNC(SSL_library_init,
+ [],
+ [AC_CHECK_LIB(ssl, SSL_library_init,
+ [LIBS="$LIBS -lssl"],
+ [AC_MSG_WARN([OpenSSL?.]); break]
+ )]
+ )
+ ;;
+esac
+
+# AC_CHECK_FUNCS([RAND_pseudo_bytes EVP_EncryptInit_ex], ,
+# [AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have
installed the latest version.]); break],
+# )
+
+# AC_CHECK_DECL([OpenSSL_add_all_algorithms], ,
+# [AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have
installed the latest version.]); break],
+# [#include <openssl/evp.h>]
+# )
+])
Modified: libmicrohttpd/src/Makefile.am
===================================================================
--- libmicrohttpd/src/Makefile.am 2013-05-05 18:48:18 UTC (rev 27029)
+++ libmicrohttpd/src/Makefile.am 2013-05-05 19:21:40 UTC (rev 27030)
@@ -6,4 +6,13 @@
endif
endif
endif
-SUBDIRS = include microhttpd examples $(curltests) $(zzuftests) .
+if ENABLE_SPDY
+# fixme: should test for spdylay before building testspdy!
+microspdy = microspdy testspdy
+endif
+
+SUBDIRS = include microhttpd $(microspdy) examples $(curltests) $(zzuftests) .
+
+EXTRA_DIST = \
+ datadir/cert-and-key.pem \
+ datadir/cert-and-key-for-wireshark.pem
Added: libmicrohttpd/src/datadir/cert-and-key-for-wireshark.pem
===================================================================
--- libmicrohttpd/src/datadir/cert-and-key-for-wireshark.pem
(rev 0)
+++ libmicrohttpd/src/datadir/cert-and-key-for-wireshark.pem 2013-05-05
19:21:40 UTC (rev 27030)
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDc1k7EFEspRcr6PdPmvAd02hBDUG2O5dDkoRK+6tgEBvQxsTxz
+50TGwJ8RbSV+qUOnncZBwhnI4i71QSEezMP6I6liRA+fUtdh3cZFvdDpxgU6P15y
+5JxfnnDeZJR5O4tfMxN99t34EOEMruZZ0CNYJJgbmIteE0hLI418oUs7cwIDAQAB
+AoGAW3WOLXrSHge/pp/QkLCyzdw5/AblONdJCkcDQnp0eEaA/8uNY9sWCtJfjpIL
+g0eKs3KOV1GR6DZ0iDIvC1h2mO6pwyrJhRYHKPO9pnx7xpv1T9zYTuVwoMfVjPfO
+UCWFedSsSKR76+oP0TrwPDqp3JoMFcAyAqZKMg2JrRUpL3ECQQD92cVSYxSEKwX3
+cHWXVp1mSkuRMR/KX70NC/9XpYr8FEjvtXBTkmp7oG3TaDwd6nhSAodtY+Zkseyj
+k5NXM6sNAkEA3rT6opc1YK0pL3uweg+AFP4lRUYrrft1bDELhLmVm9Nf4xEdTnDO
+IotiX4GYQ64Bm8J+yxVU204soGynVXbgfwJBALQLCqq+X0TGhvrSpnRqGET+mM4n
+u1Z7xMhGJBpz7TmQ4ZIya7K6fA+m3347xbeqHyB7brYlTrlIgIAcITqOCNkCQQDE
+3tuJC34mHi0ASqkw3a7t39R2rpdCT733jEuQYrY8b9id061CgDnZE7o8j0VY3uOR
+G5gWUp8W1r5gemxaAqJlAkEAwVImBKyKy3oIMsd3WsoqYCMBM+cpX8H2JAEEISPT
+Y5zSPZ7kT9JgY2zJwXf3qL+uG1oKZ6f0wn4BYujctTbXwQ==
+-----END RSA PRIVATE KEY-----
Added: libmicrohttpd/src/datadir/cert-and-key.pem
===================================================================
--- libmicrohttpd/src/datadir/cert-and-key.pem (rev 0)
+++ libmicrohttpd/src/datadir/cert-and-key.pem 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,34 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDc1k7EFEspRcr6PdPmvAd02hBDUG2O5dDkoRK+6tgEBvQxsTxz
+50TGwJ8RbSV+qUOnncZBwhnI4i71QSEezMP6I6liRA+fUtdh3cZFvdDpxgU6P15y
+5JxfnnDeZJR5O4tfMxN99t34EOEMruZZ0CNYJJgbmIteE0hLI418oUs7cwIDAQAB
+AoGAW3WOLXrSHge/pp/QkLCyzdw5/AblONdJCkcDQnp0eEaA/8uNY9sWCtJfjpIL
+g0eKs3KOV1GR6DZ0iDIvC1h2mO6pwyrJhRYHKPO9pnx7xpv1T9zYTuVwoMfVjPfO
+UCWFedSsSKR76+oP0TrwPDqp3JoMFcAyAqZKMg2JrRUpL3ECQQD92cVSYxSEKwX3
+cHWXVp1mSkuRMR/KX70NC/9XpYr8FEjvtXBTkmp7oG3TaDwd6nhSAodtY+Zkseyj
+k5NXM6sNAkEA3rT6opc1YK0pL3uweg+AFP4lRUYrrft1bDELhLmVm9Nf4xEdTnDO
+IotiX4GYQ64Bm8J+yxVU204soGynVXbgfwJBALQLCqq+X0TGhvrSpnRqGET+mM4n
+u1Z7xMhGJBpz7TmQ4ZIya7K6fA+m3347xbeqHyB7brYlTrlIgIAcITqOCNkCQQDE
+3tuJC34mHi0ASqkw3a7t39R2rpdCT733jEuQYrY8b9id061CgDnZE7o8j0VY3uOR
+G5gWUp8W1r5gemxaAqJlAkEAwVImBKyKy3oIMsd3WsoqYCMBM+cpX8H2JAEEISPT
+Y5zSPZ7kT9JgY2zJwXf3qL+uG1oKZ6f0wn4BYujctTbXwQ==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAo6gAwIBAgIJAIjfJkuxM1pAMA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV
+BAYTAkJHMQ4wDAYDVQQIEwVTb2ZpYTEOMAwGA1UEBxMFU29maWExCzAJBgNVBAoT
+AkFVMQ8wDQYDVQQDEwZBbmRyZXkxHjAcBgkqhkiG9w0BCQEWD3Jvb3RAZ29vZ2xl
+LmNvbTAeFw0xMjA5MDgxMTU2MzNaFw0xMzA5MDgxMTU2MzNaMGsxCzAJBgNVBAYT
+AkJHMQ4wDAYDVQQIEwVTb2ZpYTEOMAwGA1UEBxMFU29maWExCzAJBgNVBAoTAkFV
+MQ8wDQYDVQQDEwZBbmRyZXkxHjAcBgkqhkiG9w0BCQEWD3Jvb3RAZ29vZ2xlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3NZOxBRLKUXK+j3T5rwHdNoQ
+Q1BtjuXQ5KESvurYBAb0MbE8c+dExsCfEW0lfqlDp53GQcIZyOIu9UEhHszD+iOp
+YkQPn1LXYd3GRb3Q6cYFOj9ecuScX55w3mSUeTuLXzMTffbd+BDhDK7mWdAjWCSY
+G5iLXhNISyONfKFLO3MCAwEAAaOB0DCBzTAdBgNVHQ4EFgQUPp4dR3IT0t6bSE3Y
+b91MyHJU2+8wgZ0GA1UdIwSBlTCBkoAUPp4dR3IT0t6bSE3Yb91MyHJU2++hb6Rt
+MGsxCzAJBgNVBAYTAkJHMQ4wDAYDVQQIEwVTb2ZpYTEOMAwGA1UEBxMFU29maWEx
+CzAJBgNVBAoTAkFVMQ8wDQYDVQQDEwZBbmRyZXkxHjAcBgkqhkiG9w0BCQEWD3Jv
+b3RAZ29vZ2xlLmNvbYIJAIjfJkuxM1pAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
+AQEFBQADgYEAeBPoIRueOJ+SwpVniE2gmnvogWH9+irJnapDKGZrC/JsTA7ArqRd
+EHO1xZxqF+v+v128LmwWAdaazgMUHjR7e7B0xo4Tcp+9+voczc/GBTO0wnp6HT76
+2kUB6rPwwg9bycW8hAJiJJtr3IW5eYMtXDqM4RrbxhA1n2EAaZPVa5s=
+-----END CERTIFICATE-----
Modified: libmicrohttpd/src/examples/Makefile.am
===================================================================
--- libmicrohttpd/src/examples/Makefile.am 2013-05-05 18:48:18 UTC (rev
27029)
+++ libmicrohttpd/src/examples/Makefile.am 2013-05-05 19:21:40 UTC (rev
27030)
@@ -9,21 +9,33 @@
-I$(top_srcdir)/src/include \
@LIBGCRYPT_CFLAGS@
+AM_CFLAGS = -DDATADIR=\"$(top_srcdir)/src/datadir/\"
+
if USE_COVERAGE
- AM_CFLAGS = --coverage
+ AM_CFLAGS += --coverage
endif
+if ENABLE_SPDY
+spdyex = \
+ spdy_event_loop \
+ spdy_fileserver \
+ spdy_response_with_callback
+endif
+
+
# example programs
noinst_PROGRAMS = \
-minimal_example \
-dual_stack_example \
-minimal_example_comet \
-querystring_example \
-fileserver_example \
-fileserver_example_dirs \
-fileserver_example_external_select \
-refuse_post_example
+ minimal_example \
+ dual_stack_example \
+ minimal_example_comet \
+ querystring_example \
+ fileserver_example \
+ fileserver_example_dirs \
+ fileserver_example_external_select \
+ refuse_post_example \
+ $(spdyex)
+
if ENABLE_HTTPS
noinst_PROGRAMS += https_fileserver_example
endif
@@ -116,3 +128,31 @@
https_fileserver_example.c
https_fileserver_example_LDADD = \
$(top_builddir)/src/microhttpd/libmicrohttpd.la
+
+
+spdy_event_loop_SOURCES = \
+ spdy_event_loop.c
+spdy_event_loop_LDADD = \
+ $(top_builddir)/src/microspdy/libmicrospdy.la \
+ -lssl \
+ -lcrypto \
+ -lz \
+ -ldl
+
+spdy_fileserver_SOURCES = \
+ spdy_fileserver.c
+spdy_fileserver_LDADD = \
+ $(top_builddir)/src/microspdy/libmicrospdy.la \
+ -lssl \
+ -lcrypto \
+ -lz \
+ -ldl
+
+spdy_response_with_callback_SOURCES = \
+ spdy_response_with_callback.c
+spdy_response_with_callback_LDADD = \
+ $(top_builddir)/src/microspdy/libmicrospdy.la \
+ -lssl \
+ -lcrypto \
+ -lz \
+ -ldl
Added: libmicrohttpd/src/examples/spdy_event_loop.c
===================================================================
--- libmicrohttpd/src/examples/spdy_event_loop.c
(rev 0)
+++ libmicrohttpd/src/examples/spdy_event_loop.c 2013-05-05 19:21:40 UTC
(rev 27030)
@@ -0,0 +1,444 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file event_loop.c
+ * @brief shows how to use the daemon. THIS IS MAINLY A TEST AND DEBUG
+ * PROGRAM
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "microspdy.h"
+#include <sys/time.h>
+#include <time.h>
+#include <arpa/inet.h>
+//#include "../framinglayer/structures.h"
+//#include "../applicationlayer/alstructures.h"
+
+int run = 1;
+int run2 = 1;
+
+
+ uint64_t loops;
+ time_t start;
+
+
+void
+new_session_callback (void *cls,
+ struct SPDY_Session * session)
+{
+ char ipstr[1024];
+
+ struct sockaddr *addr;
+ socklen_t addr_len = SPDY_get_remote_addr(session, &addr);
+
+ if(!addr_len)
+ {
+ printf("SPDY_get_remote_addr");
+ abort();
+ }
+
+ if(AF_INET == addr->sa_family)
+ {
+ struct sockaddr_in * addr4 = (struct sockaddr_in *) addr;
+ if(NULL == inet_ntop(AF_INET, &(addr4->sin_addr), ipstr,
sizeof(ipstr)))
+ {
+ printf("inet_ntop");
+ abort();
+ }
+ printf("New connection from: %s:%i\n", ipstr,
ntohs(addr4->sin_port));
+
+ }
+ else if(AF_INET6 == addr->sa_family)
+ {
+ struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *) addr;
+ if(NULL == inet_ntop(AF_INET6, &(addr6->sin6_addr), ipstr,
sizeof(ipstr)))
+ {
+ printf("inet_ntop");
+ abort();
+ }
+ printf("New connection from: %s:%i\n", ipstr,
ntohs(addr6->sin6_port));
+
+ }
+}
+
+void
+session_closed_handler (void *cls,
+ struct SPDY_Session * session,
+ int by_client)
+{
+ //printf("session_closed_handler called\n");
+
+ if(SPDY_YES != by_client)
+ {
+ //killchild(child,"wrong by_client");
+ printf("session closed by server\n");
+ }
+ else
+ {
+ printf("session closed by client\n");
+ }
+
+ //session_closed_called = 1;
+}
+
+void
+response_done_callback(void *cls,
+ struct SPDY_Response *response,
+ struct SPDY_Request *request,
+ enum SPDY_RESPONSE_RESULT
status,
+ bool streamopened)
+{
+ (void)streamopened;
+ if(strcmp(cls, "/close (daemon1)") == 0)
+ run = 0;
+ else {
+ if(strcmp(cls, "/close (daemon2)") == 0) run2 = 0;
+ loops = 0;
+ start = time(NULL);
+ }
+ if(SPDY_RESPONSE_RESULT_SUCCESS != status)
+ {
+ printf("not sent frame cause %i", status);
+ }
+ printf("answer for %s was sent\n", (char*)cls);
+ //printf("raw sent headers %s\n", (char *)(response->headers)+8);
+
+ SPDY_destroy_request(request);
+ SPDY_destroy_response(response);
+ free(cls);
+}
+
+int
+print_headers (void *cls,
+ const char *name, const char *value)
+{
+ (void)cls;
+ printf("%s: %s\n",name,value);
+ return SPDY_YES;
+}
+
+/*
+void
+new_request_cb (void *cls,
+ struct SPDY_Request * request,
+ uint8_t priority,
+ const char *method,
+ const char *path,
+ const char *version,
+ const char *host,
+ const char *scheme,
+ struct SPDY_NameValue * headers)
+{
+ (void)cls;
+ (void)request;
+ printf("Priority: %i\nHTTP headers, scheme: %s\n\n%s %s %s\nHost:
%s\n", priority,scheme,method,path,version,host);
+ SPDY_name_value_iterate(headers, &print_headers, NULL);
+}
+*/
+
+int
+append_headers_to_data (void *cls,
+ const char *name, const char **value, int
num_values)
+{
+ char **data = (char **)cls;
+ void *tofree = *data;
+ int i;
+
+ if(num_values)
+ for(i=0;i<num_values;++i)
+ {
+ asprintf(data,"%s%s: %s\n", *data,name,value[i]);
+ }
+ else
+ asprintf(data,"%s%s: \n", *data,name);
+
+ free(tofree);
+ return SPDY_YES;
+}
+
+void
+standard_request_handler(void *cls,
+ struct SPDY_Request * request,
+ uint8_t priority,
+ const char *method,
+ const char *path,
+ const char *version,
+ const char *host,
+ const char *scheme,
+ struct SPDY_NameValue * headers)
+{
+ char *html;
+ char *data;
+ struct SPDY_Response *response=NULL;
+
+ printf("received request for '%s %s %s'\n", method, path, version);
+ if(strcmp(path,"/main.css")==0)
+ {
+ if(NULL != cls)
+ asprintf(&html,"body{color:green;}");
+ else
+ asprintf(&html,"body{color:red;}");
+
+ //struct SPDY_NameValue *headers=SPDY_name_value_create();
+ //SPDY_name_value_add(headers,"content-type","text/css");
+
+ response =
SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
+ free(html);
+ }
+ else
+ {
+ asprintf(&data,"Priority: %i\nHTTP headers, scheme: %s\n\n%s %s
%s\nHost: %s\n", priority,scheme,method,path,version,host);
+
+ SPDY_name_value_iterate(headers, &append_headers_to_data,
&data);
+
+ if(strcmp(path,"/close")==0)
+ {
+ asprintf(&html,"<html>"
+ "<body><b>Closing now!<br>This is an answer to the following "
+ "request:</b><br><br><pre>%s</pre></body></html>",data);
+ }
+ else
+ {
+ asprintf(&html,"<html><link href=\"main.css\"
rel=\"stylesheet\" type=\"text/css\" />"
+ "<body><b>This is an answer to the following "
+ "request:</b><br><br><pre>%s</pre></body></html>",data);
+ }
+
+ free(data);
+
+ response =
SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
+ free(html);
+ }
+
+ if(NULL==response){
+ fprintf(stdout,"no response obj\n");
+ abort();
+ }
+
+ char *pathcls;
+ asprintf(&pathcls, "%s (daemon%i)",path,NULL==cls ? 1 : 2);
+
if(SPDY_queue_response(request,response,true,false,&response_done_callback,pathcls)!=SPDY_YES)
+ {
+ fprintf(stdout,"queue\n");
+ abort();
+ }
+}
+
+void sig_handler(int signo)
+{
+ printf("received signal\n");
+}
+
+int
+main (int argc, char *const *argv)
+{
+ if(argc != 2) return 1;
+
+ if (signal(SIGPIPE, sig_handler) == SIG_ERR)
+ printf("\ncan't catch SIGPIPE\n");
+
+ SPDY_init();
+
+ struct sockaddr_in addr4;
+ struct in_addr inaddr4;
+ inaddr4.s_addr = htonl(INADDR_ANY);
+ addr4.sin_family = AF_INET;
+ addr4.sin_addr = inaddr4;
+ addr4.sin_port = htons(atoi(argv[1]));
+
+ struct SPDY_Daemon *daemon = SPDY_start_daemon(atoi(argv[1]),
+ DATADIR "cert-and-key.pem",
+ DATADIR "cert-and-key.pem",
+
&new_session_callback,&session_closed_handler,&standard_request_handler,NULL,NULL,
+ SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 10,
+ //SPDY_DAEMON_OPTION_SOCK_ADDR, (struct sockaddr *)&addr4,
+ SPDY_DAEMON_OPTION_END);
+
+ if(NULL==daemon){
+ printf("no daemon\n");
+ return 1;
+ }
+
+ struct sockaddr_in6 addr6;
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_addr = in6addr_any;
+ addr6.sin6_port = htons(atoi(argv[1]) + 1);
+
+ struct SPDY_Daemon *daemon2 = SPDY_start_daemon(atoi(argv[1]) + 1,
+ DATADIR "cert-and-key.pem",
+ DATADIR "cert-and-key.pem",
+ &new_session_callback,NULL,&standard_request_handler,NULL,&main,
+ //SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 0,
+ //SPDY_DAEMON_OPTION_SOCK_ADDR, (struct sockaddr *)&addr6,
+ //SPDY_DAEMON_OPTION_FLAGS, SPDY_DAEMON_FLAG_ONLY_IPV6,
+ SPDY_DAEMON_OPTION_END);
+
+ if(NULL==daemon2){
+ printf("no daemon\n");
+ return 1;
+ }
+
+ do
+ {
+ unsigned long long timeoutlong=0;
+ struct timeval timeout;
+ volatile int rc; /* select() return code */
+ volatile int ret;
+
+ fd_set read_fd_set;
+ fd_set write_fd_set;
+ fd_set except_fd_set;
+ int maxfd = -1;
+
+ if(run && daemon != NULL)
+ {
+ loops++;
+ FD_ZERO(&read_fd_set);
+ FD_ZERO(&write_fd_set);
+ FD_ZERO(&except_fd_set);
+
+ ret = SPDY_get_timeout(daemon, &timeoutlong);
+ //printf("tout %i\n",timeoutlong);
+ if(SPDY_NO == ret || timeoutlong > 1)
+ {
+ //do sth else
+ //sleep(1);
+
+ //try new connection
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ }
+ else
+ {
+ timeout.tv_sec = timeoutlong;
+ timeout.tv_usec = 0;//(timeoutlong % 1000) * 1000;
+ }
+
+ printf("ret=%i; timeoutlong=%i; sec=%i; usec=%i\n", ret,
timeoutlong, timeout.tv_sec, timeout.tv_usec);
+ //raise(SIGINT);
+
+ /* get file descriptors from the transfers */
+ maxfd = SPDY_get_fdset (daemon,
+ &read_fd_set,
+ &write_fd_set,
+ &except_fd_set);
+
+//struct timeval ts1,ts2;
+ //gettimeofday(&ts1, NULL);
+ rc = select(maxfd+1, &read_fd_set, &write_fd_set,
&except_fd_set, &timeout);
+ //gettimeofday(&ts2, NULL);
+ printf("rc %i\n",rc);
+ // printf("time for select %i\n",ts2.tv_usec - ts1.tv_usec);
+ // printf("%i %i %i %i\n",ts1.tv_sec, ts1.tv_usec,ts2.tv_sec, ts2.tv_usec);
+
+ switch(rc) {
+ case -1:
+ /* select error */
+ break;
+ case 0:
+
+ break;
+ default:
+ SPDY_run(daemon);
+
+ break;
+ }
+ }
+ else if(daemon != NULL){
+
+ printf("%i loops in %i secs\n", loops, time(NULL) - start);
+ SPDY_stop_daemon(daemon);
+ daemon=NULL;
+ }
+
+ if(run2)
+ {
+ FD_ZERO(&read_fd_set);
+ FD_ZERO(&write_fd_set);
+ FD_ZERO(&except_fd_set);
+
+ ret = SPDY_get_timeout(daemon2, &timeoutlong);
+ //printf("tout %i\n",timeoutlong);
+ if(SPDY_NO == ret || timeoutlong > 1)
+ {
+ //do sth else
+ //sleep(1);
+
+ //try new connection
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ }
+ else
+ {
+ timeout.tv_sec = timeoutlong;
+ timeout.tv_usec = 0;//(timeoutlong % 1000) * 1000;
+ }
+
+ //printf("ret=%i; timeoutlong=%i; sec=%i; usec=%i\n", ret,
timeoutlong, timeout.tv_sec, timeout.tv_usec);
+ //raise(SIGINT);
+
+ /* get file descriptors from the transfers */
+ maxfd = SPDY_get_fdset (daemon2,
+ &read_fd_set,
+ &write_fd_set,
+ &except_fd_set);
+
+ rc = select(maxfd+1, &read_fd_set, &write_fd_set,
&except_fd_set, &timeout);
+
+ switch(rc) {
+ case -1:
+ /* select error */
+ break;
+ case 0:
+
+ break;
+ default:
+ SPDY_run(daemon2);
+
+ break;
+ }
+ }
+ else if(daemon2 != NULL){
+ SPDY_stop_daemon(daemon2);
+ daemon2=NULL;
+ }
+ }
+ while(run || run2);
+
+ if(daemon != NULL){
+ SPDY_stop_daemon(daemon);
+ }
+ if(daemon2 != NULL){
+ SPDY_stop_daemon(daemon2);
+ }
+
+ SPDY_deinit();
+
+ return 0;
+}
+
Added: libmicrohttpd/src/examples/spdy_fileserver.c
===================================================================
--- libmicrohttpd/src/examples/spdy_fileserver.c
(rev 0)
+++ libmicrohttpd/src/examples/spdy_fileserver.c 2013-05-05 19:21:40 UTC
(rev 27030)
@@ -0,0 +1,340 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2013 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file fileserver.c
+ * @brief Simple example how the lib can be used for serving
+ * files directly read from the system
+ * @author Andrey Uzunov
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "microspdy.h"
+#include "time.h"
+
+
+int run = 1;
+char* basedir;
+
+
+#define GET_MIME_TYPE(fname, mime) do {\
+ uint __len = strlen(fname);\
+ if (__len < 4 || '.' != (fname)[__len - 4]) break;\
+ const char * __ext = &(fname)[__len - 3];\
+ if(0 == strcmp(__ext, "jpg")) (mime) = strdup("image/jpeg");\
+ else if(0 == strcmp(__ext, "png")) (mime) =
strdup("image/png");\
+ else if(0 == strcmp(__ext, "css")) (mime) = strdup("text/css");\
+ else if(0 == strcmp(__ext, "gif")) (mime) =
strdup("image/gif");\
+ else if(0 == strcmp(__ext, "htm")) (mime) =
strdup("text/html");\
+ else \
+ { \
+ (mime) = strdup("application/octet-stream");\
+ printf("MIME for %s is applic...\n", (fname));\
+ }\
+ if(NULL == (mime))\
+ {\
+ printf("no memory\n");\
+ abort();\
+ }\
+ } while (0)
+
+
+static const char *DAY_NAMES[] =
+ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+
+static const char *MONTH_NAMES[] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+//taken from
http://stackoverflow.com/questions/2726975/how-can-i-generate-an-rfc1123-date-string-from-c-code-win32
+//and modified for linux
+char *Rfc1123_DateTimeNow()
+{
+ const int RFC1123_TIME_LEN = 29;
+ time_t t;
+ struct tm tm;
+ char * buf = malloc(RFC1123_TIME_LEN+1);
+
+ time(&t);
+ gmtime_r( &t, &tm);
+
+ strftime(buf, RFC1123_TIME_LEN+1, "---, %d --- %Y %H:%M:%S GMT", &tm);
+ memcpy(buf, DAY_NAMES[tm.tm_wday], 3);
+ memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
+
+ return buf;
+}
+
+
+ssize_t
+response_callback (void *cls,
+ void *buffer,
+ size_t max,
+ bool *more)
+{
+ FILE *fd =(FILE*)cls;
+
+ int ret = fread(buffer,1,max,fd);
+ *more = feof(fd) == 0;
+
+ //if(!(*more))
+ // fclose(fd);
+
+ return ret;
+}
+
+
+void
+response_done_callback(void *cls,
+ struct SPDY_Response *response,
+ struct SPDY_Request *request,
+ enum SPDY_RESPONSE_RESULT
status,
+ bool streamopened)
+{
+ (void)streamopened;
+ //printf("answer for %s was sent\n", (char *)cls);
+
+ /*if(SPDY_RESPONSE_RESULT_SUCCESS != status)
+ {
+ printf("answer for %s was NOT sent, %i\n", (char *)cls,status);
+ }*/
+
+ SPDY_destroy_request(request);
+ SPDY_destroy_response(response);
+ if(NULL!=cls)fclose(cls);
+}
+
+void
+standard_request_handler(void *cls,
+ struct SPDY_Request * request,
+ uint8_t priority,
+ const char *method,
+ const char *path,
+ const char *version,
+ const char *host,
+ const char *scheme,
+ struct SPDY_NameValue * headers)
+{
+ (void)cls;
+ (void)request;
+ (void)priority;
+ (void)host;
+ (void)scheme;
+ (void)headers;
+
+ struct SPDY_Response *response=NULL;
+ struct SPDY_NameValue *resp_headers;
+ char *fname;
+ char *fsize;
+ char *mime=NULL;
+ char *date=NULL;
+ ssize_t filesize = -666;
+ FILE *fd = NULL;
+ int ret = -666;
+
+ //printf("received request for '%s %s %s'\n", method, path, version);
+ if(strlen(path) > 1 && NULL == strstr(path, "..") && '/' == path[0])
+ {
+ asprintf(&fname,"%s%s",basedir,path);
+ if(0 == access(fname, R_OK))
+ {
+ if(NULL == (fd = fopen(fname,"r"))
+ || 0 != (ret = fseek(fd, 0L, SEEK_END))
+ || -1 == (filesize = ftell(fd))
+ || 0 != (ret = fseek(fd, 0L, SEEK_SET)))
+ {
+ printf("Error on opening %s\n%i %i %i\n",fname,
fd, ret, filesize);
+ response =
SPDY_build_response(SPDY_HTTP_INTERNAL_SERVER_ERROR,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
+ }
+ else
+ {
+ if(NULL == (resp_headers =
SPDY_name_value_create()))
+ {
+ printf("SPDY_name_value_create
failed\n");
+ abort();
+ }
+
+ date = Rfc1123_DateTimeNow();
+ if(NULL == date
+ || SPDY_YES !=
SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_DATE,date))
+ {
+ printf("SPDY_name_value_add or
Rfc1123_DateTimeNow failed\n");
+ abort();
+ }
+ free(date);
+
+ if(-1 == asprintf(&fsize, "%i", filesize)
+ || SPDY_YES !=
SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_LENGTH,fsize))
+ {
+ printf("SPDY_name_value_add or asprintf
failed\n");
+ abort();
+ }
+ free(fsize);
+
+ GET_MIME_TYPE(path,mime);
+ if(SPDY_YES !=
SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,mime))
+ {
+ printf("SPDY_name_value_add failed\n");
+ abort();
+ }
+ free(mime);
+
+ if(SPDY_YES !=
SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_SERVER,"libmicrospdy/fileserver"))
+ {
+ printf("SPDY_name_value_add failed\n");
+ abort();
+ }
+
+ response =
SPDY_build_response_with_callback(200,NULL,
+
SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
+ SPDY_name_value_destroy(resp_headers);
+ }
+
+ if(NULL==response){
+ printf("no response obj\n");
+ abort();
+ }
+
+
if(SPDY_queue_response(request,response,true,false,&response_done_callback,fd)!=SPDY_YES)
+ {
+ printf("queue\n");
+ abort();
+ }
+
+ free(fname);
+ return;
+ }
+ free(fname);
+ }
+
+ if(strcmp(path,"/close")==0)
+ {
+ run = 0;
+ }
+
+ response =
SPDY_build_response(SPDY_HTTP_NOT_FOUND,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
+ printf("Not found %s\n",path);
+
+ if(NULL==response){
+ printf("no response obj\n");
+ abort();
+ }
+
+
if(SPDY_queue_response(request,response,true,false,&response_done_callback,NULL)!=SPDY_YES)
+ {
+ printf("queue\n");
+ abort();
+ }
+}
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned long long timeoutlong=0;
+ struct timeval timeout;
+ int ret;
+ fd_set read_fd_set;
+ fd_set write_fd_set;
+ fd_set except_fd_set;
+ int maxfd = -1;
+ struct SPDY_Daemon *daemon;
+
+ if(argc != 5)
+ {
+ printf("Usage: %s cert-file key-file base-dir port\n", argv[0]);
+ return 1;
+ }
+
+ SPDY_init();
+
+ daemon = SPDY_start_daemon(atoi(argv[4]),
+ argv[1],
+ argv[2],
+ NULL,
+ NULL,
+
&standard_request_handler,
+ NULL,
+ NULL,
+
SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
+ 1800,
+
SPDY_DAEMON_OPTION_END);
+
+ if(NULL==daemon){
+ printf("no daemon\n");
+ return 1;
+ }
+
+ basedir = argv[3];
+ timeout.tv_usec = 0;
+
+ do
+ {
+ FD_ZERO(&read_fd_set);
+ FD_ZERO(&write_fd_set);
+ FD_ZERO(&except_fd_set);
+
+ ret = SPDY_get_timeout(daemon, &timeoutlong);
+ if(SPDY_NO == ret || timeoutlong > 1)
+ {
+ //do sth else
+ //sleep(1);
+
+ //try new connection
+ timeout.tv_sec = 1;
+ }
+ else
+ {
+ timeout.tv_sec = timeoutlong;
+ }
+
+ maxfd = SPDY_get_fdset (daemon,
+ &read_fd_set,
+ &write_fd_set,
+ &except_fd_set);
+
+ ret = select(maxfd+1, &read_fd_set, &write_fd_set,
&except_fd_set, &timeout);
+
+ switch(ret) {
+ case -1:
+ printf("select error: %i\n", errno);
+ break;
+ case 0:
+
+ break;
+ default:
+ SPDY_run(daemon);
+
+ break;
+ }
+ }
+ while(run);
+
+ SPDY_stop_daemon(daemon);
+
+ SPDY_deinit();
+
+ return 0;
+}
+
Added: libmicrohttpd/src/examples/spdy_response_with_callback.c
===================================================================
--- libmicrohttpd/src/examples/spdy_response_with_callback.c
(rev 0)
+++ libmicrohttpd/src/examples/spdy_response_with_callback.c 2013-05-05
19:21:40 UTC (rev 27030)
@@ -0,0 +1,230 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2013 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file response_with_callback.c
+ * @brief shows how to create responses with callbacks
+ * @author Andrey Uzunov
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "microspdy.h"
+
+int run = 1;
+
+
+ssize_t
+response_callback (void *cls,
+ void *buffer,
+ size_t max,
+ bool *more)
+{
+ FILE *fd =(FILE*)cls;
+
+ int ret = fread(buffer,1,max,fd);
+ *more = feof(fd) == 0;
+
+ if(!(*more))
+ fclose(fd);
+
+ return ret;
+}
+
+
+void
+response_done_callback(void *cls,
+ struct SPDY_Response *response,
+ struct SPDY_Request *request,
+ bool streamopened)
+{
+ (void)streamopened;
+ printf("answer for %s was sent\n", (char *)cls);
+
+ SPDY_destroy_request(request);
+ SPDY_destroy_response(response);
+ free(cls);
+}
+
+void
+standard_request_handler(void *cls,
+ struct SPDY_Request * request,
+ uint8_t priority,
+ const char *method,
+ const char *path,
+ const char *version,
+ const char *host,
+ const char *scheme,
+ struct SPDY_NameValue * headers)
+{
+ (void)cls;
+ (void)request;
+ (void)priority;
+ (void)host;
+ (void)scheme;
+ (void)headers;
+
+ char *html;
+ struct SPDY_Response *response=NULL;
+ struct SPDY_NameValue *resp_headers;
+
+ printf("received request for '%s %s %s'\n", method, path, version);
+ if(strcmp(path,"/spdy-draft.txt")==0)
+ {
+ FILE *fd = fopen(DATADIR "spdy-draft.txt","r");
+
+ if(NULL == (resp_headers = SPDY_name_value_create()))
+ {
+ fprintf(stdout,"SPDY_name_value_create failed\n");
+ abort();
+ }
+ if(SPDY_YES !=
SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,"text/plain"))
+ {
+ fprintf(stdout,"SPDY_name_value_add failed\n");
+ abort();
+ }
+
+ response = SPDY_build_response_with_callback(200,NULL,
+
SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
+ SPDY_name_value_destroy(resp_headers);
+ }
+ else
+ {
+ if(strcmp(path,"/close")==0)
+ {
+ asprintf(&html,"<html>"
+ "<body><b>Closing now!</body></html>");
+ run = 0;
+ }
+ else
+ {
+ asprintf(&html,"<html>"
+ "<body><a
href=\"/spdy-draft.txt\">/spdy-draft.txt</a><br></body></html>");
+ }
+
+ response =
SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
+ free(html);
+ }
+
+ if(NULL==response){
+ fprintf(stdout,"no response obj\n");
+ abort();
+ }
+
+ void *clspath = strdup(path);
+
+
if(SPDY_queue_response(request,response,true,false,&response_done_callback,clspath)!=SPDY_YES)
+ {
+ fprintf(stdout,"queue\n");
+ abort();
+ }
+}
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned long long timeoutlong=0;
+ struct timeval timeout;
+ int ret;
+ fd_set read_fd_set;
+ fd_set write_fd_set;
+ fd_set except_fd_set;
+ int maxfd = -1;
+ struct SPDY_Daemon *daemon;
+
+ if(argc != 2)
+ {
+ return 1;
+ }
+
+ SPDY_init();
+
+ daemon = SPDY_start_daemon(atoi(argv[1]),
+ DATADIR
"cert-and-key.pem",
+ DATADIR
"cert-and-key.pem",
+ NULL,
+ NULL,
+
&standard_request_handler,
+ NULL,
+ NULL,
+
SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
+ 1800,
+
SPDY_DAEMON_OPTION_END);
+
+ if(NULL==daemon){
+ printf("no daemon\n");
+ return 1;
+ }
+
+ timeout.tv_usec = 0;
+
+ do
+ {
+ FD_ZERO(&read_fd_set);
+ FD_ZERO(&write_fd_set);
+ FD_ZERO(&except_fd_set);
+
+ ret = SPDY_get_timeout(daemon, &timeoutlong);
+ if(SPDY_NO == ret || timeoutlong > 1)
+ {
+ //do sth else
+ //sleep(1);
+
+ //try new connection
+ timeout.tv_sec = 1;
+ }
+ else
+ {
+ timeout.tv_sec = timeoutlong;
+ }
+
+ maxfd = SPDY_get_fdset (daemon,
+ &read_fd_set,
+ &write_fd_set,
+ &except_fd_set);
+
+ ret = select(maxfd+1, &read_fd_set, &write_fd_set,
&except_fd_set, &timeout);
+
+ switch(ret) {
+ case -1:
+ printf("select error: %i\n", errno);
+ break;
+ case 0:
+
+ break;
+ default:
+ SPDY_run(daemon);
+
+ break;
+ }
+ }
+ while(run);
+
+ SPDY_stop_daemon(daemon);
+
+ SPDY_deinit();
+
+ return 0;
+}
+
Modified: libmicrohttpd/src/include/Makefile.am
===================================================================
--- libmicrohttpd/src/include/Makefile.am 2013-05-05 18:48:18 UTC (rev
27029)
+++ libmicrohttpd/src/include/Makefile.am 2013-05-05 19:21:40 UTC (rev
27030)
@@ -1,4 +1,9 @@
SUBDIRS = plibc .
-include_HEADERS = microhttpd.h
+if ENABLE_SPDY
+microspdy = microspdy.h
+endif
+
+include_HEADERS = microhttpd.h $(microspdy)
+
EXTRA_DIST = platform.h
Added: libmicrohttpd/src/include/microspdy.h
===================================================================
--- libmicrohttpd/src/include/microspdy.h (rev 0)
+++ libmicrohttpd/src/include/microspdy.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,1275 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012, 2013 Christian Grothoff
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microspdy.h
+ * @brief public interface to libmicrospdy
+ * @author Andrey Uzunov
+ * @author Christian Grothoff
+ *
+ * All symbols defined in this header start with SPDY_. libmisrospdy is a
small
+ * SPDY daemon library. The application can start multiple daemons
+ * and they are independent.<p>
+ *
+ * The header file defines various constants used by the SPDY and the HTTP
protocol.
+ * This does not mean that the lib actually interprets all of these
+ * values. Not everything is implemented. The provided constants are exported
as a convenience
+ * for users of the library. The lib does not verify that provided
+ * HTTP headers and if their values conform to the SPDY protocol,
+ * it only checks if the required headers for the SPDY requests and
+ * responses are provided.<p>
+ *
+ * The library uses just a single thread.<p>
+ *
+ * Before including "microspdy.h" you should add the necessary
+ * includes to define the types used in this file (which headers are needed may
+ * depend on your platform; for possible suggestions consult
+ * "platform.h" in the libmicrospdy distribution).<p>
+ *
+ * All of the functions returning SPDY_YES/SPDY_NO return
+ * SPDY_INPUT_ERROR when any of the parameters are invalid, e.g.,
+ * required parameter is NULL.
+ */
+#ifndef SPDY_MICROSPDY_H
+#define SPDY_MICROSPDY_H
+
+#include <zlib.h>
+#include <stdbool.h>
+
+/**
+ * return code for "YES".
+ */
+#define SPDY_YES 1
+
+/**
+ * return code for "NO".
+ */
+#define SPDY_NO 0
+
+/**
+ * return code for error when input parameters are wrong. To be returned
+ * only by functions which return int. The others will return NULL on
+ * input error.
+ */
+#define SPDY_INPUT_ERROR -1
+
+/**
+ * SPDY version supported by the lib.
+ */
+#define SPDY_VERSION 3
+
+/**
+ * The maximum allowed size (without 8 byte headers) of
+ * SPDY frames (value length) is 8192. The lib will accept and
+ * send frames with length at most this value here.
+ */
+#define SPDY_MAX_SUPPORTED_FRAME_SIZE 8192
+
+/**
+ * HTTP response codes.
+ */
+#define SPDY_HTTP_CONTINUE 100
+#define SPDY_HTTP_SWITCHING_PROTOCOLS 101
+#define SPDY_HTTP_PROCESSING 102
+
+#define SPDY_HTTP_OK 200
+#define SPDY_HTTP_CREATED 201
+#define SPDY_HTTP_ACCEPTED 202
+#define SPDY_HTTP_NON_AUTHORITATIVE_INFORMATION 203
+#define SPDY_HTTP_NO_CONTENT 204
+#define SPDY_HTTP_RESET_CONTENT 205
+#define SPDY_HTTP_PARTIAL_CONTENT 206
+#define SPDY_HTTP_MULTI_STATUS 207
+
+#define SPDY_HTTP_MULTIPLE_CHOICES 300
+#define SPDY_HTTP_MOVED_PERMANENTLY 301
+#define SPDY_HTTP_FOUND 302
+#define SPDY_HTTP_SEE_OTHER 303
+#define SPDY_HTTP_NOT_MODIFIED 304
+#define SPDY_HTTP_USE_PROXY 305
+#define SPDY_HTTP_SWITCH_PROXY 306
+#define SPDY_HTTP_TEMPORARY_REDIRECT 307
+
+#define SPDY_HTTP_BAD_REQUEST 400
+#define SPDY_HTTP_UNAUTHORIZED 401
+#define SPDY_HTTP_PAYMENT_REQUIRED 402
+#define SPDY_HTTP_FORBIDDEN 403
+#define SPDY_HTTP_NOT_FOUND 404
+#define SPDY_HTTP_METHOD_NOT_ALLOWED 405
+#define SPDY_HTTP_METHOD_NOT_ACCEPTABLE 406
+#define SPDY_HTTP_PROXY_AUTHENTICATION_REQUIRED 407
+#define SPDY_HTTP_REQUEST_TIMEOUT 408
+#define SPDY_HTTP_CONFLICT 409
+#define SPDY_HTTP_GONE 410
+#define SPDY_HTTP_LENGTH_REQUIRED 411
+#define SPDY_HTTP_PRECONDITION_FAILED 412
+#define SPDY_HTTP_REQUEST_ENTITY_TOO_LARGE 413
+#define SPDY_HTTP_REQUEST_URI_TOO_LONG 414
+#define SPDY_HTTP_UNSUPPORTED_MEDIA_TYPE 415
+#define SPDY_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416
+#define SPDY_HTTP_EXPECTATION_FAILED 417
+#define SPDY_HTTP_UNPROCESSABLE_ENTITY 422
+#define SPDY_HTTP_LOCKED 423
+#define SPDY_HTTP_FAILED_DEPENDENCY 424
+#define SPDY_HTTP_UNORDERED_COLLECTION 425
+#define SPDY_HTTP_UPGRADE_REQUIRED 426
+#define SPDY_HTTP_NO_RESPONSE 444
+#define SPDY_HTTP_RETRY_WITH 449
+#define SPDY_HTTP_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS 450
+#define SPDY_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS 451
+
+#define SPDY_HTTP_INTERNAL_SERVER_ERROR 500
+#define SPDY_HTTP_NOT_IMPLEMENTED 501
+#define SPDY_HTTP_BAD_GATEWAY 502
+#define SPDY_HTTP_SERVICE_UNAVAILABLE 503
+#define SPDY_HTTP_GATEWAY_TIMEOUT 504
+#define SPDY_HTTP_HTTP_VERSION_NOT_SUPPORTED 505
+#define SPDY_HTTP_VARIANT_ALSO_NEGOTIATES 506
+#define SPDY_HTTP_INSUFFICIENT_STORAGE 507
+#define SPDY_HTTP_BANDWIDTH_LIMIT_EXCEEDED 509
+#define SPDY_HTTP_NOT_EXTENDED 510
+
+/**
+ * HTTP headers are used in SPDY, but all of them MUST be lowercase.
+ * Some are not valid in SPDY and MUST not be used
+ */
+#define SPDY_HTTP_HEADER_ACCEPT "accept"
+#define SPDY_HTTP_HEADER_ACCEPT_CHARSET "accept-charset"
+#define SPDY_HTTP_HEADER_ACCEPT_ENCODING "accept-encoding"
+#define SPDY_HTTP_HEADER_ACCEPT_LANGUAGE "accept-language"
+#define SPDY_HTTP_HEADER_ACCEPT_RANGES "accept-ranges"
+#define SPDY_HTTP_HEADER_AGE "age"
+#define SPDY_HTTP_HEADER_ALLOW "allow"
+#define SPDY_HTTP_HEADER_AUTHORIZATION "authorization"
+#define SPDY_HTTP_HEADER_CACHE_CONTROL "cache-control"
+/* Connection header is forbidden in SPDY */
+#define SPDY_HTTP_HEADER_CONNECTION "connection"
+#define SPDY_HTTP_HEADER_CONTENT_ENCODING "content-encoding"
+#define SPDY_HTTP_HEADER_CONTENT_LANGUAGE "content-language"
+#define SPDY_HTTP_HEADER_CONTENT_LENGTH "content-length"
+#define SPDY_HTTP_HEADER_CONTENT_LOCATION "content-location"
+#define SPDY_HTTP_HEADER_CONTENT_MD5 "content-md5"
+#define SPDY_HTTP_HEADER_CONTENT_RANGE "content-range"
+#define SPDY_HTTP_HEADER_CONTENT_TYPE "content-type"
+#define SPDY_HTTP_HEADER_COOKIE "cookie"
+#define SPDY_HTTP_HEADER_DATE "date"
+#define SPDY_HTTP_HEADER_ETAG "etag"
+#define SPDY_HTTP_HEADER_EXPECT "expect"
+#define SPDY_HTTP_HEADER_EXPIRES "expires"
+#define SPDY_HTTP_HEADER_FROM "from"
+/* Host header is forbidden in SPDY */
+#define SPDY_HTTP_HEADER_HOST "host"
+#define SPDY_HTTP_HEADER_IF_MATCH "if-match"
+#define SPDY_HTTP_HEADER_IF_MODIFIED_SINCE "if-modified-since"
+#define SPDY_HTTP_HEADER_IF_NONE_MATCH "if-none-match"
+#define SPDY_HTTP_HEADER_IF_RANGE "if-range"
+#define SPDY_HTTP_HEADER_IF_UNMODIFIED_SINCE "if-unmodified-since"
+/* Keep-Alive header is forbidden in SPDY */
+#define SPDY_HTTP_HEADER_KEEP_ALIVE "keep-alive"
+#define SPDY_HTTP_HEADER_LAST_MODIFIED "last-modified"
+#define SPDY_HTTP_HEADER_LOCATION "location"
+#define SPDY_HTTP_HEADER_MAX_FORWARDS "max-forwards"
+#define SPDY_HTTP_HEADER_PRAGMA "pragma"
+#define SPDY_HTTP_HEADER_PROXY_AUTHENTICATE "proxy-authenticate"
+#define SPDY_HTTP_HEADER_PROXY_AUTHORIZATION "proxy-authorization"
+/* Proxy-Connection header is forbidden in SPDY */
+#define SPDY_HTTP_HEADER_PROXY_CONNECTION "proxy-connection"
+#define SPDY_HTTP_HEADER_RANGE "range"
+#define SPDY_HTTP_HEADER_REFERER "referer"
+#define SPDY_HTTP_HEADER_RETRY_AFTER "retry-after"
+#define SPDY_HTTP_HEADER_SERVER "server"
+#define SPDY_HTTP_HEADER_SET_COOKIE "set-cookie"
+#define SPDY_HTTP_HEADER_SET_COOKIE2 "set-cookie2"
+#define SPDY_HTTP_HEADER_TE "te"
+#define SPDY_HTTP_HEADER_TRAILER "trailer"
+/* Transfer-Encoding header is forbidden in SPDY */
+#define SPDY_HTTP_HEADER_TRANSFER_ENCODING "transfer-encoding"
+#define SPDY_HTTP_HEADER_UPGRADE "upgrade"
+#define SPDY_HTTP_HEADER_USER_AGENT "user-agent"
+#define SPDY_HTTP_HEADER_VARY "vary"
+#define SPDY_HTTP_HEADER_VIA "via"
+#define SPDY_HTTP_HEADER_WARNING "warning"
+#define SPDY_HTTP_HEADER_WWW_AUTHENTICATE "www-authenticate"
+
+/**
+ * HTTP versions (a value must be provided in SPDY requests/responses).
+ */
+#define SPDY_HTTP_VERSION_1_0 "HTTP/1.0"
+#define SPDY_HTTP_VERSION_1_1 "HTTP/1.1"
+
+/**
+ * HTTP methods
+ */
+#define SPDY_HTTP_METHOD_CONNECT "CONNECT"
+#define SPDY_HTTP_METHOD_DELETE "DELETE"
+#define SPDY_HTTP_METHOD_GET "GET"
+#define SPDY_HTTP_METHOD_HEAD "HEAD"
+#define SPDY_HTTP_METHOD_OPTIONS "OPTIONS"
+#define SPDY_HTTP_METHOD_POST "POST"
+#define SPDY_HTTP_METHOD_PUT "PUT"
+#define SPDY_HTTP_METHOD_TRACE "TRACE"
+
+/**
+ * HTTP POST encodings, see also
+ * http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
+ */
+#define SPDY_HTTP_POST_ENCODING_FORM_URLENCODED
"application/x-www-form-urlencoded"
+#define SPDY_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data"
+
+
+/**
+ * Handle for the daemon (listening on a socket).
+ */
+struct SPDY_Daemon;
+
+
+/**
+ * Handle for a SPDY session/connection.
+ */
+struct SPDY_Session;
+
+
+/**
+ * Handle for a SPDY request sent by a client. The structure has pointer
+ * to the session's handler
+ */
+struct SPDY_Request;
+
+
+/**
+ * Handle for a response containing HTTP headers and data to be sent.
+ * The structure has pointer to the session's handler
+ * for this response.
+ */
+struct SPDY_Response;
+
+
+/**
+ * Collection of tuples of an HTTP header and values used in requests
+ * and responses.
+ */
+struct SPDY_NameValue;
+
+
+/**
+ * Collection of tuples of a SPDY setting ID, value
+ * and flags used to control the sessions.
+ */
+struct SPDY_Settings;
+
+
+/**
+ * SPDY daemon options. Passed in the varargs portion of
+ * SPDY_start_daemon to customize the daemon. Each option must
+ * be followed by a value of a specific type.<p>
+ *
+ * The values are used internally as flags, that is why they must be
+ * powers of 2.
+ */
+enum SPDY_DAEMON_OPTION
+{
+
+ /**
+ * No more options / last option. This is used
+ * to terminate the VARARGs list.
+ */
+ SPDY_DAEMON_OPTION_END = 0,
+
+ /**
+ * Set a custom timeout for all connections. Must be followed by
+ * a number of seconds, given as an 'unsigned int'. Use
+ * zero for no timeout.
+ */
+ SPDY_DAEMON_OPTION_SESSION_TIMEOUT = 1,
+
+ /**
+ * Bind daemon to the supplied sockaddr. This option must be
+ * followed by a 'struct sockaddr *'. The 'struct sockaddr*'
+ * should point to a 'struct sockaddr_in6' or to a
+ * 'struct sockaddr_in'.
+ */
+ SPDY_DAEMON_OPTION_SOCK_ADDR = 2,
+
+ /**
+ * Flags for the daemon. Must be followed by a SPDY_DAEMON_FLAG value
+ * which is the result of bitwise OR of desired flags.
+ */
+ SPDY_DAEMON_OPTION_FLAGS = 4,
+};
+
+
+/**
+ * Flags for starting SPDY daemon. They are used to set some settings
+ * for the daemon, which do not require values.
+ */
+enum SPDY_DAEMON_FLAG
+{
+ /**
+ * No flags selected.
+ */
+ SPDY_DAEMON_FLAG_NO = 0,
+
+ /**
+ * The server will bind only on IPv6 addresses. If the flag is set and
+ * the daemon is provided with IPv4 address or IPv6 is not supported,
+ * starting daemon will fail.
+ */
+ SPDY_DAEMON_FLAG_ONLY_IPV6 = 1,
+};
+
+
+/**
+ * SPDY settings IDs sent by both client and server in SPDY SETTINGS frame.
+ * They affect the whole SPDY session. Defined in SPDY Protocol - Draft 3.
+ */
+enum SPDY_SETTINGS
+{
+
+ /**
+ * Allows the sender to send its expected upload bandwidth on this
+ * channel. This number is an estimate. The value should be the
+ * integral number of kilobytes per second that the sender predicts
+ * as an expected maximum upload channel capacity.
+ */
+ SPDY_SETTINGS_UPLOAD_BANDWIDTH = 1,
+
+ /**
+ * Allows the sender to send its expected download bandwidth on this
+ * channel. This number is an estimate. The value should be the
+ * integral number of kilobytes per second that the sender predicts as
+ * an expected maximum download channel capacity.
+ */
+ SPDY_SETTINGS_DOWNLOAD_BANDWIDTH = 2,
+
+ /**
+ * Allows the sender to send its expected round-trip-time on this
+ * channel. The round trip time is defined as the minimum amount of
+ * time to send a control frame from this client to the remote and
+ * receive a response. The value is represented in milliseconds.
+ */
+ SPDY_SETTINGS_ROUND_TRIP_TIME = 3,
+
+ /**
+ * Allows the sender to inform the remote endpoint the maximum number
+ * of concurrent streams which it will allow. By default there is no
+ * limit. For implementors it is recommended that this value be no
+ * smaller than 100.
+ */
+ SPDY_SETTINGS_MAX_CONCURRENT_STREAMS = 4,
+
+ /**
+ * Allows the sender to inform the remote endpoint of the current TCP
+ * CWND value.
+ */
+ SPDY_SETTINGS_CURRENT_CWND = 5,
+
+ /**
+ * Allows the sender to inform the remote endpoint the retransmission
+ * rate (bytes retransmitted / total bytes transmitted).
+ */
+ SPDY_SETTINGS_DOWNLOAD_RETRANS_RATE = 6,
+
+ /**
+ * Allows the sender to inform the remote endpoint the initial window
+ * size (in bytes) for new streams.
+ */
+ SPDY_SETTINGS_INITIAL_WINDOW_SIZE = 7,
+
+ /**
+ * Allows the server to inform the client if the new size of the
+ * client certificate vector.
+ */
+ SPDY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8,
+};
+
+
+/**
+ * Flags for each individual SPDY setting in the SPDY SETTINGS frame.
+ * They affect only one setting to which they are set.
+ * Defined in SPDY Protocol - Draft 3.
+ */
+enum SPDY_FLAG_SETTINGS{
+
+ /**
+ * When set, the sender of this SETTINGS frame is requesting that the
+ * recipient persist the ID/Value and return it in future SETTINGS
+ * frames sent from the sender to this recipient. Because persistence
+ * is only implemented on the client, this flag is only sent by the
+ * server.
+ */
+ SPDY_FLAG_SETTINGS_PERSIST_VALUE = 1,
+
+ /**
+ * When set, the sender is notifying the recipient that this ID/Value
+ * pair was previously sent to the sender by the recipient with the
+ * SPDY_FLAG_SETTINGS_PERSIST_VALUE, and the sender is returning it.
+ * Because persistence is only implemented on the client, this flag is
+ * only sent by the client.
+ */
+ SPDY_FLAG_SETTINGS_PERSISTED = 2,
+};
+
+
+/**
+ * Flag associated with a whole SPDY SETTINGS frame. Affect all the
+ * settings in the frame. Defined in SPDY Protocol - Draft 3.
+ */
+enum SPDY_FLAG_SETTINGS_FRAME
+{
+
+ /**
+ * When set, the client should clear any previously persisted SETTINGS
+ * ID/Value pairs. If this frame contains ID/Value pairs with the
+ * SPDY_FLAG_SETTINGS_PERSIST_VALUE set, then the client will first
+ * clear its existing, persisted settings, and then persist the values
+ * with the flag set which are contained within this frame. Because
+ * persistence is only implemented on the client, this flag can only
+ * be used when the sender is the server.
+ */
+ SPDY_FLAG_SETTINGS_CLEAR_SETTINGS = 1,
+};
+
+
+/**
+ * SPDY settings function options. Passed in the varargs portion of
+ * SPDY_SettingsReceivedCallback and SPDY_send_settings to customize
+ * more the settings handling. Each option must
+ * be followed by a value of a specific type.<p>
+ *
+ * The values are used internally as flags, that is why they must be
+ * powers of 2.
+ */
+enum SPDY_SETTINGS_OPTION
+{
+
+ /**
+ * No more options / last option. This is used
+ * to terminate the VARARGs list.
+ */
+ SPDY_SETTINGS_OPTION_END = 0,
+};
+
+
+/**
+ * Used as a parameter for SPDY_ResponseResultCallback and shows if the
+ * response was actually written to the TLS socket or discarded by the
+ * lib for any reason (and respectively the reason).
+ */
+enum SPDY_RESPONSE_RESULT
+{
+
+ /**
+ * The lib has written the full response to the TLS socket.
+ */
+ SPDY_RESPONSE_RESULT_SUCCESS = 0,
+
+ /**
+ * The session is being closed, so the data is being discarded
+ */
+ SPDY_RESPONSE_RESULT_SESSION_CLOSED = 1,
+
+ /**
+ * The stream for this response has been closed. May happen when the
+ * sender had sent first SYN_STREAM and after that RST_STREAM.
+ */
+ SPDY_RESPONSE_RESULT_STREAM_CLOSED = 2,
+};
+
+
+/**
+ * Callback for serious error condition. The default action is to print
+ * an error message and abort().
+ *
+ * @param cls user specified value
+ * @param file where the error occured
+ * @param line where the error occured
+ * @param reason error details message, may be NULL
+ */
+typedef void
+(*SPDY_PanicCallback) (void * cls,
+ const char * file,
+ unsigned int line,
+ const char * reason);
+
+
+/**
+ * Callback for new SPDY session established by a client. Called
+ * immediately after the TCP connection was established.
+ *
+ * @param cls client-defined closure
+ * @param session handler for the new SPDY session
+ */
+typedef void
+(*SPDY_NewSessionCallback) (void * cls,
+ struct SPDY_Session *
session);
+
+
+/**
+ * Callback for closed session. Called after the TCP connection was
+ * closed. In this callback function the user has the last
+ * chance to access the SPDY_Session structure. After that the latter
+ * will be cleaned!
+ *
+ * @param cls client-defined closure
+ * @param session handler for the closed SPDY session
+ * @param by_client SPDY_YES if the session close was initiated by the
+ * client;
+ * SPDY_NO if closed by the server
+ */
+typedef void
+(*SPDY_SessionClosedCallback) (void * cls,
+ struct
SPDY_Session * session,
+ int by_client);
+
+
+/**
+ * Iterator over name-value pairs.
+ *
+ * @param cls client-defined closure
+ * @param name of the pair
+ * @param value of the pair
+ * @return SPDY_YES to continue iterating,
+ * SPDY_NO to abort the iteration
+ */
+typedef int
+(*SPDY_NameValueIterator) (void * cls,
+ const char * name,
+ const char * const *
value,
+ int num_values);
+
+
+/**
+ * Callback for received SPDY request.
+ *
+ * @param cls client-defined closure
+ * @param request handler. The request object is required for
+ * sending responses.
+ * @param priority of the SPDY stream which the request was
+ * sent over
+ * @param method HTTP method
+ * @param path HTTP path
+ * @param version HTTP version just like in HTTP request/response:
+ * "HTTP/1.0" or "HTTP/1.1" currently
+ * @param host called host as in HTTP
+ * @param scheme used ("http" or "https"). In SPDY 3 it is only "https".
+ * @param headers other HTTP headers from the request
+ */
+typedef void (*SPDY_NewRequestCallback) (void * cls,
+ struct SPDY_Request * request,
+ uint8_t priority,
+ const char * method,
+ const char * path,
+ const char * version,
+ const char * host,
+ const char * scheme,
+ struct SPDY_NameValue * headers);
+
+
+/**
+ * Callback for received new data chunk from the POST data of a given
+ * request.
+ *
+ * @param cls client-defined closure
+ * @param request handler
+ * @param buf data chunk from the POST data
+ * @param size the size of the data chunk 'buf' in bytes
+ * @param more false if this is the last chunk from the POST data. Note:
+ * true does not mean that more data will come, exceptional
+ * situation is possible
+ * @return SPDY_YES to continue calling the function,
+ * SPDY_NO to stop calling the function for this request
+ */
+typedef int (*SPDY_NewPOSTDataCallback) (void * cls,
+ struct SPDY_Request *request,
+ const void * buf,
+ size_t size,
+ bool more);
+// How about passing POST encoding information
+// here as well?
+//TODO
+
+
+/**
+ * Callback to be used with SPDY_build_response_with_callback. The
+ * callback will be called when the lib wants to write to the TLS socket.
+ * The application should provide the data to be sent.
+ *
+ * @param cls client-defined closure
+ * @param max maximum number of bytes that are allowed to be written
+ * to the buffer.
+ * @param more true if more data will be sent (i.e. the function must
+ * be calleed again),
+ * false if this is the last chunk, the lib will close
+ * the stream
+ * @return number of bytes written to buffer. On error the call MUST
+ * return value less than 0 to indicate the library.
+ */
+typedef ssize_t (*SPDY_ResponseCallback) (void * cls,
+ void * buffer,
+ size_t max,
+ bool * more);
+
+
+/**
+ * Callback to be called when the last bytes from the response was sent
+ * to the client or when the response was discarded from the lib. This
+ * callback is a very good place to discard the request and the response
+ * objects, if they will not be reused (e.g., sending the same response
+ * again). If the stream is closed it is safe to discard the request
+ * object.
+ *
+ * @param cls client-defined closure
+ * @param response handler to the response that was just sent
+ * @param request handler to the request for which the response was sent
+ * @param status shows if actually the response was sent or it was
+ * discarded by the lib for any reason (e.g., closing
session,
+ * closing stream, stopping daemon, etc.). It is possible
that
+ * status indicates an error but parts of the response
headers
+ * and/or body (in one
+ * or several frames) were already sent to the client.
+ * @param streamopened indicates if the the stream for this request/
+ * response pair is still opened. If yes, the server may
want
+ * to use SPDY push to send something additional to the
client
+ * and/or close the stream.
+ */
+typedef void
+(*SPDY_ResponseResultCallback) (void * cls,
+ struct
SPDY_Response * response,
+ struct
SPDY_Request * request,
+ enum
SPDY_RESPONSE_RESULT status,
+ bool
streamopened);
+
+
+/**
+ * Callback to notify when SPDY ping response is received.
+ *
+ * @param session handler for which the ping request was sent
+ * @param rtt the timespan between sending ping request and receiving it
+ * from the library
+ */
+typedef void
+(*SPDY_PingCallback) (void * cls,
+ struct SPDY_Session * session,
+ struct timeval * rtt);
+
+
+/**
+ * Iterator over settings ID/Value/Flags tuples.
+ *
+ * @param cls client-defined closure
+ * @param id SPDY settings ID
+ * @param value value for this setting
+ * @param flags flags for this tuple; use
+ * enum SPDY_FLAG_SETTINGS
+ * @return SPDY_YES to continue iterating,
+ * SPDY_NO to abort the iteration
+ */
+typedef int
+(*SPDY_SettingsIterator) (void * cls,
+ enum
SPDY_SETTINGS id,
+ int32_t value,
+ uint8_t flags);
+
+
+/**
+ * Callback to notify when SPDY SETTINGS are received from the client.
+ *
+ * @param session handler for which settings are received
+ * @param settings ID/value/flags tuples of the settings
+ * @param flags for the whole settings frame; use
+ * enum SPDY_FLAG_SETTINGS_FRAME
+ * @param ... list of options (type-value pairs,
+ * terminated with SPDY_SETTINGS_OPTION_END).
+ */
+typedef void
+(*SPDY_SettingsReceivedCallback) (struct SPDY_Session * session,
+ struct
SPDY_Settings * settings,
+ uint8_t flags,
+ ...);
+
+
+/* Global functions for the library */
+
+
+/**
+ * Init function for the whole library. It MUST be called before any
+ * other function of the library to initialize things like TLS context
+ * and possibly other stuff needed by the lib. Currently the call
+ * always returns SPDY_YES.
+ *
+ * @return SPDY_YES if the library was correctly initialized and its
+ * functions can be used now;
+ * SPDY_NO on error
+ */
+int
+SPDY_init (void);
+
+
+/**
+ * Deinit function for the whole lib. It can be called after finishing
+ * using the library. It frees and cleans up resources allocated in
+ * SPDY_init. Currently the function does not do anything.
+ */
+void
+SPDY_deinit (void);
+
+
+/**
+ * Sets the global error handler to a different implementation. "cb"
+ * will only be called in the case of typically fatal, serious
+ * internal consistency issues. These issues should only arise in the
+ * case of serious memory corruption or similar problems with the
+ * architecture as well as failed assertions. While "cb" is allowed to
+ * return and the lib will then try to continue, this is never safe.
+ *
+ * The default implementation that is used if no panic function is set
+ * simply prints an error message and calls "abort". Alternative
+ * implementations might call "exit" or other similar functions.
+ *
+ * @param cb new error handler
+ * @param cls passed to error handler
+ */
+void
+SPDY_set_panic_func (SPDY_PanicCallback cb,
+ void *cls);
+
+
+/* Daemon functions */
+
+
+/**
+ * Start a SPDY webserver on the given port.
+ *
+ * @param port to bind to. The value is ignored if address structure
+ * is passed as daemon option
+ * @param certfile path to the certificate that will be used by server
+ * @param keyfile path to the keyfile for the certificate
+ * @param nscb callback called when a new SPDY session is
+ * established by a client
+ * @param sccb callback called when a session is closed
+ * @param nrcb callback called when a client sends request
+ * @param npdcb callback called when HTTP POST params are received
+ * after request
+ * @param cls common extra argument to all of the callbacks
+ * @param ... list of options (type-value pairs,
+ * terminated with SPDY_DAEMON_OPTION_END).
+ * @return NULL on error, handle to daemon on success
+ */
+struct SPDY_Daemon *
+SPDY_start_daemon (uint16_t port,
+ const char * certfile,
+ const char * keyfile,
+ SPDY_NewSessionCallback nscb,
+ SPDY_SessionClosedCallback sccb,
+ SPDY_NewRequestCallback nrcb,
+ SPDY_NewPOSTDataCallback npdcb,
+ void * cls,
+ ...);
+
+
+/**
+ * Shutdown the daemon. First all sessions are closed. It is NOT safe
+ * to call this function in user callbacks.
+ *
+ * @param daemon to stop
+ */
+void
+SPDY_stop_daemon (struct SPDY_Daemon *daemon);
+
+
+/**
+ * Obtain the select sets for this daemon. Only those are retrieved,
+ * which some processing should be done for, i.e. not all sockets are
+ * added to write_fd_set.<p>
+ *
+ * It is possible that there is
+ * nothing to be read from a socket but there is data either in the
+ * TLS subsystem's read buffers or in libmicrospdy's read buffers, which
+ * waits for being processed. In such case the file descriptor will be
+ * added to write_fd_set. Since it is very likely for the socket to be
+ * ready for writing, the select used in the application's event loop
+ * will return with success, SPDY_run will be called, the data will be
+ * processed and maybe something will be written to the socket. Without
+ * this behaviour, considering a proper event loop, data may stay in the
+ * buffers, but run is never called.
+ *
+ * @param daemon to get sets from
+ * @param read_fd_set read set
+ * @param write_fd_set write set
+ * @param except_fd_set except set
+ * @return largest FD added to any of the sets
+ */
+int
+SPDY_get_fdset (struct SPDY_Daemon * daemon,
+ fd_set * read_fd_set,
+ fd_set * write_fd_set,
+ fd_set * except_fd_set);
+
+
+/**
+ * Obtain timeout value for select for this daemon. The returned value
+ * is how long select
+ * should at most block, not the timeout value set for connections.
+ *
+ * @param daemon to query for timeout
+ * @param timeout will be set to the timeout value (in seconds)
+ * @return SPDY_YES on success
+ * SPDY_NO if no connections exist that
+ * would necessiate the use of a timeout right now
+ */
+int
+SPDY_get_timeout (struct SPDY_Daemon * daemon,
+ unsigned long long * timeout);
+
+
+/**
+ * Run webserver operations. This method must be called in
+ * the client event loop.
+ *
+ * @param daemon to run
+ */
+void
+SPDY_run (struct SPDY_Daemon *daemon);
+
+
+/* SPDY Session handling functions */
+
+
+/**
+ * Closes a SPDY session. SPDY clients and servers are expected to keep
+ * sessions opened as long as possible. However, the server may want to
+ * close some connections, e.g. if there are too many, to free some
+ * resources. The function can also be used to close a specific session
+ * if the client is not desired.
+ *
+ * @param session handler to be closed
+ */
+void
+SPDY_close_session(struct SPDY_Session * session);
+
+
+/**
+ * Associate a void pointer with a session. The data accessible by the
+ * pointer can later be used wherever the session handler is available.
+ *
+ * @param session handler
+ * @param cls any data pointed by a pointer to be accessible later
+ */
+void
+SPDY_set_cls_to_session(struct SPDY_Session * session,
+ void * cls);
+
+
+/**
+ * Retrieves the pointer associated with SPDY_set_cls_to_session().
+ *
+ * @param session handler to get its cls
+ * @return same pointer added by SPDY_set_cls_to_session() or
+ * NULL when nothing was associated
+ */
+void *
+SPDY_get_cls_from_session(struct SPDY_Session * session);
+
+
+/**
+ * Retrieves the remote address of a given session.
+ *
+ * @param session handler to get its remote address
+ * @param addr out parameter; pointing to remote address
+ * @return length of the address structure
+ */
+socklen_t
+SPDY_get_remote_addr(struct SPDY_Session * session,
+ struct sockaddr ** addr);
+
+
+/* SPDY name/value data structure handling functions */
+
+
+/**
+ * Create a new NameValue structure. It is needed for putting inside the
+ * HTTP headers and their values for a response. The user should later
+ * destroy alone the structure.
+ *
+ * @return hendler to the new empty structure or NULL on error
+ */
+struct SPDY_NameValue *
+SPDY_name_value_create ();
+
+
+/**
+ * Add name/value pair to a NameValue structure. SPDY_NO will be returned
+ * if the name/value pair is already in the structure. It is legal to
+ * add different values for the same name.
+ *
+ * @param container structure to which the new pair is added
+ * @param name for the value. Null-terminated string.
+ * @param value the value itself. Null-terminated string.
+ * @return SPDY_NO on error or SPDY_YES on success
+ */
+int
+SPDY_name_value_add (struct SPDY_NameValue * container,
+ const char * name,
+ const char * value);
+
+
+/**
+ * Lookup value for a name in a name/value structure.
+ *
+ * @param container structure in which to lookup
+ * @param name the name to look for
+ * @param num_values length of the returned array with values
+ * @return NULL if no such item was found, or an array containing the
+ * values
+ */
+const char * const *
+SPDY_name_value_lookup (struct SPDY_NameValue *container,
+ const char *name,
+ int * num_values);
+
+
+/**
+ * Iterate over name/value structure.
+ *
+ * @param container structure which to iterate over
+ * @param iterator callback to call on each name/value pair;
+ * maybe NULL (then just count headers)
+ * @param iterator_cls extra argument to iterator
+ * @return number of entries iterated over
+ */
+int
+SPDY_name_value_iterate (struct SPDY_NameValue *container,
+ SPDY_NameValueIterator iterator,
+ void *iterator_cls);
+
+
+/**
+ * Destroy a NameValue structure. Use this function to destroy only
+ * objects which, after passed to, will not be destroied by other
+ * functions.
+ *
+ */
+void
+SPDY_name_value_destroy (struct SPDY_NameValue * container);
+
+
+/* SPDY request handling functions */
+
+
+/**
+ * Gets the session responsible for the given
+ * request.
+ *
+ * @param request for which the session is wanted
+ * @return session handler for the request
+ */
+struct SPDY_Session *
+SPDY_get_session_for_request(const struct SPDY_Request * request);
+
+
+/**
+ * Associate a void pointer with a request. The data accessible by the
+ * pointer can later be used wherever the request handler is available.
+ *
+ * @param request with which to associate a pointer
+ * @param cls any data pointed by a pointer to be accessible later
+ */
+void
+SPDY_set_cls_to_request(struct SPDY_Request * request,
+ void * cls);
+
+
+/**
+ * Retrieves the pointer associated with the request by
+ * SPDY_set_cls_to_request().
+ *
+ * @param request to get its cls
+ * @return same pointer added by SPDY_set_cls_to_request() or
+ * NULL when nothing was associated
+ */
+void *
+SPDY_get_cls_from_request(struct SPDY_Request * request);
+
+
+/* SPDY response handling functions */
+
+
+/**
+ * Create response object containing all needed headers and data. The
+ * response object is not bound to a request, so it can be used multiple
+ * times with SPDY_queue_response() and schould be
+ * destroied by calling the SPDY_destroy_response().<p>
+ *
+ * Currently the library does not provide compression of the body data.
+ * It is up to the user to pass already compressed data and the
+ * appropriate headers to this function when desired.
+ *
+ * @param status HTTP status code for the response (e.g. 404)
+ * @param statustext HTTP status message for the response, which will
+ * be appended to the status code (e.g. "OK"). Can be NULL
+ * @param version HTTP version for the response (e.g. "http/1.1")
+ * @param headers name/value structure containing additional HTTP headers.
+ * Can be NULL. Can be used multiple times, it is up to
+ * the user to destoy the object when not needed anymore.
+ * @param data the body of the response. The lib will make a copy of it,
+ * so it is up to the user to take care of the memory
+ * pointed by data
+ * @param size length of data. It can be 0, then the lib will send only
+ * headers
+ * @return NULL on error, handle to response object on success
+ */
+struct SPDY_Response *
+SPDY_build_response(int status,
+ const char * statustext,
+ const char * version,
+ struct SPDY_NameValue * headers,
+ const void * data,
+ size_t size);
+
+
+/**
+ * Create response object containing all needed headers. The data will
+ * be provided later when the lib calls the callback function (just
+ * before writing it to the TLS socket). The
+ * response object is not bound to a request, so it can be used multiple
+ * times with SPDY_queue_response() and schould be
+ * destroied by calling the SPDY_destroy_response().<p>
+ *
+ * Currently the library does not provide compression of the body data.
+ * It is up to the user to pass already compressed data and the
+ * appropriate headers to this function and the callback when desired.
+ *
+ * @param status HTTP status code for the response (e.g. 404)
+ * @param statustext HTTP status message for the response, which will
+ * be appended to the status code (e.g. "OK"). Can be NULL
+ * @param version HTTP version for the response (e.g. "http/1.1")
+ * @param headers name/value structure containing additional HTTP headers.
+ * Can be NULL. Can be used multiple times, it is up to
+ * the user to destoy the object when not needed anymore.
+ * @param rcb callback to use to obtain response data
+ * @param rcb_cls extra argument to rcb
+ * @param block_size preferred block size for querying rcb (advisory only,
+ * the lib will call rcb specifying the block size); clients
+ * should pick a value that is appropriate for IO and
+ * memory performance requirements. The function will
+ * fail if the value is bigger than the maximum
+ * supported value (SPDY_MAX_SUPPORTED_FRAME_SIZE).
+ * Can be 0, then the lib will use
+ * SPDY_MAX_SUPPORTED_FRAME_SIZE instead.
+ * @return NULL on error, handle to response object on success
+ */
+struct SPDY_Response *
+SPDY_build_response_with_callback(int status,
+ const char * statustext,
+ const char * version,
+ struct SPDY_NameValue * headers,
+ SPDY_ResponseCallback rcb,
+ void *rcb_cls,
+ uint32_t block_size);
+
+
+/**
+ * Queue response object to be sent to the client. A successfully queued
+ * response may never be sent, e.g. when the stream gets closed. The
+ * data will be added to the output queue. The call will fail, if the
+ * output for this session
+ * is closed (i.e. the session is closed, half or full) or the output
+ * channel for the stream, on which the request was received, is closed
+ * (i.e. the stream is closed, half or full).
+ *
+ * @param request object identifying the request to which the
+ * response is returned
+ * @param response object containg headers and data to be sent
+ * @param closestream TRUE if the server does NOT intend to PUSH
+ * something more associated to this request/response
later,
+ * FALSE otherwise
+ * @param consider_priority if FALSE, the response will be added to the
+ * end of the queue. If TRUE, the response will be added
after
+ * the last previously added response with priority of the
+ * request grater or equal to that of the current one. This
+ * means that the function should be called with TRUE each
time
+ * if one wants to be sure that the output queue behaves
like
+ * a priority queue
+ * @param rrcb callback called when all the data was sent (last frame
+ * from response) or when that frame was discarded (e.g.
the
+ * stream has been closed meanwhile)
+ * @param rrcb_cls extra argument to rcb
+ * @return SPDY_NO on error or SPDY_YES on success
+ */
+int
+SPDY_queue_response (struct SPDY_Request * request,
+ struct SPDY_Response *response,
+ bool closestream,
+ bool consider_priority,
+ SPDY_ResponseResultCallback rrcb,
+ void * rrcb_cls);
+
+
+/**
+ * Destroy a response structure. It should be called for all objects
+ * returned by SPDY_build_response*() functions to free the memory
+ * associated with the prepared response. It is safe to call this
+ * function not before being sure that the response will not be used by
+ * the lib anymore, this means after SPDY_ResponseResultCallback
+ * callbacks were called for all calls to SPDY_queue_response() passing
+ * this response.
+ *
+ * @param response to destroy
+ */
+void
+SPDY_destroy_response (struct SPDY_Response *response);
+
+
+/* SPDY settings ID/value data structure handling functions */
+
+
+/**
+ * Create a new SettingsIDValue structure. It is needed for putting
+ * inside tuples of SPDY option, flags and value for sending to the
+ * client.
+ *
+ * @return hendler to the new empty structure or NULL on error
+ */
+const struct SPDY_Settings *
+SPDY_settings_create ();
+
+
+/**
+ * Add or update a tuple to a SettingsIDValue structure.
+ *
+ * @param container structure to which the new tuple is added
+ * @param id SPDY settings ID that will be sent. If this ID already in
+ * container, the tupple for it will be updated (value and/or
+ * flags). If it is not in the container, a new tupple will be
+ * added.
+ * @param flags SPDY settings flags applied only to this setting
+ * @param value of the setting
+ * @return SPDY_NO on error
+ * or SPDY_YES if a new setting was added
+ */
+int
+SPDY_settings_add (struct SPDY_Settings *container,
+ enum SPDY_SETTINGS id,
+ enum SPDY_FLAG_SETTINGS
flags,
+ int32_t value);
+
+
+/**
+ * Lookup value and flags for an ID in a settings ID/value structure.
+ *
+ * @param container structure in which to lookup
+ * @param id SPDY settings ID to search for
+ * @param flags out param for SPDY settings flags for this setting;
+ * check it against the flags in enum SPDY_FLAG_SETTINGS
+ * @param value out param for the value of this setting
+ * @return SPDY_NO if the setting is not into the structure
+ * or SPDY_YES if it is into it
+ */
+int
+SPDY_settings_lookup (const struct SPDY_Settings * container,
+ enum
SPDY_SETTINGS id,
+ enum
SPDY_FLAG_SETTINGS * flags,
+ int32_t *
value);
+
+
+/**
+ * Iterate over settings ID/value structure.
+ *
+ * @param container structure which to iterate over
+ * @param iterator callback to call on each ID/value pair;
+ * maybe NULL (then just count number of settings)
+ * @param iterator_cls extra argument to iterator
+ * @return number of entries iterated over
+ */
+int
+SPDY_settings_iterate (const struct SPDY_Settings * container,
+
SPDY_SettingsIterator iterator,
+ void *
iterator_cls);
+
+
+/**
+ * Destroy a settings ID/value structure. Use this function to destroy
+ * only objects which, after passed to, will not be destroied by other
+ * functions.
+ *
+ * @param container structure which to detroy
+ */
+void
+SPDY_settings_destroy (struct SPDY_Settings * container);
+
+
+/* SPDY SETTINGS handling functions */
+
+
+/**
+ * Send SPDY SETTINGS to the client. The call will return fail if there
+ * in invald setting into the settings container (e.g. invalid setting
+ * ID).
+ *
+ * @param session SPDY_Session handler for which settings are being sent
+ * @param settings ID/value pairs of the settings to be sent.
+ * Can be used multiple times, it is up to the user to
destoy
+ * the object when not needed anymore.
+ * @param flags for the whole settings frame. They are valid for all tuples
+ * @param ... list of options (type-value pairs,
+ * terminated with SPDY_SETTINGS_OPTION_END).
+ * @return SPDY_NO on error or SPDY_YES on
+ * success
+ */
+int
+SPDY_send_settings (struct SPDY_Session * session,
+ struct SPDY_Settings * settings,
+ enum SPDY_FLAG_SETTINGS_FRAME flags,
+ ...);
+
+
+/* SPDY misc functions */
+
+
+/**
+ * Destroy a request structure. It should be called for all objects
+ * received as a parameter in SPDY_NewRequestCallback to free the memory
+ * associated with the request. It is safe to call this
+ * function not before being sure that the request will not be used by
+ * the lib anymore, this means after the stream, on which this request
+ * had been sent, was closed and all SPDY_ResponseResultCallback
+ * callbacks were called for all calls to SPDY_queue_response() passing
+ * this request object.
+ *
+ * @param request to destroy
+ */
+void
+SPDY_destroy_request (struct SPDY_Request * request);
+
+
+/**
+ * Send SPDY ping to the client
+ *
+ * @param session handler for which the ping request is sent
+ * @param rttcb callback called when ping response to the request is
+ * received
+ * @param rttcb_cls extra argument to rttcb
+ * @return SPDY_NO on error or SPDY_YES on success
+ */
+int
+SPDY_send_ping(struct SPDY_Session * session,
+ SPDY_PingCallback rttcb,
+ void * rttcb_cls);
+
+
+#endif
Added: libmicrohttpd/src/microspdy/EXPORT.sym
===================================================================
--- libmicrohttpd/src/microspdy/EXPORT.sym (rev 0)
+++ libmicrohttpd/src/microspdy/EXPORT.sym 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,2 @@
+SPDY_start_daemon
+SPDY_stop_daemon
Added: libmicrohttpd/src/microspdy/Makefile.am
===================================================================
--- libmicrohttpd/src/microspdy/Makefile.am (rev 0)
+++ libmicrohttpd/src/microspdy/Makefile.am 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,38 @@
+if USE_PRIVATE_PLIBC_H
+ PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc
+endif
+
+AM_CPPFLAGS = \
+ $(PLIBC_INCLUDE) \
+ -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/src/microspdy
+
+
+EXTRA_DIST = EXPORT.sym
+
+
+lib_LTLIBRARIES = \
+ libmicrospdy.la
+
+libmicrospdy_la_SOURCES = \
+ tls.h tls.c \
+ structures.h structures.c \
+ internal.h internal.c \
+ daemon.h daemon.c \
+ stream.h stream.c \
+ compression.h compression.c \
+ session.h session.c \
+ applicationlayer.c applicationlayer.h \
+ alstructures.c alstructures.h
+
+
+libmicrospdy_la_LDFLAGS = \
+ $(SPDY_LIB_LDFLAGS)
+
+libmicrospdy_la_CFLAGS = -Wextra \
+ $(SPDY_LIB_CFLAGS)
+
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage
+endif
Added: libmicrohttpd/src/microspdy/alstructures.c
===================================================================
--- libmicrohttpd/src/microspdy/alstructures.c (rev 0)
+++ libmicrohttpd/src/microspdy/alstructures.c 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,41 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file alstructures.c
+ * @brief structures only for the application layer
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "alstructures.h"
+#include "internal.h"
+
+void
+SPDY_destroy_request (struct SPDY_Request *request)
+{
+ if(NULL == request)
+ {
+ SPDYF_DEBUG("request is NULL");
+ return;
+ }
+ //strings into request struct are just references to strings in
+ //headers, so no need to free them twice
+ SPDY_name_value_destroy(request->headers);
+ free(request);
+}
Added: libmicrohttpd/src/microspdy/alstructures.h
===================================================================
--- libmicrohttpd/src/microspdy/alstructures.h (rev 0)
+++ libmicrohttpd/src/microspdy/alstructures.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,79 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file alstructures.h
+ * @brief structures only for the application layer
+ * @author Andrey Uzunov
+ */
+
+#ifndef ALSTRUCTURES_H
+#define ALSTRUCTURES_H
+
+#include "platform.h"
+
+
+/**
+ * Represents a SPDY request.
+ */
+struct SPDY_Request
+{
+ /**
+ * SPDY stream in whose context the request was received
+ */
+ struct SPDYF_Stream *stream;
+
+ /**
+ * Other HTTP headers from the request
+ */
+ struct SPDY_NameValue *headers;
+
+ /**
+ * HTTP method
+ */
+ char *method;
+
+ /**
+ * HTTP path
+ */
+ char *path;
+
+ /**
+ * HTTP version just like in HTTP request/response:
+ * "HTTP/1.0" or "HTTP/1.1" currently
+ */
+ char *version;
+
+ /**
+ * called host as in HTTP
+ */
+ char *host;
+
+ /**
+ * The scheme used ("http" or "https")
+ */
+ char *scheme;
+
+ /**
+ * Extra field to be used by the user with set/get func for whatever
+ * purpose he wants.
+ */
+ void *user_cls;
+};
+
+#endif
Added: libmicrohttpd/src/microspdy/applicationlayer.c
===================================================================
--- libmicrohttpd/src/microspdy/applicationlayer.c
(rev 0)
+++ libmicrohttpd/src/microspdy/applicationlayer.c 2013-05-05 19:21:40 UTC
(rev 27030)
@@ -0,0 +1,679 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file applicationlayer.c
+ * @brief SPDY application or HTTP layer
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "applicationlayer.h"
+#include "alstructures.h"
+#include "structures.h"
+#include "internal.h"
+#include "daemon.h"
+#include "session.h"
+
+
+/**
+ * Callback called when new stream is created. It extracts the info from
+ * the stream to create (HTTP) request object and pass it to the client.
+ *
+ * @param cls
+ * @param stream the new SPDY stream
+ * @return SPDY_YES on success, SPDY_NO on memomry error
+ */
+static int
+spdy_handler_new_stream (void *cls,
+ struct SPDYF_Stream * stream)
+{
+ (void)cls;
+ uint i;
+ char *method = NULL;
+ char *path = NULL;
+ char *version = NULL;
+ char *host = NULL;
+ char *scheme = NULL;
+ struct SPDY_Request * request = NULL;
+ struct SPDY_NameValue * headers = NULL;
+ struct SPDY_NameValue * iterator = stream->headers;
+ struct SPDY_Daemon *daemon;
+
+ daemon = stream->session->daemon;
+
+ //if the user doesn't care, ignore it
+ if(NULL == daemon->new_request_cb)
+ return SPDY_YES;
+
+ if(NULL == (headers=SPDY_name_value_create()))
+ goto free_and_fail;
+
+ if(NULL==(request = malloc(sizeof(struct SPDY_Request))))
+ goto free_and_fail;
+
+ memset(request, 0, sizeof(struct SPDY_Request));
+ request->stream = stream;
+
+ /* extract the mandatory fields from stream->headers' structure
+ * to pass them to the client */
+ while(iterator != NULL)
+ {
+ if(strcmp(":method",iterator->name) == 0)
+ {
+ if(1 != iterator->num_values)
+ break;
+ method = iterator->value[0];
+ }
+ else if(strcmp(":path",iterator->name) == 0)
+ {
+ if(1 != iterator->num_values)
+ break;
+ path = iterator->value[0];
+ }
+ else if(strcmp(":version",iterator->name) == 0)
+ {
+ if(1 != iterator->num_values)
+ break;
+ version = iterator->value[0];
+ }
+ else if(strcmp(":host",iterator->name) == 0)
+ {
+ //TODO can it have more values?
+ if(1 != iterator->num_values)
+ break;
+ host = iterator->value[0];
+ }
+ else if(strcmp(":scheme",iterator->name) == 0)
+ {
+ if(1 != iterator->num_values)
+ break;
+ scheme = iterator->value[0];
+ }
+ else
+ for(i=0; i<iterator->num_values; ++i)
+ if (SPDY_YES !=
SPDY_name_value_add(headers,iterator->name,iterator->value[i]))
+ goto free_and_fail;
+
+ iterator = iterator->next;
+ }
+
+ request->method=method;
+ request->path=path;
+ request->version=version;
+ request->host=host;
+ request->scheme=scheme;
+ request->headers=headers;
+
+ //check request validity, all these fields are mandatory for a request
+ if(NULL == method || strlen(method) == 0
+ || NULL == path || strlen(path) == 0
+ || NULL == version || strlen(version) == 0
+ || NULL == host || strlen(host) == 0
+ || NULL == scheme || strlen(scheme) == 0
+ )
+ {
+ //TODO HTTP 400 Bad Request must be answered
+
+ SPDYF_DEBUG("Bad request");
+
+ SPDY_destroy_request(request);
+
+ return SPDY_YES;
+ }
+
+ //call client's callback function to notify
+ daemon->new_request_cb(daemon->cls,
+ request,
+ stream->priority,
+ method,
+ path,
+ version,
+ host,
+ scheme,
+ headers);
+
+ return SPDY_YES;
+
+ //for GOTO
+ free_and_fail:
+
+ SPDY_name_value_destroy(headers);
+ return SPDY_NO;
+}
+
+
+/**
+ * Callback to be called when the response queue object was handled and
+ * the data was already sent or discarded.
+ *
+ * @param cls
+ * @param response_queue the object which is being handled
+ * @param status shows if actually the response was sent or it was
+ * discarded by the lib for any reason (e.g., closing
session,
+ * closing stream, stopping daemon, etc.). It is possible
that
+ * status indicates an error but parts of the response
headers
+ * and/or body (in one
+ * or several frames) were already sent to the client.
+ */
+static void
+spdy_handler_response_queue_result(void * cls,
+ struct
SPDYF_Response_Queue *response_queue,
+ enum
SPDY_RESPONSE_RESULT status)
+{
+ int streamopened;
+ struct SPDY_Request *request = (struct SPDY_Request *)cls;
+
+ SPDYF_ASSERT(NULL == response_queue->data_frame
+ && NULL != response_queue->control_frame
+ || NULL != response_queue->data_frame
+ && NULL == response_queue->control_frame,
+ "response queue must have either control frame or data frame");
+
+ streamopened = !response_queue->stream->is_out_closed;
+
+ response_queue->rrcb(response_queue->rrcb_cls,
response_queue->response, request, status, streamopened);
+}
+
+
+int
+SPDY_init ()
+{
+ SPDYF_ASSERT(SPDYF_BUFFER_SIZE >= SPDY_MAX_SUPPORTED_FRAME_SIZE,
+ "Buffer size is less than max supported frame size!");
+ SPDYF_ASSERT(SPDY_MAX_SUPPORTED_FRAME_SIZE >= 32,
+ "Max supported frame size must be bigger than the minimal
value!");
+ SPDYF_tls_global_init();
+ return SPDY_YES;
+}
+
+
+void
+SPDY_deinit ()
+{
+ //currently nothing to be freed/deinited
+ //SPDYF_tls_global_deinit doesn't do anything now
+ //SPDYF_tls_global_deinit();
+}
+
+
+void
+SPDY_run (struct SPDY_Daemon *daemon)
+{
+ if(NULL == daemon)
+ {
+ SPDYF_DEBUG("daemon is NULL");
+ return;
+ }
+
+ SPDYF_run(daemon);
+}
+
+
+int
+SPDY_get_timeout (struct SPDY_Daemon *daemon,
+ unsigned long long *timeout)
+{
+ if(NULL == daemon)
+ {
+ SPDYF_DEBUG("daemon is NULL");
+ return SPDY_INPUT_ERROR;
+ }
+
+ return SPDYF_get_timeout(daemon,timeout);
+}
+
+
+int
+SPDY_get_fdset (struct SPDY_Daemon *daemon,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *except_fd_set)
+{
+ if(NULL == daemon
+ || NULL == read_fd_set
+ || NULL == write_fd_set
+ || NULL == except_fd_set)
+ {
+ SPDYF_DEBUG("a parameter is NULL");
+ return SPDY_INPUT_ERROR;
+ }
+
+ return SPDYF_get_fdset(daemon,
+ read_fd_set,
+ write_fd_set,
+ except_fd_set,
+ false);
+}
+
+
+struct SPDY_Daemon *
+SPDY_start_daemon (uint16_t port,
+ const char *certfile,
+ const char *keyfile,
+ SPDY_NewSessionCallback nscb,
+ SPDY_SessionClosedCallback sccb,
+ SPDY_NewRequestCallback nrcb,
+ SPDY_NewPOSTDataCallback npdcb,
+ void * cls,
+ ...)
+{
+ struct SPDY_Daemon *daemon;
+ va_list valist;
+
+ if(NULL == certfile)
+ {
+ SPDYF_DEBUG("certfile is NULL");
+ return NULL;
+ }
+ if(NULL == keyfile)
+ {
+ SPDYF_DEBUG("keyfile is NULL");
+ return NULL;
+ }
+
+ va_start(valist, cls);
+ daemon = SPDYF_start_daemon_va ( port,
+ certfile,
+ keyfile,
+ nscb,
+ sccb,
+ nrcb,
+ npdcb,
+ &spdy_handler_new_stream,
+ cls,
+ NULL,
+ valist
+ );
+ va_end(valist);
+
+ return daemon;
+}
+
+
+void
+SPDY_stop_daemon (struct SPDY_Daemon *daemon)
+{
+ if(NULL == daemon)
+ {
+ SPDYF_DEBUG("daemon is NULL");
+ return;
+ }
+
+ SPDYF_stop_daemon(daemon);
+}
+
+
+struct SPDY_Response *
+SPDY_build_response(int status,
+ const char * statustext,
+ const char * version,
+ struct SPDY_NameValue * headers,
+ const void * data,
+ size_t size)
+{
+ struct SPDY_Response *response = NULL;
+ struct SPDY_NameValue ** all_headers = NULL;
+ char *fullstatus = NULL;
+ int ret;
+ int num_hdr_containers = 1;
+
+ if(NULL == version)
+ {
+ SPDYF_DEBUG("version is NULL");
+ return NULL;
+ }
+
+ if(NULL == (response = malloc(sizeof(struct SPDY_Response))))
+ goto free_and_fail;
+ memset(response, 0, sizeof(struct SPDY_Response));
+
+ if(NULL != headers)
+ num_hdr_containers = 2;
+
+ if(NULL == (all_headers = malloc(num_hdr_containers * sizeof(struct
SPDY_NameValue *))))
+ goto free_and_fail;
+ memset(all_headers, 0, num_hdr_containers * sizeof(struct
SPDY_NameValue *));
+
+ if(2 == num_hdr_containers)
+ all_headers[1] = headers;
+
+ if(NULL == (all_headers[0] = SPDY_name_value_create()))
+ goto free_and_fail;
+
+ if(NULL == statustext)
+ ret = asprintf(&fullstatus, "%i", status);
+ else
+ ret = asprintf(&fullstatus, "%i %s", status, statustext);
+ if(-1 == ret)
+ goto free_and_fail;
+
+ if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":status",
fullstatus))
+ goto free_and_fail;
+
+ free(fullstatus);
+ fullstatus = NULL;
+
+ if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":version", version))
+ goto free_and_fail;
+
+ if(0 >= (response->headers_size =
SPDYF_name_value_to_stream(all_headers,
+
num_hdr_containers,
+
&(response->headers))))
+ goto free_and_fail;
+
+ SPDY_name_value_destroy(all_headers[0]);
+ free(all_headers);
+
+ if(size > 0)
+ {
+ //copy the data to the response object
+ if(NULL == (response->data = malloc(size)))
+ {
+ free(response->headers);
+ goto free_and_fail;
+ }
+ memcpy(response->data, data, size);
+ response->data_size = size;
+ }
+
+ return response;
+
+ //for GOTO
+ free_and_fail:
+
+ free(fullstatus);
+ if(NULL != all_headers)
+ SPDY_name_value_destroy(all_headers[0]);
+ free(all_headers);
+ free(response);
+
+ return NULL;
+}
+
+
+struct SPDY_Response *
+SPDY_build_response_with_callback(int status,
+ const char * statustext,
+ const char * version,
+ struct SPDY_NameValue * headers,
+ SPDY_ResponseCallback rcb,
+ void *rcb_cls,
+ uint32_t block_size)
+{
+ struct SPDY_Response *response;
+
+ if(NULL == rcb)
+ {
+ SPDYF_DEBUG("rcb is NULL");
+ return NULL;
+ }
+ if(block_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)
+ {
+ SPDYF_DEBUG("block_size is wrong");
+ return NULL;
+ }
+
+ if(0 == block_size)
+ block_size = SPDY_MAX_SUPPORTED_FRAME_SIZE;
+
+ response = SPDY_build_response(status,
+ statustext,
+ version,
+ headers,
+ NULL,
+ 0);
+
+ if(NULL == response)
+ {
+ return NULL;
+ }
+
+ response->rcb = rcb;
+ response->rcb_cls = rcb_cls;
+ response->rcb_block_size = block_size;
+
+ return response;
+}
+
+
+int
+SPDY_queue_response (struct SPDY_Request * request,
+ struct SPDY_Response *response,
+ bool closestream,
+ bool consider_priority,
+ SPDY_ResponseResultCallback rrcb,
+ void * rrcb_cls)
+{
+ struct SPDYF_Response_Queue *headers_to_queue;
+ struct SPDYF_Response_Queue *body_to_queue;
+ SPDYF_ResponseQueueResultCallback frqcb = NULL;
+ void *frqcb_cls = NULL;
+ int int_consider_priority = consider_priority ? SPDY_YES : SPDY_NO;
+
+ if(NULL == request)
+ {
+ SPDYF_DEBUG("request is NULL");
+ return SPDY_INPUT_ERROR;
+ }
+ if(NULL == response)
+ {
+ SPDYF_DEBUG("request is NULL");
+ return SPDY_INPUT_ERROR;
+ }
+
+ if(request->stream->is_out_closed
+ || SPDY_SESSION_STATUS_CLOSING ==
request->stream->session->status)
+ return SPDY_NO;
+
+ if(NULL != rrcb)
+ {
+ frqcb_cls = request;
+ frqcb = &spdy_handler_response_queue_result;
+ }
+
+ if(response->data_size > 0)
+ {
+ //SYN_REPLY and DATA will be queued
+
+ if(NULL == (headers_to_queue =
SPDYF_response_queue_create(false,
+ response->headers,
+ response->headers_size,
+ response,
+ request->stream,
+ false,
+ NULL,
+ NULL,
+ NULL,
+ NULL)))
+ {
+ return SPDY_NO;
+ }
+
+ if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
+ response->data,
+ response->data_size,
+ response,
+ request->stream,
+ closestream,
+ frqcb,
+ frqcb_cls,
+ rrcb,
+ rrcb_cls)))
+ {
+ SPDYF_response_queue_destroy(headers_to_queue);
+ return SPDY_NO;
+ }
+
+ SPDYF_queue_response (headers_to_queue,
+
request->stream->session,
+ int_consider_priority);
+
+ SPDYF_queue_response (body_to_queue,
+
request->stream->session,
+ int_consider_priority);
+ }
+ else if(NULL == response->rcb)
+ {
+ //no "body" will be queued, e.g. HTTP 404 without body
+
+ if(NULL == (headers_to_queue =
SPDYF_response_queue_create(false,
+ response->headers,
+ response->headers_size,
+ response,
+ request->stream,
+ closestream,
+ frqcb,
+ frqcb_cls,
+ rrcb,
+ rrcb_cls)))
+ {
+ return SPDY_NO;
+ }
+
+ SPDYF_queue_response (headers_to_queue,
+
request->stream->session,
+ int_consider_priority);
+ }
+ else
+ {
+ //response with callbacks
+
+ if(NULL == (headers_to_queue =
SPDYF_response_queue_create(false,
+ response->headers,
+ response->headers_size,
+ response,
+ request->stream,
+ false,
+ NULL,
+ NULL,
+ NULL,
+ NULL)))
+ {
+ return SPDY_NO;
+ }
+
+ if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
+ response->data,
+ response->data_size,
+ response,
+ request->stream,
+ closestream,
+ frqcb,
+ frqcb_cls,
+ rrcb,
+ rrcb_cls)))
+ {
+ SPDYF_response_queue_destroy(headers_to_queue);
+ return SPDY_NO;
+ }
+
+ SPDYF_queue_response (headers_to_queue,
+
request->stream->session,
+ int_consider_priority);
+
+ SPDYF_queue_response (body_to_queue,
+
request->stream->session,
+ int_consider_priority);
+ }
+
+ return SPDY_YES;
+}
+
+
+socklen_t
+SPDY_get_remote_addr(struct SPDY_Session * session,
+ struct sockaddr ** addr)
+{
+ if(NULL == session)
+ {
+ SPDYF_DEBUG("session is NULL");
+ return 0;
+ }
+
+ *addr = session->addr;
+
+ return session->addr_len;
+}
+
+
+struct SPDY_Session *
+SPDY_get_session_for_request(const struct SPDY_Request * request)
+{
+ if(NULL == request)
+ {
+ SPDYF_DEBUG("request is NULL");
+ return NULL;
+ }
+
+ return request->stream->session;
+}
+
+
+void *
+SPDY_get_cls_from_session(struct SPDY_Session * session)
+{
+ if(NULL == session)
+ {
+ SPDYF_DEBUG("session is NULL");
+ return NULL;
+ }
+
+ return session->user_cls;
+}
+
+
+void
+SPDY_set_cls_to_session(struct SPDY_Session * session,
+ void * cls)
+{
+ if(NULL == session)
+ {
+ SPDYF_DEBUG("session is NULL");
+ return;
+ }
+
+ session->user_cls = cls;
+}
+
+
+void *
+SPDY_get_cls_from_request(struct SPDY_Request * request)
+{
+ if(NULL == request)
+ {
+ SPDYF_DEBUG("request is NULL");
+ return NULL;
+ }
+
+ return request->user_cls;
+}
+
+
+void
+SPDY_set_cls_to_request(struct SPDY_Request * request,
+ void * cls)
+{
+ if(NULL == request)
+ {
+ SPDYF_DEBUG("request is NULL");
+ return;
+ }
+
+ request->user_cls = cls;
+}
Added: libmicrohttpd/src/microspdy/applicationlayer.h
===================================================================
--- libmicrohttpd/src/microspdy/applicationlayer.h
(rev 0)
+++ libmicrohttpd/src/microspdy/applicationlayer.h 2013-05-05 19:21:40 UTC
(rev 27030)
@@ -0,0 +1,31 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file applicationlayer.h
+ * @brief SPDY application or HTTP layer
+ * @author Andrey Uzunov
+ */
+
+#ifndef APPLICATIONLAYER_H
+#define APPLICATIONLAYER_H
+
+#include "platform.h"
+
+
+#endif
Added: libmicrohttpd/src/microspdy/compression.c
===================================================================
--- libmicrohttpd/src/microspdy/compression.c (rev 0)
+++ libmicrohttpd/src/microspdy/compression.c 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,441 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file compression.c
+ * @brief zlib handling functions
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "structures.h"
+#include "internal.h"
+#include "compression.h"
+
+/* spdy ver 3 specific dictionary used by zlib */
+static const unsigned char
+spdyf_zlib_dictionary[] = {
+ 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // - - - - o p t i
+ 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // o n s - - - - h
+ 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // e a d - - - - p
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // o s t - - - - p
+ 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // u t - - - - d e
+ 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // l e t e - - - -
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // t r a c e - - -
+ 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // - a c c e p t -
+ 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
+ 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t - c h a r s e
+ 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t - - - - a c c
+ 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e p t - e n c o
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // d i n g - - - -
+ 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // a c c e p t - l
+ 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // a n g u a g e -
+ 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // - - - a c c e p
+ 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t - r a n g e s
+ 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // - - - - a g e -
+ 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // - - - a l l o w
+ 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // - - - - a u t h
+ 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // o r i z a t i o
+ 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n - - - - c a c
+ 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // h e - c o n t r
+ 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // o l - - - - c o
+ 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // n n e c t i o n
+ 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // e n t - b a s e
+ 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // e n t - e n c o
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // d i n g - - - -
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // c o n t e n t -
+ 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // l a n g u a g e
+ 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // - - - - c o n t
+ 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // e n t - l e n g
+ 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // t h - - - - c o
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // n t e n t - l o
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // c a t i o n - -
+ 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
+ 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t - m d 5 - - -
+ 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // - c o n t e n t
+ 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // - r a n g e - -
+ 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // - - c o n t e n
+ 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t - t y p e - -
+ 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // - - d a t e - -
+ 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // - - e t a g - -
+ 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // - - e x p e c t
+ 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // - - - - e x p i
+ 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // r e s - - - - f
+ 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // r o m - - - - h
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // o s t - - - - i
+ 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f - m a t c h -
+ 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // - - - i f - m o
+ 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // d i f i e d - s
+ 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // i n c e - - - -
+ 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // i f - n o n e -
+ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // m a t c h - - -
+ 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // - i f - r a n g
+ 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e - - - - i f -
+ 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // u n m o d i f i
+ 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // e d - s i n c e
+ 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // - - - - l a s t
+ 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // - m o d i f i e
+ 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d - - - - l o c
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // a t i o n - - -
+ 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // - m a x - f o r
+ 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // w a r d s - - -
+ 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // - p r a g m a -
+ 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // - - - p r o x y
+ 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // - a u t h e n t
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // i c a t e - - -
+ 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // - p r o x y - a
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // u t h o r i z a
+ 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // t i o n - - - -
+ 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // r a n g e - - -
+ 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // - r e f e r e r
+ 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // - - - - r e t r
+ 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y - a f t e r -
+ 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // - - - s e r v e
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r - - - - t e -
+ 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // - - - t r a i l
+ 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // e r - - - - t r
+ 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // a n s f e r - e
+ 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // n c o d i n g -
+ 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // - - - u p g r a
+ 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // d e - - - - u s
+ 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // e r - a g e n t
+ 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // - - - - v a r y
+ 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // - - - - v i a -
+ 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // - - - w a r n i
+ 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // n g - - - - w w
+ 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w - a u t h e n
+ 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // t i c a t e - -
+ 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // - - m e t h o d
+ 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // - - - - g e t -
+ 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // - - - s t a t u
+ 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s - - - - 2 0 0
+ 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // - O K - - - - v
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // e r s i o n - -
+ 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // - - H T T P - 1
+ 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // - 1 - - - - u r
+ 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l - - - - p u b
+ 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // l i c - - - - s
+ 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // e t - c o o k i
+ 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e - - - - k e e
+ 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p - a l i v e -
+ 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // - - - o r i g i
+ 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n 1 0 0 1 0 1 2
+ 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 0 1 2 0 2 2 0 5
+ 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 2 0 6 3 0 0 3 0
+ 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 2 3 0 3 3 0 4 3
+ 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 0 5 3 0 6 3 0 7
+ 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 4 0 2 4 0 5 4 0
+ 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 6 4 0 7 4 0 8 4
+ 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 0 9 4 1 0 4 1 1
+ 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 4 1 2 4 1 3 4 1
+ 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 4 4 1 5 4 1 6 4
+ 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 1 7 5 0 2 5 0 4
+ 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 5 0 5 2 0 3 - N
+ 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // o n - A u t h o
+ 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // r i t a t i v e
+ 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // - I n f o r m a
+ 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // t i o n 2 0 4 -
+ 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // N o - C o n t e
+ 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // n t 3 0 1 - M o
+ 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // v e d - P e r m
+ 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // a n e n t l y 4
+ 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 0 0 - B a d - R
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // e q u e s t 4 0
+ 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1 - U n a u t h
+ 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // o r i z e d 4 0
+ 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3 - F o r b i d
+ 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // d e n 4 0 4 - N
+ 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // o t - F o u n d
+ 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 5 0 0 - I n t e
+ 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // r n a l - S e r
+ 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // v e r - E r r o
+ 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r 5 0 1 - N o t
+ 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // - I m p l e m e
+ 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // n t e d 5 0 3 -
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // S e r v i c e -
+ 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // U n a v a i l a
+ 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // b l e J a n - F
+ 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // e b - M a r - A
+ 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // p r - M a y - J
+ 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // u n - J u l - A
+ 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // u g - S e p t -
+ 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // O c t - N o v -
+ 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // D e c - 0 0 - 0
+ 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0 - 0 0 - M o n
+ 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // - - T u e - - W
+ 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // e d - - T h u -
+ 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // - F r i - - S a
+ 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t - - S u n - -
+ 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // G M T c h u n k
+ 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // e d - t e x t -
+ 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // h t m l - i m a
+ 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // g e - p n g - i
+ 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // m a g e - j p g
+ 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // - i m a g e - g
+ 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // i f - a p p l i
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
+ 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // m l - a p p l i
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // c a t i o n - x
+ 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // h t m l - x m l
+ 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // - t e x t - p l
+ 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // a i n - t e x t
+ 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // - j a v a s c r
+ 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // i p t - p u b l
+ 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // i c p r i v a t
+ 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // e m a x - a g e
+ 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // - g z i p - d e
+ 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // f l a t e - s d
+ 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // c h c h a r s e
+ 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t - u t f - 8 c
+ 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // h a r s e t - i
+ 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // s o - 8 8 5 9 -
+ 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1 - u t f - - -
+ 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // - e n q - 0 -
+};
+
+
+int
+SPDYF_zlib_deflate_init(z_stream *strm)
+{
+ int ret;
+
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ //the second argument is "level of compression"
+ //use 0 for no compression; 9 for best compression
+ ret = deflateInit(strm, Z_DEFAULT_COMPRESSION);
+ if(ret != Z_OK)
+ {
+ SPDYF_DEBUG("deflate init");
+ return SPDY_NO;
+ }
+ ret = deflateSetDictionary(strm,
+ spdyf_zlib_dictionary,
+ sizeof(spdyf_zlib_dictionary));
+ if(ret != Z_OK)
+ {
+ SPDYF_DEBUG("deflate set dict");
+ deflateEnd(strm);
+ return SPDY_NO;
+ }
+ return SPDY_YES;
+}
+
+
+void
+SPDYF_zlib_deflate_end(z_stream *strm)
+{
+ deflateEnd(strm);
+}
+
+int
+SPDYF_zlib_deflate(z_stream *strm,
+ const void *src,
+ size_t src_size,
+ size_t *data_used,
+ void **dest,
+ size_t *dest_size)
+{
+ int ret;
+ int flush;
+ uint have;
+ Bytef out[SPDYF_ZLIB_CHUNK];
+
+ *dest = NULL;
+ *dest_size = 0;
+
+ do
+ {
+ /* check for big data bigger than the buffer used */
+ if(src_size > SPDYF_ZLIB_CHUNK)
+ {
+ strm->avail_in = SPDYF_ZLIB_CHUNK;
+ src_size -= SPDYF_ZLIB_CHUNK;
+ /* flush is used for the loop to detect if we still
+ * need to supply additional
+ * data to the stream via avail_in and next_in. */
+ flush = Z_NO_FLUSH;
+ }
+ else
+ {
+ strm->avail_in = src_size;
+ flush = Z_SYNC_FLUSH;
+ }
+ *data_used += strm->avail_in;
+
+ strm->next_in = (Bytef *)src;
+
+ /* Loop while output data is available */
+ do
+ {
+ strm->avail_out = SPDYF_ZLIB_CHUNK;
+ strm->next_out = out;
+
+ /* No need to check return value of deflate.
+ * (See zlib documentation at
http://www.zlib.net/zlib_how.html */
+ ret = deflate(strm, flush);
+ have = SPDYF_ZLIB_CHUNK - strm->avail_out;
+
+ /* (Re)allocate memory for dest and keep track of it's
size. */
+ *dest_size += have;
+ *dest = realloc(*dest, *dest_size);
+ if(!*dest)
+ {
+ SPDYF_DEBUG("realloc data for result");
+ deflateEnd(strm);
+ return SPDY_NO;
+ }
+ memcpy((*dest) + ((*dest_size) - have), out, have);
+ }
+ while(strm->avail_out == 0);
+ /* At this point, all of the input data should already
+ * have been used. */
+ SPDYF_ASSERT(strm->avail_in == 0,"compressing bug");
+ }
+ while(flush != Z_SYNC_FLUSH);
+
+ return Z_OK == ret ? SPDY_YES : SPDY_NO;
+}
+
+
+int
+SPDYF_zlib_inflate_init(z_stream *strm)
+{
+ int ret;
+
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ strm->avail_in = 0;
+ strm->next_in = Z_NULL;
+ //change 15 to lower value for performance and benchmark
+ //"The windowBits parameter is the base two logarithm of the
+ // maximum window size (the size of the history buffer)."
+ ret = inflateInit2(strm, 15);
+ if(ret != Z_OK)
+ {
+ SPDYF_DEBUG("Cannot inflateInit2 the stream");
+ return SPDY_NO;
+ }
+ return SPDY_YES;
+}
+
+
+void
+SPDYF_zlib_inflate_end(z_stream *strm)
+{
+ inflateEnd(strm);
+}
+
+
+int
+SPDYF_zlib_inflate(z_stream *strm,
+ const void *src,
+ size_t src_size,
+ void **dest,
+ size_t *dest_size)
+{
+ int ret = Z_OK;
+ uint32_t have;
+ Bytef out[SPDYF_ZLIB_CHUNK];
+
+ *dest = NULL;
+ *dest_size = 0;
+
+ /* decompress until deflate stream ends or end of file */
+ do
+ {
+ if(src_size > SPDYF_ZLIB_CHUNK)
+ {
+ strm->avail_in = SPDYF_ZLIB_CHUNK;
+ src_size -= SPDYF_ZLIB_CHUNK;
+ }
+ else
+ {
+ strm->avail_in = src_size;
+ src_size = 0;
+ }
+
+ if(strm->avail_in == 0){
+ //the loop breaks always here as the stream never ends
+ break;
+ }
+
+ strm->next_in = (Bytef *) src;
+ /* run inflate() on input until output buffer not full */
+ do {
+ strm->avail_out = SPDYF_ZLIB_CHUNK;
+ strm->next_out = out;
+ ret = inflate(strm, Z_SYNC_FLUSH);
+
+ switch (ret)
+ {
+ case Z_STREAM_ERROR:
+ SPDYF_DEBUG("Error on inflate");
+ //no inflateEnd here, same in zlib
example
+ return SPDY_NO;
+
+ case Z_NEED_DICT:
+ ret = inflateSetDictionary(strm,
+
spdyf_zlib_dictionary,
+
sizeof(spdyf_zlib_dictionary));
+ if(ret != Z_OK)
+ {
+ SPDYF_DEBUG("Error on
inflateSetDictionary");
+ inflateEnd(strm);
+ return SPDY_NO;
+ }
+ ret = inflate(strm, Z_SYNC_FLUSH);
+ if(Z_STREAM_ERROR == ret)
+ {
+ SPDYF_DEBUG("Error on inflate");
+ return SPDY_NO;
+ }
+ break;
+
+ case Z_DATA_ERROR:
+ SPDYF_DEBUG("Z_DATA_ERROR");
+ inflateEnd(strm);
+ return SPDY_NO;
+
+ case Z_MEM_ERROR:
+ SPDYF_DEBUG("Z_MEM_ERROR");
+ inflateEnd(strm);
+ return SPDY_NO;
+ }
+ have = SPDYF_ZLIB_CHUNK - strm->avail_out;
+ *dest_size += have;
+ /* (re)alloc memory for the output buffer */
+ *dest = realloc(*dest, *dest_size);
+ if(!*dest)
+ {
+ SPDYF_DEBUG("Cannot realloc memory");
+ inflateEnd(strm);
+ return SPDY_NO;
+ }
+ memcpy((*dest) + ((*dest_size) - have), out, have);
+ }
+ while (0 == strm->avail_out);
+ }
+ while (Z_STREAM_END != ret);
+
+ return Z_OK == ret || Z_STREAM_END == ret ? SPDY_YES : SPDY_NO;
+}
Added: libmicrohttpd/src/microspdy/compression.h
===================================================================
--- libmicrohttpd/src/microspdy/compression.h (rev 0)
+++ libmicrohttpd/src/microspdy/compression.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,117 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file compression.h
+ * @brief zlib handling functions
+ * @author Andrey Uzunov
+ */
+
+#ifndef COMPRESSION_H
+#define COMPRESSION_H
+
+#include "platform.h"
+
+/* size of buffers used by zlib on (de)compressing */
+#define SPDYF_ZLIB_CHUNK 16384
+
+
+/**
+ * Initializes the zlib stream for compression. Must be called once
+ * for a session on initialization.
+ *
+ * @param strm Zlib stream on which we work
+ * @return SPDY_NO if zlib failed. SPDY_YES otherwise
+ */
+int
+SPDYF_zlib_deflate_init(z_stream *strm);
+
+
+/**
+ * Deinitializes the zlib stream for compression. Should be called once
+ * for a session on cleaning up.
+ *
+ * @param strm Zlib stream on which we work
+ */
+void
+SPDYF_zlib_deflate_end(z_stream *strm);
+
+
+/**
+ * Compressing stream with zlib.
+ *
+ * @param strm Zlib stream on which we work
+ * @param src stream of the data to be compressed
+ * @param src_size size of the data
+ * @param data_used the number of bytes from src_stream that were used
+ * TODO do we need
+ * @param dest the resulting compressed stream. Should be NULL. Must be
+ * freed later manually.
+ * @param dest_size size of the data after compression
+ * @return SPDY_NO if malloc or zlib failed. SPDY_YES otherwise
+ */
+int
+SPDYF_zlib_deflate(z_stream *strm,
+ const void *src,
+ size_t src_size,
+ size_t *data_used,
+ void **dest,
+ size_t *dest_size);
+
+
+/**
+ * Initializes the zlib stream for decompression. Must be called once
+ * for a session.
+ *
+ * @param strm Zlib stream on which we work
+ * @return SPDY_NO if zlib failed. SPDY_YES otherwise
+ */
+int
+SPDYF_zlib_inflate_init(z_stream *strm);
+
+
+/**
+ * Deinitializes the zlib stream for decompression. Should be called once
+ * for a session on cleaning up.
+ *
+ * @param strm Zlib stream on which we work
+ */
+void
+SPDYF_zlib_inflate_end(z_stream *strm);
+
+
+/**
+ * Decompressing stream with zlib.
+ *
+ * @param strm Zlib stream on which we work
+ * @param src stream of the data to be decompressed
+ * @param src_size size of the data
+ * @param dest the resulting decompressed stream. Should be NULL. Must
+ * be freed manually.
+ * @param dest_size size of the data after decompression
+ * @return SPDY_NO if malloc or zlib failed. SPDY_YES otherwise. If the
+ * function fails, the SPDY session must be closed
+ */
+int
+SPDYF_zlib_inflate(z_stream *strm,
+ const void *src,
+ size_t src_size,
+ void **dest,
+ size_t *dest_size);
+
+#endif
Added: libmicrohttpd/src/microspdy/daemon.c
===================================================================
--- libmicrohttpd/src/microspdy/daemon.c (rev 0)
+++ libmicrohttpd/src/microspdy/daemon.c 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,515 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file daemon.c
+ * @brief daemon functionality
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "structures.h"
+#include "internal.h"
+#include "session.h"
+#include "tls.h"
+
+
+/**
+ * Default implementation of the panic function,
+ * prints an error message and aborts.
+ *
+ * @param cls unused
+ * @param file name of the file with the problem
+ * @param line line number with the problem
+ * @param reason error message with details
+ */
+static void
+spdyf_panic_std (void *cls,
+ const char *file,
+ unsigned int line,
+ const char *reason)
+{
+ (void)cls;
+ fprintf (stdout, "Fatal error in libmicrospdy %s:%u: %s\n",
+ file, line, reason);
+ //raise(SIGINT); //used for gdb
+ abort ();
+}
+
+
+/**
+ * Global handler for fatal errors.
+ */
+SPDY_PanicCallback spdyf_panic = &spdyf_panic_std;
+
+
+/**
+ * Global closure argument for "spdyf_panic".
+ */
+void *spdyf_panic_cls;
+
+
+/**
+ * Free resources associated with all closed connections.
+ * (destroy responses, free buffers, etc.).
+ *
+ * @param daemon daemon to clean up
+ */
+static void
+spdyf_cleanup_sessions (struct SPDY_Daemon *daemon)
+{
+ struct SPDY_Session *session;
+
+ while (NULL != (session = daemon->cleanup_head))
+ {
+ DLL_remove (daemon->cleanup_head,
+ daemon->cleanup_tail,
+ session);
+
+ SPDYF_session_destroy(session);
+ }
+}
+
+
+/**
+ * Closing of all connections handled by the daemon.
+ *
+ * @param daemon SPDY daemon
+ */
+static void
+spdyf_close_all_sessions (struct SPDY_Daemon *daemon)
+{
+ struct SPDY_Session *session;
+
+ while (NULL != (session = daemon->sessions_head))
+ {
+ //prepare GOAWAY frame
+ SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
+ //try to send the frame (it is best effort, so it will maybe
sent)
+ SPDYF_session_write(session,true);
+ SPDYF_session_close(session);
+ }
+
+ spdyf_cleanup_sessions(daemon);
+}
+
+
+/**
+ * Parse a list of options given as varargs.
+ *
+ * @param daemon the daemon to initialize
+ * @param valist the options
+ * @return SPDY_YES on success, SPDY_NO on error
+ */
+static int
+spdyf_parse_options_va (struct SPDY_Daemon *daemon,
+ va_list valist)
+{
+ enum SPDY_DAEMON_OPTION opt;
+
+ while (SPDY_DAEMON_OPTION_END != (opt = (enum SPDY_DAEMON_OPTION)
va_arg (valist, int)))
+ {
+ if(opt & daemon->options)
+ {
+ SPDYF_DEBUG("Daemon option %i used twice",opt);
+ return SPDY_NO;
+ }
+ daemon->options |= opt;
+
+ switch (opt)
+ {
+ case SPDY_DAEMON_OPTION_SESSION_TIMEOUT:
+ daemon->session_timeout = va_arg (valist,
unsigned int);
+ break;
+ case SPDY_DAEMON_OPTION_SOCK_ADDR:
+ daemon->address = va_arg (valist, struct
sockaddr *);
+ break;
+ case SPDY_DAEMON_OPTION_FLAGS:
+ daemon->flags = va_arg (valist, enum
SPDY_DAEMON_FLAG);
+ break;
+ default:
+ SPDYF_DEBUG("Wrong option for the daemon
%i",opt);
+ return SPDY_NO;
+ }
+ }
+ return SPDY_YES;
+}
+
+
+void
+SPDY_set_panic_func (SPDY_PanicCallback cb,
+ void *cls)
+{
+ spdyf_panic = cb;
+ spdyf_panic_cls = cls;
+}
+
+
+struct SPDY_Daemon *
+SPDYF_start_daemon_va (uint16_t port,
+ const char *certfile,
+ const char *keyfile,
+ SPDY_NewSessionCallback nscb,
+ SPDY_SessionClosedCallback sccb,
+ SPDY_NewRequestCallback nrcb,
+ SPDY_NewPOSTDataCallback npdcb,
+ SPDYF_NewStreamCallback fnscb,
+ void * cls,
+ void * fcls,
+ va_list valist)
+{
+ struct SPDY_Daemon *daemon = NULL;
+ int afamily;
+ int option_on = 1;
+ int ret;
+ struct sockaddr_in* servaddr4 = NULL;
+#if HAVE_INET6
+ struct sockaddr_in6* servaddr6 = NULL;
+#endif
+ socklen_t addrlen;
+
+ if (NULL == (daemon = malloc (sizeof (struct SPDY_Daemon))))
+ {
+ SPDYF_DEBUG("malloc");
+ return NULL;
+ }
+ memset (daemon, 0, sizeof (struct SPDY_Daemon));
+ daemon->socket_fd = -1;
+ daemon->port = port;
+ if (NULL == (daemon->certfile = strdup (certfile)))
+ {
+ SPDYF_DEBUG("str");
+ goto free_and_fail;
+ }
+ if (NULL == (daemon->keyfile = strdup (keyfile)))
+ {
+ SPDYF_DEBUG("str");
+ goto free_and_fail;
+ }
+ daemon->new_session_cb = nscb;
+ daemon->session_closed_cb = sccb;
+ daemon->new_request_cb = nrcb;
+ daemon->new_post_data_cb = npdcb;
+ daemon->cls = cls;
+ daemon->fcls = fcls;
+ daemon->fnew_stream_cb = fnscb;
+
+ if(SPDY_YES != spdyf_parse_options_va (daemon, valist))
+ {
+ SPDYF_DEBUG("parse");
+ goto free_and_fail;
+ }
+
+ if(!port && NULL == daemon->address)
+ {
+ SPDYF_DEBUG("Port is 0");
+ goto free_and_fail;
+ }
+
+#if HAVE_INET6
+ //handling IPv6
+ if((daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
+ && NULL != daemon->address && AF_INET6 !=
daemon->address->sa_family)
+ {
+ SPDYF_DEBUG("SPDY_DAEMON_FLAG_ONLY_IPV6 set but IPv4 address
provided");
+ goto free_and_fail;
+ }
+
+ if(NULL == daemon->address)
+ {
+ addrlen = sizeof (struct sockaddr_in6);
+
+ if (NULL == (servaddr6 = malloc (addrlen)))
+ {
+ SPDYF_DEBUG("malloc");
+ goto free_and_fail;
+ }
+ memset (servaddr6, 0, addrlen);
+ servaddr6->sin6_family = AF_INET6;
+ servaddr6->sin6_addr = in6addr_any;
+ servaddr6->sin6_port = htons (port);
+ daemon->address = (struct sockaddr *) servaddr6;
+ }
+
+ afamily = AF_INET6 == daemon->address->sa_family ? PF_INET6 : PF_INET;
+#else
+ //handling IPv4
+ if(daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
+ {
+ SPDYF_DEBUG("SPDY_DAEMON_FLAG_ONLY_IPV6 set but no support");
+ goto free_and_fail;
+ }
+
+ if(NULL == daemon->address)
+ {
+ addrlen = sizeof (struct sockaddr_in);
+
+ if (NULL == (servaddr4 = malloc (addrlen)))
+ {
+ SPDYF_DEBUG("malloc");
+ goto free_and_fail;
+ }
+ memset (servaddr4, 0, addrlen);
+ servaddr4->sin_family = AF_INET;
+ servaddr4->sin_addr = INADDR_ANY;
+ servaddr4->sin_port = htons (port);
+ daemon->address = (struct sockaddr *) servaddr4;
+ }
+
+ afamily = PF_INET;
+#endif
+
+ daemon->socket_fd = socket (afamily, SOCK_STREAM, 0);
+ if (-1 == daemon->socket_fd)
+ {
+ SPDYF_DEBUG("sock");
+ goto free_and_fail;
+ }
+
+ //setting option for the socket to reuse address
+ ret = setsockopt(daemon->socket_fd, SOL_SOCKET, SO_REUSEADDR,
&option_on, sizeof(option_on));
+ if(ret)
+ {
+ SPDYF_DEBUG("WARNING: SO_REUSEADDR was not set for the server");
+ }
+
+#if HAVE_INET6
+ if(daemon->flags & SPDY_DAEMON_FLAG_ONLY_IPV6)
+ {
+ ret = setsockopt(daemon->socket_fd, IPPROTO_IPV6, IPV6_V6ONLY,
&option_on, sizeof(option_on));
+ if(ret)
+ {
+ SPDYF_DEBUG("setsockopt with IPPROTO_IPV6 failed");
+ goto free_and_fail;
+ }
+ }
+#endif
+
+ if (-1 == bind (daemon->socket_fd, daemon->address, addrlen))
+ {
+ SPDYF_DEBUG("bind %i",errno);
+ goto free_and_fail;
+ }
+
+ if (listen (daemon->socket_fd, 20) < 0)
+ {
+ SPDYF_DEBUG("listen %i",errno);
+ goto free_and_fail;
+ }
+
+ if(SPDY_YES != SPDYF_tls_init(daemon))
+ {
+ SPDYF_DEBUG("tls");
+ goto free_and_fail;
+ }
+
+ return daemon;
+
+ //for GOTO
+ free_and_fail:
+ if(daemon->socket_fd > 0)
+ close (daemon->socket_fd);
+
+ free(servaddr4);
+#if HAVE_INET6
+ free(servaddr6);
+#endif
+ if(NULL != daemon->certfile)
+ free(daemon->certfile);
+ if(NULL != daemon->keyfile)
+ free(daemon->keyfile);
+ free (daemon);
+
+ return NULL;
+}
+
+
+void
+SPDYF_stop_daemon (struct SPDY_Daemon *daemon)
+{
+ SPDYF_tls_deinit(daemon);
+
+ shutdown (daemon->socket_fd, SHUT_RDWR);
+ spdyf_close_all_sessions (daemon);
+ close (daemon->socket_fd);
+
+ if(!(SPDY_DAEMON_OPTION_SOCK_ADDR & daemon->options))
+ free(daemon->address);
+
+ free(daemon->certfile);
+ free(daemon->keyfile);
+
+ free(daemon);
+}
+
+
+int
+SPDYF_get_timeout (struct SPDY_Daemon *daemon,
+ unsigned long long *timeout)
+{
+ time_t earliest_deadline = 0;
+ time_t now;
+ struct SPDY_Session *pos;
+ bool have_timeout;
+
+ if(0 == daemon->session_timeout)
+ return SPDY_NO;
+
+ now = SPDYF_monotonic_time();
+ have_timeout = false;
+ for (pos = daemon->sessions_head; NULL != pos; pos = pos->next)
+ {
+ if ( (! have_timeout) ||
+ (earliest_deadline > pos->last_activity +
daemon->session_timeout) )
+ earliest_deadline = pos->last_activity +
daemon->session_timeout;
+
+ have_timeout = true;
+
+ if (SPDY_YES == SPDYF_tls_is_pending(pos))
+ {
+ earliest_deadline = 0;
+ break;
+ }
+ }
+
+ if (!have_timeout)
+ return SPDY_NO;
+ if (earliest_deadline < now)
+ *timeout = 0;
+ else
+ //*timeout = 1000 * (1 + earliest_deadline - now);
+ *timeout = earliest_deadline - now;
+
+ return SPDY_YES;
+}
+
+
+int
+SPDYF_get_fdset (struct SPDY_Daemon *daemon,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *except_fd_set,
+ bool all)
+{
+ (void)except_fd_set;
+ struct SPDY_Session *pos;
+ int fd;
+ int max_fd = -1;
+
+ fd = daemon->socket_fd;
+ if (-1 != fd)
+ {
+ FD_SET (fd, read_fd_set);
+ /* update max file descriptor */
+ max_fd = fd;
+ }
+
+ for (pos = daemon->sessions_head; NULL != pos; pos = pos->next)
+ {
+ fd = pos->socket_fd;
+ FD_SET(fd, read_fd_set);
+ if(all
+ || NULL != pos->response_queue_head //frames pending
+ || NULL != pos->write_buffer //part of last frame
pending
+ || SPDY_SESSION_STATUS_CLOSING == pos->status //the
session is about to be closed
+ || daemon->session_timeout //timeout passed for the
session
+ && (pos->last_activity +
daemon->session_timeout < SPDYF_monotonic_time())
+ || SPDY_YES == SPDYF_tls_is_pending(pos) //data in TLS'
read buffer pending
+ || ((pos->read_buffer_offset -
pos->read_buffer_beginning) > 0) // data in lib's read buffer pending
+ )
+ FD_SET(fd, write_fd_set);
+ if(fd > max_fd)
+ max_fd = fd;
+ }
+
+ return max_fd;
+}
+
+
+void
+SPDYF_run (struct SPDY_Daemon *daemon)
+{
+ struct SPDY_Session *pos;
+ struct SPDY_Session *next;
+ int num_ready;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ int max;
+ struct timeval timeout;
+ int ds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ //here we need really all descriptors to see later which are ready
+ max = SPDYF_get_fdset(daemon,&rs,&ws,&es, true);
+
+ num_ready = select (max + 1, &rs, &ws, &es, &timeout);
+
+ if(num_ready < 1)
+ return;
+
+ if ( (-1 != (ds = daemon->socket_fd)) &&
+ (FD_ISSET (ds, &rs)) ){
+ SPDYF_session_accept(daemon);
+ }
+
+ next = daemon->sessions_head;
+ while (NULL != (pos = next))
+ {
+ next = pos->next;
+ ds = pos->socket_fd;
+ if (ds != -1)
+ {
+ //fill the read buffer
+ if (FD_ISSET (ds, &rs) || SPDYF_tls_is_pending(pos)){
+ SPDYF_session_read(pos);
+ }
+
+ //do something with the data in read buffer
+ if(SPDY_NO == SPDYF_session_idle(pos))
+ {
+ //the session was closed, cannot write anymore
+ //continue;
+ }
+
+ //write whatever has been put to the response queue
+ //during read or idle operation, something might be put
+ //on the response queue, thus call write operation
+ if (FD_ISSET (ds, &ws)){
+ if(SPDY_NO == SPDYF_session_write(pos, false))
+ {
+ //SPDYF_session_close(pos);
+ //continue;
+ }
+ }
+
+ /* the response queue has been flushed for half closed
+ * connections, so let close them */
+ /*if(pos->read_closed)
+ {
+ SPDYF_session_close(pos);
+ }*/
+ }
+ }
+
+ spdyf_cleanup_sessions(daemon);
+}
Added: libmicrohttpd/src/microspdy/daemon.h
===================================================================
--- libmicrohttpd/src/microspdy/daemon.h (rev 0)
+++ libmicrohttpd/src/microspdy/daemon.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,121 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file daemon.h
+ * @brief daemon functionality
+ * @author Andrey Uzunov
+ */
+
+#ifndef DAEMON_H
+#define DAEMON_H
+
+#include "platform.h"
+
+
+/**
+ * Start a SPDDY webserver on the given port.
+ *
+ * @param port port to bind to
+ * @param certfile path to the certificate that will be used by server
+ * @param keyfile path to the keyfile for the certificate
+ * @param nscb callback called when a new SPDY session is
+ * established by a client
+ * @param sccb callback called when a client closes the session
+ * @param nrcb callback called when a client sends request
+ * @param npdcb callback called when HTTP POST params are received
+ * after request
+ * @param fnscb callback called when new stream is opened by a client
+ * @param cls extra argument to all of the callbacks without those
+ * specific only for the framing layer
+ * @param fcls extra argument to all of the callbacks, specific only for
+ * the framing layer (those vars starting with
'f').
+ * @param valist va_list of options (type-value pairs,
+ * terminated with SPDY_DAEMON_OPTION_END).
+ * @return NULL on error, handle to daemon on success
+ */
+struct SPDY_Daemon *
+SPDYF_start_daemon_va (uint16_t port,
+ const char *certfile,
+ const char *keyfile,
+ SPDY_NewSessionCallback nscb,
+ SPDY_SessionClosedCallback sccb,
+ SPDY_NewRequestCallback nrcb,
+ SPDY_NewPOSTDataCallback npdcb,
+ SPDYF_NewStreamCallback fnscb,
+ void * cls,
+ void * fcls,
+ va_list valist);
+
+
+/**
+ * Run webserver operations (without blocking unless
+ * in client callbacks). This method must be called in the client event
+ * loop.
+ *
+ * @param daemon daemon to run
+ */
+void
+SPDYF_run (struct SPDY_Daemon *daemon);
+
+
+/**
+ * Obtain timeout value for select for this daemon. The returned value
+ * is how long select
+ * should at most block, not the timeout value set for connections.
+ *
+ * @param daemon daemon to query for timeout
+ * @param timeout set to the timeout (in seconds)
+ * @return SPDY_YES on success, SPDY_NO if no connections exist that
+ * would necessiate the use of a timeout right now
+ */
+int
+SPDYF_get_timeout (struct SPDY_Daemon *daemon,
+ unsigned long long *timeout);
+
+
+/**
+ * Obtain the select sets for this daemon. The idea of SPDYF_get_fdset
+ * is to return such descriptors that the select in the application can
+ * return and SPDY_run can be called only when this is really needed.
+ * That means not all sockets will be added to write_fd_set.
+ *
+ * @param daemon daemon to get sets from
+ * @param read_fd_set read set
+ * @param write_fd_set write set
+ * @param except_fd_set except set
+ * @param all add all session's descriptors to write_fd_set or not
+ * @return largest FD added
+ */
+int
+SPDYF_get_fdset (struct SPDY_Daemon *daemon,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *except_fd_set,
+ bool all);
+
+
+/**
+ * Shutdown the daemon.
+ *
+ * @param daemon daemon to stop
+ */
+void
+SPDYF_stop_daemon (struct SPDY_Daemon *daemon);
+
+#endif
Added: libmicrohttpd/src/microspdy/internal.c
===================================================================
--- libmicrohttpd/src/microspdy/internal.c (rev 0)
+++ libmicrohttpd/src/microspdy/internal.c 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,38 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file internal.c
+ * @brief internal functions and macros for the framing layer
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "structures.h"
+
+
+time_t
+SPDYF_monotonic_time(void)
+{
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+ return ts.tv_sec;
+#endif
+ return time(NULL);
+}
Added: libmicrohttpd/src/microspdy/internal.h
===================================================================
--- libmicrohttpd/src/microspdy/internal.h (rev 0)
+++ libmicrohttpd/src/microspdy/internal.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,189 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file structures.h
+ * @brief internal functions and macros for the framing layer
+ * @author Andrey Uzunov
+ */
+
+#ifndef INTERNAL_H_H
+#define INTERNAL_H_H
+
+#include "platform.h"
+#include "microspdy.h"
+#include "tls.h"
+
+/* size of read buffers for each connection
+ * must be at least the size of SPDY_MAX_SUPPORTED_FRAME_SIZE */
+#define SPDYF_BUFFER_SIZE 8192
+
+/* number of frames written to the socket at once. After X frames
+ * everything should be run again. In this way the application can
+ * response to more important requests while a big file is still
+ * being transmitted to the client */
+#define SPDYF_NUM_SENT_FRAMES_AT_ONCE 10
+
+
+/**
+ * Handler for fatal errors.
+ */
+extern SPDY_PanicCallback spdyf_panic;
+
+
+/**
+ * Closure argument for "mhd_panic".
+ */
+extern void *spdyf_panic_cls;
+
+
+/**
+ * Trigger 'panic' action based on fatal errors.
+ *
+ * @param msg error message (const char *)
+ */
+#define SPDYF_PANIC(msg) \
+ spdyf_panic (spdyf_panic_cls, __FILE__, __LINE__, msg)
+
+
+/**
+ * Asserts the validity of an expression.
+ *
+ * @param expression (bool)
+ * @param msg message to print on error (const char *)
+ */
+#define SPDYF_ASSERT(expr,msg) \
+ if(!(expr)){\
+ SPDYF_PANIC(msg);\
+ abort();\
+ }
+
+
+/**
+ * Convert 24 bit integer from host byte order to network byte order.
+ *
+ * @param n input value (int32_t)
+ * @return converted value (uint32_t)
+ */
+#if HAVE_BIG_ENDIAN
+#define HTON24(n) n
+#else
+#define HTON24(n) (((((uint32_t)(n) & 0xFF)) << 16)\
+ | (((uint32_t)(n) & 0xFF00))\
+ | ((((uint32_t)(n) & 0xFF0000)) >> 16))
+#endif
+
+
+/**
+ * Convert 24 bit integer from network byte order to host byte order.
+ *
+ * @param n input value (int32_t)
+ * @return converted value (uint32_t)
+ */
+#if HAVE_BIG_ENDIAN
+#define NTOH24(n) n
+#else
+#define NTOH24(n) (((((uint32_t)(n) & 0xFF)) << 16)\
+ | (((uint32_t)(n) & 0xFF00))\
+ | ((((uint32_t)(n) & 0xFF0000)) >> 16))
+#endif
+
+
+/**
+ * Convert 31 bit integer from network byte order to host byte order.
+ *
+ * @param n input value (int32_t)
+ * @return converted value (uint32_t)
+ */
+#if HAVE_BIG_ENDIAN
+#define NTOH31(n) n
+#else
+#define NTOH31(n) (((((uint32_t)(n) & 0x7F)) << 24) | \
+ ((((uint32_t)(n) & 0xFF00)) << 8) | \
+ ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
+ ((((uint32_t)(n) & 0xFF000000)) >> 24))
+#endif
+
+
+/**
+ * Convert 31 bit integer from host byte order to network byte order.
+ *
+ * @param n input value (int32_t)
+ * @return converted value (uint32_t)
+ */
+#if HAVE_BIG_ENDIAN
+#define HTON31(n) n
+#else
+#define HTON31(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
+ ((((uint32_t)(n) & 0xFF00)) << 8) | \
+ ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
+ ((((uint32_t)(n) & 0x7F000000)) >> 24))
+#endif
+
+
+/**
+ * Print formatted debug value.
+ *
+ * @param fmt format (const char *)
+ * @param ... args for format
+ */
+#define SPDYF_DEBUG(fmt, ...) do { \
+ fprintf (stdout, "%s\n%u: ",__FILE__, __LINE__);\
+ fprintf(stdout,fmt,##__VA_ARGS__);\
+ fprintf(stdout,"\n");\
+ fflush(stdout); } while (0)
+
+
+/**
+ * Print stream for debuging.
+ *
+ * @param strm (void *)
+ * @param size (int)
+ */
+#define SPDYF_PRINT_STREAM(strm, size) do { \
+ int ___i;\
+ for(___i=0;___i<size;___i++){\
+ fprintf(stdout,"%x ",*((uint8_t *) strm + ___i));\
+ fflush(stdout);\
+ }\
+ fprintf(stdout,"\n");\
+ } while (0)
+
+
+/**
+ * Print message and raise SIGINT for debug purposes.
+ *
+ * @param msg message (const char *)
+ */
+#define SPDYF_SIGINT(msg) do { \
+ fprintf(stdout,"%i : %s\n", __LINE__,__FILE__);\
+ fprintf(stdout,msg);\
+ fprintf(stdout,"\n");\
+ fflush(stdout);\
+ raise(SIGINT); } while (0)
+
+
+/**
+ * Returns monotonic time, to be used for session timeouts.
+ *
+ * @return time in seconds
+ */
+time_t
+SPDYF_monotonic_time(void);
+
+#endif
Added: libmicrohttpd/src/microspdy/session.c
===================================================================
--- libmicrohttpd/src/microspdy/session.c (rev 0)
+++ libmicrohttpd/src/microspdy/session.c 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,1554 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file session.c
+ * @brief TCP connection/SPDY session handling. So far most of the
+ * functions for handling SPDY framing layer are here.
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "structures.h"
+#include "internal.h"
+#include "session.h"
+#include "compression.h"
+#include "tls.h"
+#include "stream.h"
+
+
+/**
+ * Handler for reading the full SYN_STREAM frame after we know that
+ * the frame is such.
+ * The function waits for the full frame and then changes status
+ * of the session. New stream is created.
+ *
+ * @param session SPDY_Session whose read buffer is used.
+ */
+static void
+spdyf_handler_read_syn_stream (struct SPDY_Session *session)
+{
+ size_t name_value_strm_size = 0;
+ uint compressed_data_size;
+ int ret;
+ void *name_value_strm = NULL;
+ struct SPDYF_Control_Frame *frame;
+ struct SPDY_NameValue *headers;
+
+ SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
+ || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
+ "the function is called wrong");
+
+ frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
+
+ //handle subheaders
+ if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
+ {
+ if(0 == frame->length)
+ {
+ //protocol error: incomplete frame
+ //we just ignore it since there is no stream id for
which to
+ //send RST_STREAM
+ //TODO maybe GOAWAY and closing session is appropriate
+ SPDYF_DEBUG("zero long SYN_STREAM received");
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+ free(frame);
+ return;
+ }
+
+ if(SPDY_YES != SPDYF_stream_new(session))
+ {
+ /* waiting for some more fields to create new stream
+ or something went wrong, SPDYF_stream_new has handled
the
+ situation */
+ return;
+ }
+
+ session->current_stream_id = session->streams_head->stream_id;
+ if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
+ {
+ //TODO no need to create stream if this happens
+ session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
+ return;
+ }
+ else
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
+ }
+
+ //handle body
+
+ //start reading the compressed name/value pairs (http headers)
+ compressed_data_size = frame->length //everything after length field
+ - 10;//4B stream id, 4B assoc strem id, 2B priority, unused and
slot
+
+ if(session->read_buffer_offset - session->read_buffer_beginning <
compressed_data_size)
+ {
+ // the full frame is not yet here, try later
+ return;
+ }
+
+ if(compressed_data_size > 0
+ && SPDY_YES != SPDYF_zlib_inflate(&session->zlib_recv_stream,
+ session->read_buffer +
session->read_buffer_beginning,
+ compressed_data_size,
+ &name_value_strm,
+ &name_value_strm_size))
+ {
+ /* something went wrong on inflating,
+ * the state of the stream for decompression is unknown
+ * and we may not be able to read anything more received on
+ * this session,
+ * so it is better to close the session */
+ free(name_value_strm);
+ free(frame);
+
+ /* mark the session for closing and close it, when
+ * everything on the output queue is already written */
+ session->status = SPDY_SESSION_STATUS_FLUSHING;
+
+ SPDYF_prepare_goaway(session,
SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
+
+ return;
+ }
+
+ if(0 == name_value_strm_size || 0 == compressed_data_size)
+ {
+ //Protocol error: send RST_STREAM
+ if(SPDY_YES != SPDYF_prepare_rst_stream(session,
session->current_stream_id,
+
SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR))
+ {
+ //no memory, try later to send RST
+ return;
+ }
+ }
+
+ ret = SPDYF_name_value_from_stream(name_value_strm,
name_value_strm_size, &headers);
+ if(SPDY_NO == ret)
+ {
+ //memory error, try later
+ free(name_value_strm);
+ return;
+ }
+
+ session->streams_head->headers = headers;
+ //inform the application layer for the new stream received
+ if(SPDY_YES != session->daemon->fnew_stream_cb(session->daemon->fcls,
session->streams_head))
+ {
+ //memory error, try later
+ free(name_value_strm);
+ return;
+ }
+
+ session->read_buffer_beginning += compressed_data_size;
+ //change state to wait for new frame
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+ free(frame);
+ free(name_value_strm);
+}
+
+
+/**
+ * Handler for reading the GOAWAY frame after we know that
+ * the frame is such.
+ * The function waits for the full frame and then changes status
+ * of the session.
+ *
+ * @param session SPDY_Session whose read buffer is used.
+ */
+static void
+spdyf_handler_read_goaway (struct SPDY_Session *session)
+{
+ struct SPDYF_Control_Frame *frame;
+ uint32_t last_good_stream_id;
+ uint32_t status_int;
+ enum SPDY_GOAWAY_STATUS status;
+
+ SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
+ "the function is called wrong");
+
+ frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
+
+ if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
+ {
+ //this is a protocol error/attack
+ session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
+ return;
+ }
+
+ if(0 != frame->flags || 8 != frame->length)
+ {
+ //this is a protocol error
+ SPDYF_DEBUG("wrong GOAWAY received");
+ //anyway, it will be handled
+ }
+
+ if((session->read_buffer_offset - session->read_buffer_beginning) <
frame->length)
+ {
+ //not all fields are received
+ //try later
+ return;
+ }
+
+ //mark that the session is almost closed
+ session->is_goaway_received = true;
+
+ if(8 == frame->length)
+ {
+ memcpy(&last_good_stream_id, session->read_buffer +
session->read_buffer_beginning, 4);
+ last_good_stream_id = NTOH31(last_good_stream_id);
+ session->read_buffer_beginning += 4;
+
+ memcpy(&status_int, session->read_buffer +
session->read_buffer_beginning, 4);
+ status = ntohl(status_int);
+ session->read_buffer_beginning += 4;
+
+ //TODO do something with last_good
+
+ //SPDYF_DEBUG("Received GOAWAY; status=%i;
lastgood=%i",status,last_good_stream_id);
+
+ //do something according to the status
+ //TODO
+ switch(status)
+ {
+ case SPDY_GOAWAY_STATUS_OK:
+ break;
+ case SPDY_GOAWAY_STATUS_PROTOCOL_ERROR:
+ break;
+ case SPDY_GOAWAY_STATUS_INTERNAL_ERROR:
+ break;
+ }
+ }
+
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+ free(frame);
+}
+
+
+/**
+ * Handler for reading RST_STREAM frames. After receiving the frame
+ * the stream moves into closed state and status
+ * of the session is changed. Frames, belonging to this stream, which
+ * are still at the output queue, will be ignored later.
+ *
+ * @param session SPDY_Session whose read buffer is used.
+ */
+static void
+spdyf_handler_read_rst_stream (struct SPDY_Session *session)
+{
+ struct SPDYF_Control_Frame *frame;
+ uint32_t stream_id;
+ int32_t status_int;
+ enum SPDY_RST_STREAM_STATUS status;
+ struct SPDYF_Stream *stream;
+
+ SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status,
+ "the function is called wrong");
+
+ frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
+
+ if(0 != frame->flags || 8 != frame->length)
+ {
+ //this is a protocol error
+ SPDYF_DEBUG("wrong RST_STREAM received");
+ //ignore as a large frame
+ session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
+ return;
+ }
+
+ if((session->read_buffer_offset - session->read_buffer_beginning) <
frame->length)
+ {
+ //not all fields are received
+ //try later
+ return;
+ }
+
+ memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning,
4);
+ stream_id = NTOH31(stream_id);
+ session->read_buffer_beginning += 4;
+
+ memcpy(&status_int, session->read_buffer + session->read_buffer_beginning,
4);
+ status = ntohl(status_int);
+ session->read_buffer_beginning += 4;
+
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+ free(frame);
+
+ //mark the stream as closed
+ stream = session->streams_head;
+ while(NULL != stream)
+ {
+ if(stream_id == stream->stream_id)
+ {
+ stream->is_in_closed = true;
+ stream->is_out_closed = true;
+ break;
+ }
+ stream = stream->next;
+ }
+
+ SPDYF_DEBUG("Received RST_STREAM; status=%i; id=%i",status,stream_id);
+
+ //do something according to the status
+ //TODO
+ /*switch(status)
+ {
+ case SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR:
+ break;
+ }*/
+}
+
+
+/**
+ * Handler for reading DATA frames. In requests they are used for POST
+ * arguments.
+ *
+ * @param session SPDY_Session whose read buffer is used.
+ */
+static void
+spdyf_handler_read_data (struct SPDY_Session *session)
+{
+ (void)session;
+ //TODO ignore data frames for now
+ SPDYF_PANIC("POST requests are Not yet implemented!");
+}
+
+
+int
+SPDYF_handler_write_syn_reply (struct SPDY_Session *session)
+{
+ struct SPDYF_Response_Queue *response_queue =
session->response_queue_head;
+ struct SPDYF_Stream *stream = response_queue->stream;
+ struct SPDYF_Control_Frame control_frame;
+ void *compressed_headers = NULL;
+ size_t compressed_headers_size=0;
+ size_t used_data=0;
+ size_t total_size;
+ uint32_t stream_id_nbo;
+
+ SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not
in the correct moment");
+
+ memcpy(&control_frame, response_queue->control_frame,
sizeof(control_frame));
+
+ if(SPDY_YES != SPDYF_zlib_deflate(&session->zlib_send_stream,
+ response_queue->data,
+ response_queue->data_size,
+ &used_data,
+ &compressed_headers,
+ &compressed_headers_size))
+ {
+ /* something went wrong on compressing,
+ * the state of the stream for compression is unknown
+ * and we may not be able to send anything more on
+ * this session,
+ * so it is better to close the session right now */
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+
+ free(compressed_headers);
+
+ return SPDY_NO;
+ }
+
+ //TODO do we need this used_Data
+ SPDYF_ASSERT(used_data == response_queue->data_size, "not everything
was used by zlib");
+
+ total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
+ + 4 // stream id as "subheader"
+ + compressed_headers_size;
+
+ if(NULL == (session->write_buffer = malloc(total_size)))
+ {
+ /* no memory
+ * since we do not save the compressed data anywhere and
+ * the sending zlib stream is already in new state, we must
+ * close the session */
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+
+ free(compressed_headers);
+
+ return SPDY_NO;
+ }
+ session->write_buffer_beginning = 0;
+ session->write_buffer_offset = 0;
+ session->write_buffer_size = total_size;
+
+ control_frame.length = compressed_headers_size + 4; // compressed data
+ stream_id
+ SPDYF_CONTROL_FRAME_HTON(&control_frame);
+
+ //put frame headers to write buffer
+ memcpy(session->write_buffer +
session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
+ session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
+
+ //put stream id to write buffer
+ stream_id_nbo = HTON31(stream->stream_id);
+ memcpy(session->write_buffer + session->write_buffer_offset,
&stream_id_nbo, 4);
+ session->write_buffer_offset += 4;
+
+ //put compressed name/value pairs to write buffer
+ memcpy(session->write_buffer + session->write_buffer_offset,
compressed_headers, compressed_headers_size);
+ session->write_buffer_offset += compressed_headers_size;
+
+ SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
+ SPDYF_ASSERT(session->write_buffer_offset ==
session->write_buffer_size, "bug2");
+
+ //DEBUG CODE, break compression state to see what happens
+/* SPDYF_zlib_deflate(&session->zlib_send_stream,
+ "1234567890",
+ 10,
+ &used_data,
+ &compressed_headers,
+ &compressed_headers_size);
+*/
+ free(compressed_headers);
+
+ session->last_replied_to_stream_id = stream->stream_id;
+
+ return SPDY_YES;
+}
+
+
+int
+SPDYF_handler_write_goaway (struct SPDY_Session *session)
+{
+ struct SPDYF_Response_Queue *response_queue =
session->response_queue_head;
+ struct SPDYF_Control_Frame control_frame;
+ size_t total_size;
+ int last_good_stream_id;
+
+ SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not
in the correct moment");
+
+ memcpy(&control_frame, response_queue->control_frame,
sizeof(control_frame));
+
+ session->is_goaway_sent = true;
+
+ total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
+ + 4 // last good stream id as "subheader"
+ + 4; // status code as "subheader"
+
+ if(NULL == (session->write_buffer = malloc(total_size)))
+ {
+ return SPDY_NO;
+ }
+ session->write_buffer_beginning = 0;
+ session->write_buffer_offset = 0;
+ session->write_buffer_size = total_size;
+
+ control_frame.length = 8; // always for GOAWAY
+ SPDYF_CONTROL_FRAME_HTON(&control_frame);
+
+ //put frame headers to write buffer
+ memcpy(session->write_buffer +
session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
+ session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
+
+ //put last good stream id to write buffer
+ last_good_stream_id = HTON31(session->last_replied_to_stream_id);
+ memcpy(session->write_buffer + session->write_buffer_offset,
&last_good_stream_id, 4);
+ session->write_buffer_offset += 4;
+
+ //put "data" to write buffer. This is the status
+ memcpy(session->write_buffer + session->write_buffer_offset,
response_queue->data, 4);
+ session->write_buffer_offset += 4;
+ //data is not freed by the destroy function so:
+ //free(response_queue->data);
+
+ SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
+ SPDYF_ASSERT(session->write_buffer_offset ==
session->write_buffer_size, "bug2");
+
+ return SPDY_YES;
+}
+
+
+int
+SPDYF_handler_write_data (struct SPDY_Session *session)
+{
+ struct SPDYF_Response_Queue *response_queue =
session->response_queue_head;
+ struct SPDYF_Response_Queue *new_response_queue;
+ size_t total_size;
+ struct SPDYF_Data_Frame data_frame;
+ ssize_t ret;
+ bool more;
+
+ SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not
in the correct moment");
+
+ memcpy(&data_frame, response_queue->data_frame, sizeof(data_frame));
+
+ if(NULL == response_queue->response->rcb)
+ {
+ //standard response with data into the struct
+ SPDYF_ASSERT(NULL != response_queue->data, "no data for the
response");
+
+ total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
+ + response_queue->data_size;
+
+ if(NULL == (session->write_buffer = malloc(total_size)))
+ {
+ return SPDY_NO;
+ }
+ session->write_buffer_beginning = 0;
+ session->write_buffer_offset = 0;
+ session->write_buffer_size = total_size;
+
+ data_frame.length = response_queue->data_size;
+ SPDYF_DATA_FRAME_HTON(&data_frame);
+
+ //put SPDY headers to the writing buffer
+ memcpy(session->write_buffer +
session->write_buffer_offset,&data_frame,sizeof(struct SPDYF_Data_Frame));
+ session->write_buffer_offset += sizeof(struct
SPDYF_Data_Frame);
+
+ //put data to the writing buffer
+ memcpy(session->write_buffer + session->write_buffer_offset,
response_queue->data, response_queue->data_size);
+ session->write_buffer_offset += response_queue->data_size;
+ }
+ else
+ {
+ /* response with callbacks. The lib will produce more than 1
+ * data frames
+ */
+
+ total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header
+ + SPDY_MAX_SUPPORTED_FRAME_SIZE; //max possible size
+
+ if(NULL == (session->write_buffer = malloc(total_size)))
+ {
+ return SPDY_NO;
+ }
+ session->write_buffer_beginning = 0;
+ session->write_buffer_offset = 0;
+ session->write_buffer_size = total_size;
+
+ ret =
response_queue->response->rcb(response_queue->response->rcb_cls,
+ session->write_buffer + sizeof(struct SPDYF_Data_Frame),
+ response_queue->response->rcb_block_size,
+ &more);
+
+ if(ret < 0 || ret > response_queue->response->rcb_block_size)
+ {
+ //TODO send RST_STREAM (app error)
+ //for now close session
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+
+ free(session->write_buffer);
+ return SPDY_NO;
+ }
+ if(0 == ret && more)
+ {
+ //the app couldn't write anything to buf but later will
+ free(session->write_buffer);
+ session->write_buffer = NULL;
+ session->write_buffer_size = 0;
+
+ if(NULL != response_queue->next)
+ {
+ //put the frame at the end of the queue
+ //otherwise - head of line blocking
+ session->response_queue_head =
response_queue->next;
+ session->response_queue_head->prev = NULL;
+ session->response_queue_tail->next =
response_queue;
+ response_queue->prev =
session->response_queue_tail;
+ response_queue->next = NULL;
+ session->response_queue_tail = response_queue;
+ }
+
+ return SPDY_YES;
+ }
+
+ if(more)
+ {
+ //create another response queue object to call the user
cb again
+ if(NULL == (new_response_queue =
SPDYF_response_queue_create(true,
+ NULL,
+ 0,
+
response_queue->response,
+ response_queue->stream,
+ false,
+ response_queue->frqcb,
+
response_queue->frqcb_cls,
+ response_queue->rrcb,
+
response_queue->rrcb_cls)))
+ {
+ //TODO send RST_STREAM
+ //for now close session
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+
+ free(session->write_buffer);
+ return SPDY_NO;
+ }
+
+ //put it at second position on the queue
+ new_response_queue->prev = response_queue;
+ new_response_queue->next = response_queue->next;
+ if(NULL == response_queue->next)
+ {
+ session->response_queue_tail =
new_response_queue;
+ }
+ else
+ {
+ response_queue->next->prev = new_response_queue;
+ }
+ response_queue->next = new_response_queue;
+
+ response_queue->frqcb = NULL;
+ response_queue->frqcb_cls = NULL;
+ response_queue->rrcb = NULL;
+ response_queue->rrcb_cls = NULL;
+ }
+ else
+ {
+ data_frame.flags |= SPDY_DATA_FLAG_FIN;
+ }
+
+ data_frame.length = ret;
+ SPDYF_DATA_FRAME_HTON(&data_frame);
+
+ //put SPDY headers to the writing buffer
+ memcpy(session->write_buffer + session->write_buffer_offset,
+ &data_frame,
+ sizeof(struct SPDYF_Data_Frame));
+ session->write_buffer_offset += sizeof(struct
SPDYF_Data_Frame);
+ session->write_buffer_offset += ret;
+ session->write_buffer_size = session->write_buffer_offset;
+ }
+
+ SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
+ SPDYF_ASSERT(session->write_buffer_offset ==
session->write_buffer_size, "bug2");
+
+ return SPDY_YES;
+}
+
+
+int
+SPDYF_handler_write_rst_stream (struct SPDY_Session *session)
+{
+ struct SPDYF_Response_Queue *response_queue =
session->response_queue_head;
+ struct SPDYF_Control_Frame control_frame;
+ size_t total_size;
+
+ SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not
in the correct moment");
+
+ memcpy(&control_frame, response_queue->control_frame,
sizeof(control_frame));
+
+ total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header
+ + 4 // stream id as "subheader"
+ + 4; // status code as "subheader"
+
+ if(NULL == (session->write_buffer = malloc(total_size)))
+ {
+ return SPDY_NO;
+ }
+ session->write_buffer_beginning = 0;
+ session->write_buffer_offset = 0;
+ session->write_buffer_size = total_size;
+
+ control_frame.length = 8; // always for RST_STREAM
+ SPDYF_CONTROL_FRAME_HTON(&control_frame);
+
+ //put frame headers to write buffer
+ memcpy(session->write_buffer +
session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame));
+ session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame);
+
+ //put stream id to write buffer. This is the status
+ memcpy(session->write_buffer + session->write_buffer_offset,
response_queue->data, 8);
+ session->write_buffer_offset += 8;
+ //data is not freed by the destroy function so:
+ //free(response_queue->data);
+
+ SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1");
+ SPDYF_ASSERT(session->write_buffer_offset ==
session->write_buffer_size, "bug2");
+
+ return SPDY_YES;
+}
+
+
+void
+SPDYF_handler_ignore_frame (struct SPDY_Session *session)
+{
+ struct SPDYF_Control_Frame *frame;
+
+ SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
+ || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
+ "the function is called wrong");
+
+
+ frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
+
+ //handle subheaders
+ if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status)
+ {
+ if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE)
+ {
+ session->status = SPDY_SESSION_STATUS_IGNORE_BYTES;
+ return;
+ }
+ else
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY;
+ }
+
+ //handle body
+
+ if(session->read_buffer_offset - session->read_buffer_beginning
+ >= frame->length)
+ {
+ session->read_buffer_beginning += frame->length;
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+ free(frame);
+ }
+}
+
+
+int
+SPDYF_session_read (struct SPDY_Session *session)
+{
+ int bytes_read;
+ bool reallocate;
+ size_t actual_buf_size;
+
+ if(SPDY_SESSION_STATUS_CLOSING == session->status
+ || SPDY_SESSION_STATUS_FLUSHING == session->status)
+ return SPDY_NO;
+
+ //if the read buffer is full to the end, we need to reallocate space
+ if (session->read_buffer_size == session->read_buffer_offset)
+ {
+ //but only if the state of the session requires it
+ //i.e. no further proceeding is possible without reallocation
+ reallocate = false;
+ actual_buf_size = session->read_buffer_offset
+ - session->read_buffer_beginning;
+ switch(session->status)
+ {
+ case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
+
+ case SPDY_SESSION_STATUS_IGNORE_BYTES:
+ //we need space for a whole control frame header
+ if(actual_buf_size < sizeof(struct
SPDYF_Control_Frame))
+ reallocate = true;
+ break;
+
+ case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
+
+ case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
+ //we need as many bytes as set in length field
of the
+ //header
+ SPDYF_ASSERT(NULL != session->frame_handler_cls,
+ "no frame for session");
+ if(session->frame_handler !=
&spdyf_handler_read_data)
+ {
+ if(actual_buf_size
+ < ((struct SPDYF_Control_Frame
*)session->frame_handler_cls)->length)
+ reallocate = true;
+ }
+ else
+ {
+ if(actual_buf_size
+ < ((struct SPDYF_Data_Frame
*)session->frame_handler_cls)->length)
+ reallocate = true;
+ }
+ break;
+
+ case SPDY_SESSION_STATUS_CLOSING:
+ case SPDY_SESSION_STATUS_FLUSHING:
+ //nothing needed
+ break;
+ }
+
+ if(reallocate)
+ {
+ //reuse the space in the buffer that was already read
by the lib
+ memmove(session->read_buffer,
+ session->read_buffer +
session->read_buffer_beginning,
+ session->read_buffer_offset -
session->read_buffer_beginning);
+
+ session->read_buffer_offset -=
session->read_buffer_beginning;
+ session->read_buffer_beginning = 0;
+ }
+ else
+ {
+ //will read next time
+ //TODO optimize it, memmove more often?
+ return SPDY_NO;
+ }
+ }
+
+ session->last_activity = SPDYF_monotonic_time();
+
+ //actual read from the TLS socket
+ bytes_read = SPDYF_tls_recv(session,
+ session->read_buffer +
session->read_buffer_offset,
+ session->read_buffer_size -
session->read_buffer_offset);
+
+ switch(bytes_read)
+ {
+ case SPDY_TLS_ERROR_CLOSED:
+ //The TLS connection was closed by the other party,
clean
+ //or not
+ shutdown (session->socket_fd, SHUT_RD);
+ session->read_closed = true;
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+ return SPDY_YES;
+
+ case SPDY_TLS_ERROR_ERROR:
+ //any kind of error in the TLS subsystem
+ //try to prepare GOAWAY frame
+ SPDYF_prepare_goaway(session,
SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false);
+ //try to flush the queue when write is called
+ session->status = SPDY_SESSION_STATUS_FLUSHING;
+ return SPDY_YES;
+
+ case SPDY_TLS_ERROR_AGAIN:
+ //read or write should be called again; leave it for the
+ //next time
+ return SPDY_NO;
+
+ //default:
+ //something was really read from the TLS subsystem
+ //just continue
+ }
+
+ session->read_buffer_offset += bytes_read;
+
+ return SPDY_YES;
+}
+
+
+int
+SPDYF_session_write (struct SPDY_Session *session, bool only_one_frame)
+{
+ int i;
+ int bytes_written;
+ struct SPDYF_Response_Queue *queue_head;
+ struct SPDYF_Response_Queue *response_queue;
+
+ if(SPDY_SESSION_STATUS_CLOSING == session->status)
+ return SPDY_NO;
+
+ for(i=0;
+ only_one_frame
+ ? i < 1
+ : i < SPDYF_NUM_SENT_FRAMES_AT_ONCE;
+ ++i)
+ {
+ //if the buffer is not null, part of the last frame is still
+ //pending to be sent
+ if(NULL == session->write_buffer)
+ {
+ //discard frames on closed streams
+ response_queue = session->response_queue_head;
+
+ while(NULL != response_queue)
+ {
+ //if stream is closed, remove not yet sent
frames
+ //associated with it
+ //GOAWAY frames are not associated to streams
+ //and still need to be sent
+ if(NULL == response_queue->stream
+ ||
!response_queue->stream->is_out_closed)
+ break;
+
+
DLL_remove(session->response_queue_head,session->response_queue_tail,response_queue);
+
+ if(NULL != response_queue->frqcb)
+ {
+
response_queue->frqcb(response_queue->frqcb_cls, response_queue,
SPDY_RESPONSE_RESULT_STREAM_CLOSED);
+ }
+
+ SPDYF_response_queue_destroy(response_queue);
+ response_queue = session->response_queue_head;
+ }
+
+ if(NULL == session->response_queue_head)
+ break;//nothing on the queue
+
+ //get next data from queue and put it to the write
buffer
+ // to send it
+ if(SPDY_NO ==
session->response_queue_head->process_response_handler(session))
+ {
+ //error occured and the handler changed or not
the
+ //session's status appropriately
+ if(SPDY_SESSION_STATUS_CLOSING ==
session->status)
+ {
+ //try to send GOAWAY first if the
current frame is different
+ if(session->response_queue_head->is_data
+ ||
SPDY_CONTROL_FRAME_TYPES_GOAWAY
+ !=
session->response_queue_head->control_frame->type)
+ {
+ session->status =
SPDY_SESSION_STATUS_FLUSHING;
+ SPDYF_prepare_goaway(session,
SPDY_GOAWAY_STATUS_INTERNAL_ERROR, true);
+
SPDYF_session_write(session,true);
+ session->status =
SPDY_SESSION_STATUS_CLOSING;
+ }
+ return SPDY_YES;
+ }
+
+ //just return from the loop to return from this
function
+ break;
+ }
+
+ //check if something was prepared for writing
+ //on respones with callbacks it is possible that their
is no
+ //data available
+ if(0 == session->write_buffer_size)//nothing to write
+ if(response_queue !=
session->response_queue_head)
+ {
+ //the handler modified the queue
+ continue;
+ }
+ else
+ {
+ //no need to try the same frame again
+ break;
+ }
+ }
+
+ session->last_activity = SPDYF_monotonic_time();
+
+ //actual write to the TLS socket
+ bytes_written = SPDYF_tls_send(session,
+ session->write_buffer + session->write_buffer_beginning,
+ session->write_buffer_offset -
session->write_buffer_beginning);
+
+ switch(bytes_written)
+ {
+ case SPDY_TLS_ERROR_CLOSED:
+ //The TLS connection was closed by the other
party, clean
+ //or not
+ shutdown (session->socket_fd, SHUT_RD);
+ session->read_closed = true;
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+ return SPDY_YES;
+
+ case SPDY_TLS_ERROR_ERROR:
+ //any kind of error in the TLS subsystem
+ //forbid more writing
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+ return SPDY_YES;
+
+ case SPDY_TLS_ERROR_AGAIN:
+ //read or write should be called again; leave
it for the
+ //next time; return from the function as we do
not now
+ //whether reading or writing is needed
+ return i>0 ? SPDY_YES : SPDY_NO;
+
+ //default:
+ //something was really read from the TLS
subsystem
+ //just continue
+ }
+
+ session->write_buffer_beginning += bytes_written;
+
+ //check if the full buffer was written
+ if(session->write_buffer_beginning ==
session->write_buffer_size)
+ {
+ //that response is handled, remove it from queue
+ free(session->write_buffer);
+ session->write_buffer = NULL;
+ session->write_buffer_size = 0;
+ queue_head = session->response_queue_head;
+ if(NULL == queue_head->next)
+ {
+ session->response_queue_head = NULL;
+ session->response_queue_tail = NULL;
+ }
+ else
+ {
+ session->response_queue_head = queue_head->next;
+ session->response_queue_head->prev = NULL;
+ }
+
+ //set stream to closed if the frame's fin flag is set
+ SPDYF_stream_set_flags(queue_head);
+
+ if(NULL != queue_head->frqcb)
+ {
+ //application layer callback to notify sending
of the response
+ queue_head->frqcb(queue_head->frqcb_cls,
queue_head, SPDY_RESPONSE_RESULT_SUCCESS);
+ }
+
+ SPDYF_response_queue_destroy(queue_head);
+ }
+ }
+
+ if(SPDY_SESSION_STATUS_FLUSHING == session->status
+ && NULL == session->response_queue_head)
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+
+ return i>0 ? SPDY_YES : SPDY_NO;
+}
+
+
+int
+SPDYF_session_idle (struct SPDY_Session *session)
+{
+ size_t read_buffer_beginning;
+ size_t frame_length;
+ struct SPDYF_Control_Frame* control_frame;
+ struct SPDYF_Data_Frame *data_frame;
+
+ //prepare session for closing if timeout is used and already passed
+ if(SPDY_SESSION_STATUS_CLOSING != session->status
+ && session->daemon->session_timeout
+ && (session->last_activity + session->daemon->session_timeout <
SPDYF_monotonic_time()))
+ {
+ session->status = SPDY_SESSION_STATUS_CLOSING;
+ //best effort for sending GOAWAY
+ SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true);
+ SPDYF_session_write(session,true);
+ }
+
+ switch(session->status)
+ {
+ //expect new frame to arrive
+ case SPDY_SESSION_STATUS_WAIT_FOR_HEADER:
+ session->current_stream_id = 0;
+ //check if the whole frame header is already here
+ //both frame types have the same length
+ if(session->read_buffer_offset -
session->read_buffer_beginning
+ < sizeof(struct SPDYF_Control_Frame))
+ return SPDY_NO;
+
+ /* check the first bit to see if it is data or control
frame
+ * and also if the version is supported */
+ if(0x80 == *(uint8_t *)(session->read_buffer +
session->read_buffer_beginning)
+ && SPDY_VERSION == *((uint8_t
*)session->read_buffer + session->read_buffer_beginning + 1))
+ {
+ //control frame
+ if(NULL == (control_frame =
malloc(sizeof(struct SPDYF_Control_Frame))))
+ {
+ SPDYF_DEBUG("No memory");
+ return SPDY_NO;
+ }
+
+ //get frame headers
+ memcpy(control_frame,
+ session->read_buffer +
session->read_buffer_beginning,
+ sizeof(struct SPDYF_Control_Frame));
+ session->read_buffer_beginning += sizeof(struct
SPDYF_Control_Frame);
+ SPDYF_CONTROL_FRAME_NTOH(control_frame);
+
+ session->status =
SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER;
+ //assign different frame handler according to
frame type
+ switch(control_frame->type){
+ case
SPDY_CONTROL_FRAME_TYPES_SYN_STREAM:
+ session->frame_handler =
&spdyf_handler_read_syn_stream;
+ break;
+ case SPDY_CONTROL_FRAME_TYPES_GOAWAY:
+ session->frame_handler =
&spdyf_handler_read_goaway;
+ break;
+ case
SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
+ session->frame_handler =
&spdyf_handler_read_rst_stream;
+ break;
+ default:
+ session->frame_handler =
&SPDYF_handler_ignore_frame;
+ }
+ session->frame_handler_cls = control_frame;
+ //DO NOT break the outer case
+ }
+ else if(0 == *(uint8_t *)(session->read_buffer +
session->read_buffer_beginning))
+ {
+ //needed for POST
+ //data frame
+ if(NULL == (data_frame = malloc(sizeof(struct
SPDYF_Data_Frame))))
+ {
+ SPDYF_DEBUG("No memory");
+ return SPDY_NO;
+ }
+
+ //get frame headers
+ memcpy(data_frame,
+ session->read_buffer +
session->read_buffer_beginning,
+ sizeof(struct SPDYF_Data_Frame));
+ session->read_buffer_beginning += sizeof(struct
SPDYF_Data_Frame);
+
+ session->status =
SPDY_SESSION_STATUS_WAIT_FOR_BODY;
+ session->frame_handler =
&spdyf_handler_read_data;
+ session->frame_handler_cls = data_frame;
+ //DO NOT brake the outer case
+ }
+ else
+ {
+ SPDYF_DEBUG("another protocol or version
received!");
+
+ /* According to the draft the lib should send
here
+ * RST_STREAM with status UNSUPPORTED_VERSION.
I don't
+ * see any sense of keeping the session open
since
+ * we don't know how many bytes is the bogus
"frame".
+ * And the latter normally will be HTTP request.
+ *
+ */
+
+ //shutdown(session->socket_fd, SHUT_RD);
+ session->status = SPDY_SESSION_STATUS_FLUSHING;
+ SPDYF_prepare_goaway(session,
SPDY_GOAWAY_STATUS_PROTOCOL_ERROR,false);
+ //SPDYF_session_write(session,false);
+ /* close connection since the client expects
another
+ protocol from us */
+ //SPDYF_session_close(session);
+ return SPDY_YES;
+ }
+
+ //expect specific header fields after the standard header
+ case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER:
+ if(NULL!=session->frame_handler)
+ {
+ read_buffer_beginning =
session->read_buffer_beginning;
+ //if everything is ok, the "body" will also be
processed
+ //by the handler
+ session->frame_handler(session);
+
+ if(SPDY_SESSION_STATUS_IGNORE_BYTES ==
session->status)
+ {
+ //check for larger than max supported
frame
+ if(session->frame_handler !=
&spdyf_handler_read_data)
+ {
+ frame_length = ((struct
SPDYF_Control_Frame *)session->frame_handler_cls)->length;
+ }
+ else
+ {
+ frame_length = ((struct
SPDYF_Data_Frame *)session->frame_handler_cls)->length;
+ }
+
+ //if(SPDY_MAX_SUPPORTED_FRAME_SIZE <
frame_length)
+ {
+ SPDYF_DEBUG("received frame
with unsupported size: %zu", frame_length);
+ //the data being received must
be ignored and
+ //RST_STREAM sent
+
+ //ignore bytes that will arive
later
+ session->read_ignore_bytes =
frame_length
+ + read_buffer_beginning
+ -
session->read_buffer_offset;
+ //ignore what is already in
read buffer
+ session->read_buffer_beginning
= session->read_buffer_offset;
+
+
SPDYF_prepare_rst_stream(session,
+
session->current_stream_id, //may be 0 here which is not good
+
SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE);
+
+ //actually the read buffer can
be bigger than the
+ //max supported size
+ session->status =
session->read_ignore_bytes
+ ?
SPDY_SESSION_STATUS_IGNORE_BYTES
+ :
SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+
+
free(session->frame_handler_cls);
+ }
+ }
+ }
+
+ if(SPDY_SESSION_STATUS_IGNORE_BYTES != session->status)
+ {
+ break;
+ }
+
+ //ignoring data in read buffer
+ case SPDY_SESSION_STATUS_IGNORE_BYTES:
+ SPDYF_ASSERT(session->read_ignore_bytes > 0,
+ "Session is in wrong state");
+ if(session->read_ignore_bytes
+ > session->read_buffer_offset -
session->read_buffer_beginning)
+ {
+ session->read_ignore_bytes -=
+ session->read_buffer_offset -
session->read_buffer_beginning;
+ session->read_buffer_beginning =
session->read_buffer_offset;
+ }
+ else
+ {
+ session->read_buffer_beginning +=
session->read_ignore_bytes;
+ session->read_ignore_bytes = 0;
+ session->status =
SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+ }
+ break;
+
+ //expect frame body (name/value pairs)
+ case SPDY_SESSION_STATUS_WAIT_FOR_BODY:
+ if(NULL!=session->frame_handler)
+ session->frame_handler(session);
+ break;
+
+ case SPDY_SESSION_STATUS_FLUSHING:
+
+ return SPDY_NO;
+
+ //because of error the session needs to be closed
+ case SPDY_SESSION_STATUS_CLOSING:
+ //error should be already sent to the client
+ SPDYF_session_close(session);
+ return SPDY_YES;
+ }
+
+ return SPDY_YES;
+}
+
+
+void
+SPDYF_session_close (struct SPDY_Session *session)
+{
+ struct SPDY_Daemon *daemon = session->daemon;
+ int by_client = session->read_closed ? SPDY_YES : SPDY_NO;
+
+ //shutdown the tls and deinit the tls context
+ SPDYF_tls_close_session(session);
+ shutdown (session->socket_fd,
+ session->read_closed ? SHUT_WR : SHUT_RDWR);
+ session->read_closed = true;
+
+ //remove session from the list
+ DLL_remove (daemon->sessions_head,
+ daemon->sessions_tail,
+ session);
+ //add the session for the list for cleaning up
+ DLL_insert (daemon->cleanup_head,
+ daemon->cleanup_tail,
+ session);
+
+ //call callback for closed session
+ if(NULL != daemon->session_closed_cb)
+ {
+ daemon->session_closed_cb(daemon->cls, session, by_client);
+ }
+}
+
+
+int
+SPDYF_session_accept(struct SPDY_Daemon *daemon)
+{
+ int new_socket_fd;
+ //int fd_flags;
+ struct SPDY_Session *session = NULL;
+ socklen_t addr_len;
+ struct sockaddr *addr;
+#if HAVE_INET6
+ struct sockaddr_in6 addr6;
+
+ addr = (struct sockaddr *)&addr6;
+ addr_len = sizeof(addr6);
+#else
+ struct sockaddr_in addr4;
+
+ addr = (struct sockaddr *)&addr4;
+ addr_len = sizeof(addr6);
+#endif
+
+ new_socket_fd = accept (daemon->socket_fd, addr, &addr_len);
+
+ if(new_socket_fd < 1)
+ return SPDY_NO;
+
+ //setting the socket to be non-blocking
+ /*
+ * different handling is needed by libssl if non-blocking is used
+ *
+ fd_flags = fcntl (new_socket_fd, F_GETFL);
+ if ( -1 == fd_flags
+ || 0 != fcntl (new_socket_fd, F_SETFL, fd_flags | O_NONBLOCK))
+ {
+ SPDYF_DEBUG("WARNING: Couldn't set the new connection to be
non-blocking");
+ }
+ */
+
+ if (NULL == (session = malloc (sizeof (struct SPDY_Session))))
+ {
+ goto free_and_fail;
+ }
+ memset (session, 0, sizeof (struct SPDY_Session));
+
+ session->daemon = daemon;
+ session->socket_fd = new_socket_fd;
+
+ //init TLS context, handshake will be done
+ if(SPDY_YES != SPDYF_tls_new_session(session))
+ {
+ goto free_and_fail;
+ }
+
+ //read buffer
+ session->read_buffer_size = SPDYF_BUFFER_SIZE;
+ if (NULL == (session->read_buffer = malloc (session->read_buffer_size)))
+ {
+ SPDYF_tls_close_session(session);
+ goto free_and_fail;
+ }
+
+ //address of the client
+ if (NULL == (session->addr = malloc (addr_len)))
+ {
+ SPDYF_tls_close_session(session);
+ goto free_and_fail;
+ }
+ memcpy (session->addr, addr, addr_len);
+
+ session->addr_len = addr_len;
+ session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
+
+ //init zlib context for the whole session
+ if(SPDY_YES != SPDYF_zlib_deflate_init(&session->zlib_send_stream))
+ {
+ SPDYF_tls_close_session(session);
+ goto free_and_fail;
+ }
+ if(SPDY_YES != SPDYF_zlib_inflate_init(&session->zlib_recv_stream))
+ {
+ SPDYF_tls_close_session(session);
+ SPDYF_zlib_deflate_end(&session->zlib_send_stream);
+ goto free_and_fail;
+ }
+
+ //add it to daemon's list
+ DLL_insert(daemon->sessions_head,daemon->sessions_tail,session);
+
+ session->last_activity = SPDYF_monotonic_time();
+
+ if(NULL != daemon->new_session_cb)
+ daemon->new_session_cb(daemon->cls, session);
+
+ return SPDY_YES;
+
+ //for GOTO
+ free_and_fail:
+ /* something failed, so shutdown, close and free memory */
+ shutdown (new_socket_fd, SHUT_RDWR);
+ close (new_socket_fd);
+
+ if(NULL != session)
+ {
+ if(NULL != session->addr)
+ free (session->addr);
+ if(NULL != session->read_buffer)
+ free (session->read_buffer);
+ free (session);
+ }
+ return SPDY_NO;
+}
+
+
+void
+SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
+ struct SPDY_Session *session,
+ int consider_priority)
+{
+ struct SPDYF_Response_Queue *pos;
+ struct SPDYF_Response_Queue *last;
+ uint8_t priority;
+
+ SPDYF_ASSERT(SPDY_YES != consider_priority || NULL !=
response_to_queue->stream,
+ "called with consider_priority but no stream provided");
+
+ last = response_to_queue;
+ while(NULL != last->next)
+ {
+ last = last->next;
+ }
+
+ if(SPDY_NO == consider_priority)
+ {
+ //put it at the end of the queue
+ response_to_queue->prev = session->response_queue_tail;
+ if (NULL == session->response_queue_head)
+ session->response_queue_head = response_to_queue;
+ else
+ session->response_queue_tail->next = response_to_queue;
+ session->response_queue_tail = last;
+ return;
+ }
+ else if(-1 == consider_priority)
+ {
+ //put it at the head of the queue
+ last->next = session->response_queue_head;
+ if (NULL == session->response_queue_tail)
+ session->response_queue_tail = last;
+ else
+ session->response_queue_head->prev = response_to_queue;
+ session->response_queue_head = response_to_queue;
+ return;
+ }
+
+ if(NULL == session->response_queue_tail)
+ {
+ session->response_queue_head = response_to_queue;
+ session->response_queue_tail = last;
+ return;
+ }
+
+ //search for the right position to put it
+ pos = session->response_queue_tail;
+ priority = response_to_queue->stream->priority;
+ while(NULL != pos
+ && pos->stream->priority > priority)
+ {
+ pos = pos->prev;
+ }
+
+ if(NULL == pos)
+ {
+ //put it on the head
+ session->response_queue_head->prev = last;
+ last->next = session->response_queue_head;
+ session->response_queue_head = response_to_queue;
+ }
+ else if(NULL == pos->next)
+ {
+ //put it at the end
+ response_to_queue->prev = pos;
+ pos->next = response_to_queue;
+ session->response_queue_tail = last;
+ }
+ else
+ {
+ response_to_queue->prev = pos;
+ last->next = pos->next;
+ pos->next = response_to_queue;
+ last->next->prev = last;
+ }
+}
+
+
+void
+SPDYF_session_destroy(struct SPDY_Session *session)
+{
+ struct SPDYF_Stream *stream;
+ struct SPDYF_Response_Queue *response_queue;
+
+ close (session->socket_fd);
+ SPDYF_zlib_deflate_end(&session->zlib_send_stream);
+ SPDYF_zlib_inflate_end(&session->zlib_recv_stream);
+
+ //clean up unsent data in the output queue
+ while (NULL != (response_queue = session->response_queue_head))
+ {
+ DLL_remove (session->response_queue_head,
+ session->response_queue_tail,
+ response_queue);
+
+ if(NULL != response_queue->frqcb)
+ {
+ response_queue->frqcb(response_queue->frqcb_cls,
response_queue, SPDY_RESPONSE_RESULT_SESSION_CLOSED);
+ }
+
+ SPDYF_response_queue_destroy(response_queue);
+ }
+
+ //clean up the streams belonging to this session
+ while (NULL != (stream = session->streams_head))
+ {
+ DLL_remove (session->streams_head,
+ session->streams_tail,
+ stream);
+
+ SPDYF_stream_destroy(stream);
+ }
+
+ free(session->addr);
+ free(session->read_buffer);
+ free(session->write_buffer);
+ free(session);
+}
+
+
+int
+SPDYF_prepare_goaway (struct SPDY_Session *session,
+ enum SPDY_GOAWAY_STATUS status,
+ bool in_front)
+{
+ struct SPDYF_Response_Queue *response_to_queue;
+ struct SPDYF_Control_Frame *control_frame;
+ uint32_t *data;
+
+ if(NULL == (response_to_queue = malloc(sizeof(struct
SPDYF_Response_Queue))))
+ {
+ return SPDY_NO;
+ }
+ memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
+
+ if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
+ {
+ free(response_to_queue);
+ return SPDY_NO;
+ }
+ memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
+
+ if(NULL == (data = malloc(4)))
+ {
+ free(control_frame);
+ free(response_to_queue);
+ return SPDY_NO;
+ }
+ *(data) = htonl(status);
+
+ control_frame->control_bit = 1;
+ control_frame->version = SPDY_VERSION;
+ control_frame->type = SPDY_CONTROL_FRAME_TYPES_GOAWAY;
+ control_frame->flags = 0;
+
+ response_to_queue->control_frame = control_frame;
+ response_to_queue->process_response_handler =
&SPDYF_handler_write_goaway;
+ response_to_queue->data = data;
+ response_to_queue->data_size = 4;
+
+ SPDYF_queue_response (response_to_queue,
+ session,
+ in_front ? -1 : SPDY_NO);
+
+ return SPDY_YES;
+}
+
+
+int
+SPDYF_prepare_rst_stream (struct SPDY_Session *session,
+ uint32_t stream_id,
+ enum SPDY_RST_STREAM_STATUS status)
+{
+ struct SPDYF_Response_Queue *response_to_queue;
+ struct SPDYF_Control_Frame *control_frame;
+ uint32_t *data;
+
+ if(NULL == (response_to_queue = malloc(sizeof(struct
SPDYF_Response_Queue))))
+ {
+ return SPDY_NO;
+ }
+ memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
+
+ if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
+ {
+ free(response_to_queue);
+ return SPDY_NO;
+ }
+ memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
+
+ if(NULL == (data = malloc(8)))
+ {
+ free(control_frame);
+ free(response_to_queue);
+ return SPDY_NO;
+ }
+ *(data) = HTON31(stream_id);
+ *(data + 1) = htonl(status);
+
+ control_frame->control_bit = 1;
+ control_frame->version = SPDY_VERSION;
+ control_frame->type = SPDY_CONTROL_FRAME_TYPES_RST_STREAM;
+ control_frame->flags = 0;
+
+ response_to_queue->control_frame = control_frame;
+ response_to_queue->process_response_handler =
&SPDYF_handler_write_rst_stream;
+ response_to_queue->data = data;
+ response_to_queue->data_size = 8;
+
+ SPDYF_queue_response (response_to_queue,
+ session,
+ -1);
+
+ return SPDY_YES;
+}
Added: libmicrohttpd/src/microspdy/session.h
===================================================================
--- libmicrohttpd/src/microspdy/session.h (rev 0)
+++ libmicrohttpd/src/microspdy/session.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,248 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file session.h
+ * @brief TCP connection/SPDY session handling
+ * @author Andrey Uzunov
+ */
+
+#ifndef SESSION_H
+#define SESSION_H
+
+#include "platform.h"
+#include "structures.h"
+
+/**
+ * Called by the daemon when the socket for the session has available
+ * data to be read. Reads data from the TLS socket and puts it to the
+ * session's read buffer. The latte
+ *
+ * @param session SPDY_Session for which data will be read.
+ * @return SPDY_YES if something was read or session's status was
+ * changed. It is possible that error occurred but was handled
+ * and the status was therefore changed.
+ * SPDY_NO if nothing happened, e.g. the subsystem wants read/
+ * write to be called again.
+ */
+int
+SPDYF_session_read (struct SPDY_Session *session);
+
+
+/**
+ * Called by the daemon when the socket for the session is ready for some
+ * data to be written to it. For one or more objects on the response
+ * queue tries to fill in the write buffer, based on the frame on the
+ * queue, and to write data to the TLS socket.
+ *
+ * @param session SPDY_Session for which data will be written.
+ * @return TODO document after changes
+ * SPDY_YES if something was written, the status was changed or
+ * response callback was called but did not provide data
+ * @return SPDY_YES if something was written, session's status was
+ * changed or response callback was called but did not provide
+ * data. It is possible that error occurred but was handled
+ * and the status was therefore changed.
+ * SPDY_NO if nothing happened, e.g. the subsystem wants read/
+ * write to be called again. However, it is possible that some
+ * frames were discarded within the call, e.g. frames belonging
+ * to a closed stream.
+ */
+int
+SPDYF_session_write (struct SPDY_Session *session, bool only_one_frame);
+
+
+/**
+ * Called by the daemon on SPDY_run to handle the data in the read and write
+ * buffer of a session. Based on the state and the content of the read
+ * buffer new frames are received and interpreted, appropriate user
+ * callbacks are called and maybe something is put on the response queue
+ * ready to be handled by session_write.
+ *
+ * @param session SPDY_Session which will be handled.
+ * @return SPDY_YES if something from the read buffers was processed,
+ * session's status was changed and/or the session was closed.
+ * SPDY_NO if nothing happened, e.g. the session is in a state,
+ * not allowing processing read buffers.
+ */
+int
+SPDYF_session_idle (struct SPDY_Session *session);
+
+
+/**
+ * This function shutdowns the socket, moves the session structure to
+ * daemon's queue for sessions to be cleaned up.
+ *
+ * @param session SPDY_Session which will be handled.
+ */
+void
+SPDYF_session_close (struct SPDY_Session *session);
+
+
+/**
+ * Called to accept new TCP connection and create SPDY session.
+ *
+ * @param daemon SPDY_Daemon whose listening socket is used.
+ * @return SPDY_NO on any kind of error while accepting new TCP connection
+ * and initializing new SPDY_Session.
+ * SPDY_YES otherwise.
+ */
+int
+SPDYF_session_accept(struct SPDY_Daemon *daemon);
+
+
+/**
+ * Puts SPDYF_Response_Queue object on the queue to be sent to the
+ * client later.
+ *
+ * @param response_to_queue linked list of objects containing SPDY
+ * frame and data to be added to the queue
+ * @param session SPDY session for which the response is sent
+ * @param consider_priority if SPDY_NO, the list will be added to the
+ * end of the queue.
+ * If SPDY_YES, the response will be added after
+ * the last previously added response with priority of the
+ * request grater or equal to that of the current one.
+ * If -1, the object will be put at the head of the queue.
+ */
+void
+SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
+ struct SPDY_Session *session,
+ int consider_priority);
+
+
+/**
+ * Cleans up the TSL context for the session, closes the TCP connection,
+ * cleans up any data pointed by members of the session structure
+ * (buffers, queue of responses, etc.) and frees the memory allocated by
+ * the session itself.
+ */
+void
+SPDYF_session_destroy(struct SPDY_Session *session);
+
+
+/**
+ * Prepares GOAWAY frame to tell the client to stop creating new streams.
+ * The session should be closed soon after this call.
+ *
+ * @param session SPDY session
+ * @param status code for the GOAWAY frame
+ * @param in_front whether or not to put the frame in front of everything
+ * on the response queue
+ * @return SPDY_NO on error (not enough memory) or
+ * SPDY_YES on success
+ */
+int
+SPDYF_prepare_goaway (struct SPDY_Session *session,
+ enum SPDY_GOAWAY_STATUS status,
+ bool in_front);
+
+
+/**
+ * Prepares RST_STREAM frame to terminate a stream. This frame may or
+ * not indicate an error. The frame will be put at the head of the queue.
+ * This means that frames for this stream which are still in the queue
+ * will be discarded soon.
+ *
+ * @param session SPDY session
+ * @param stream_id stream to terminate
+ * @param status code for the RST_STREAM frame
+ * @return SPDY_NO on memory error or
+ * SPDY_YES on success
+ */
+int
+SPDYF_prepare_rst_stream (struct SPDY_Session *session,
+ uint32_t stream_id,
+ enum SPDY_RST_STREAM_STATUS status);
+
+
+/**
+ * Handler called by session_write to fill the write buffer according to
+ * the data frame waiting in the response queue.
+ * When response data is given by user callback, the lib does not know
+ * how many frames are needed. In such case this call produces
+ * another ResponseQueue object and puts it on the queue while the the
+ * user callback says that there will be more data.
+ *
+ * @return SPDY_NO on error (not enough memory or the user calback for
+ * providing response data did something wrong). If
+ * the error is unrecoverable the handler changes session's
+ * status.
+ * SPDY_YES on success
+ */
+int
+SPDYF_handler_write_data (struct SPDY_Session *session);
+
+
+/**
+ * Handler called by session_write to fill the write buffer based on the
+ * control frame (SYN_REPLY) waiting in the response queue.
+ *
+ * @param session SPDY session
+ * @return SPDY_NO on error (zlib state is broken; the session MUST be
+ * closed). If
+ * the error is unrecoverable the handler changes session's
+ * status.
+ * SPDY_YES on success
+ */
+int
+SPDYF_handler_write_syn_reply (struct SPDY_Session *session);
+
+
+/**
+ * Handler called by session_write to fill the write buffer based on the
+ * control frame (GOAWAY) waiting in the response queue.
+ *
+ * @param session SPDY session
+ * @return SPDY_NO on error (not enough memory; by specification the
+ * session must be closed
+ * soon, thus there is no need to handle the error) or
+ * SPDY_YES on success
+ */
+int
+SPDYF_handler_write_goaway (struct SPDY_Session *session);
+
+
+/**
+ * Handler called by session_write to fill the write buffer based on the
+ * control frame (RST_STREAM) waiting in the response queue.
+ *
+ * @param session SPDY session
+ * @return SPDY_NO on error (not enough memory). If
+ * the error is unrecoverable the handler changes session's
+ * status.
+ * SPDY_YES on success
+ */
+int
+SPDYF_handler_write_rst_stream (struct SPDY_Session *session);
+
+
+/**
+ * Carefully ignore the full size of frames which are not yet supported
+ * by the lib.
+ * TODO Ignoring frames containing compressed bodies means that the
+ * compress state will be corrupted on next received frame. According to
+ * the draft the lib SHOULD try to decompress data also in corrupted
+ * frames just to keep right compression state.
+ *
+ * @param session SPDY_Session whose read buffer is used.
+ */
+void
+SPDYF_handler_ignore_frame (struct SPDY_Session *session);
+
+#endif
Added: libmicrohttpd/src/microspdy/stream.c
===================================================================
--- libmicrohttpd/src/microspdy/stream.c (rev 0)
+++ libmicrohttpd/src/microspdy/stream.c 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,151 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file stream.c
+ * @brief SPDY streams handling
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "structures.h"
+#include "internal.h"
+#include "session.h"
+
+
+int
+SPDYF_stream_new (struct SPDY_Session *session)
+{
+ uint32_t stream_id;
+ uint32_t assoc_stream_id;
+ uint8_t priority;
+ uint8_t slot;
+ size_t buffer_pos = session->read_buffer_beginning;
+ struct SPDYF_Stream *stream;
+ struct SPDYF_Control_Frame *frame;
+
+ if((session->read_buffer_offset - session->read_buffer_beginning) < 10)
+ {
+ //not all fields are received to create new stream
+ return SPDY_NO;
+ }
+
+ frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls;
+
+ //get stream id of the new stream
+ memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning,
4);
+ stream_id = NTOH31(stream_id);
+ session->read_buffer_beginning += 4;
+ if(stream_id <= session->last_in_stream_id || 0==(stream_id % 2))
+ {
+ //wrong stream id sent by client
+ //GOAWAY with PROTOCOL_ERROR MUST be sent
+ //TODO
+
+ //ignore frame
+ session->frame_handler = &SPDYF_handler_ignore_frame;
+ return SPDY_NO;
+ }
+ else if(session->is_goaway_sent)
+ {
+ //the client is not allowed to create new streams anymore
+ //we MUST ignore the frame
+ session->frame_handler = &SPDYF_handler_ignore_frame;
+ return SPDY_NO;
+ }
+
+ //set highest stream id for session
+ session->last_in_stream_id = stream_id;
+
+ //get assoc stream id of the new stream
+ //this value is used with SPDY PUSH, thus nothing to do with it here
+ memcpy(&assoc_stream_id, session->read_buffer +
session->read_buffer_beginning, 4);
+ assoc_stream_id = NTOH31(assoc_stream_id);
+ session->read_buffer_beginning += 4;
+
+ //get stream priority (3 bits)
+ //after it there are 5 bits that are not used
+ priority = *(uint8_t *)(session->read_buffer +
session->read_buffer_beginning) >> 5;
+ session->read_buffer_beginning++;
+
+ //get slot (see SPDY draft)
+ slot = *(uint8_t *)(session->read_buffer +
session->read_buffer_beginning);
+ session->read_buffer_beginning++;
+
+ if(NULL == (stream = malloc(sizeof(struct SPDYF_Stream))))
+ {
+ SPDYF_DEBUG("No memory");
+ //revert buffer state
+ session->read_buffer_beginning = buffer_pos;
+ return SPDY_NO;
+ }
+ memset(stream,0, sizeof(struct SPDYF_Stream));
+ stream->session = session;
+ stream->stream_id = stream_id;
+ stream->assoc_stream_id = assoc_stream_id;
+ stream->priority = priority;
+ stream->slot = slot;
+ stream->is_in_closed = (frame->flags & SPDY_SYN_STREAM_FLAG_FIN) != 0;
+ stream->flag_unidirectional = (frame->flags &
SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL) != 0;
+ stream->is_out_closed = stream->flag_unidirectional;
+ stream->is_server_initiator = false;
+
+ //put the stream to the list of streams for the session
+ DLL_insert(session->streams_head, session->streams_tail, stream);
+
+ return SPDY_YES;
+}
+
+
+void
+SPDYF_stream_destroy(struct SPDYF_Stream *stream)
+{
+ SPDY_name_value_destroy(stream->headers);
+ free(stream);
+ stream = NULL;
+}
+
+
+void
+SPDYF_stream_set_flags(struct SPDYF_Response_Queue *response_queue)
+{
+ struct SPDYF_Stream * stream = response_queue->stream;
+
+ if(NULL != response_queue->data_frame)
+ {
+ stream->is_out_closed =
(bool)(response_queue->data_frame->flags & SPDY_DATA_FLAG_FIN);
+ }
+ else if(NULL != response_queue->control_frame)
+ {
+ switch(response_queue->control_frame->type)
+ {
+ case SPDY_CONTROL_FRAME_TYPES_SYN_REPLY:
+ stream->is_out_closed =
(bool)(response_queue->control_frame->flags & SPDY_SYN_REPLY_FLAG_FIN);
+ break;
+
+ case SPDY_CONTROL_FRAME_TYPES_RST_STREAM:
+ if(NULL != stream)
+ {
+ stream->is_out_closed = true;
+ stream->is_in_closed = true;
+ }
+ break;
+
+ }
+ }
+}
Added: libmicrohttpd/src/microspdy/stream.h
===================================================================
--- libmicrohttpd/src/microspdy/stream.h (rev 0)
+++ libmicrohttpd/src/microspdy/stream.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,65 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file stream.h
+ * @brief SPDY streams handling
+ * @author Andrey Uzunov
+ */
+
+#ifndef STREAM_H
+#define STREAM_H
+
+#include "platform.h"
+
+
+/**
+ * Reads data from session's read buffer and tries to create a new SPDY
+ * stream. This function is called after control frame's header has been
+ * read from the buffer (after the length field). If bogus frame is
+ * received the function changes the read handler of the session and
+ * fails, i.e. there is no need of further error handling by the caller.
+ *
+ * @param session SPDY_Session whose read buffer is being read
+ * @return SPDY_YES if a new SPDY stream request was correctly received
+ * and handled. SPDY_NO if the whole SPDY frame was not yet
+ * received or memory error occurred.
+ */
+int
+SPDYF_stream_new (struct SPDY_Session *session);
+
+
+/**
+ * Destroys stream structure and whatever is in it.
+ *
+ * @param stream SPDY_Stream to destroy
+ */
+void
+SPDYF_stream_destroy(struct SPDYF_Stream *stream);
+
+
+/**
+ * Set stream flags if needed based on the type of the frame that was
+ * just sent (e.g., close stream if it was RST_STREAM).
+ *
+ * @param response_queue sent for this stream
+ */
+void
+SPDYF_stream_set_flags(struct SPDYF_Response_Queue *response_queue);
+
+#endif
Added: libmicrohttpd/src/microspdy/structures.c
===================================================================
--- libmicrohttpd/src/microspdy/structures.c (rev 0)
+++ libmicrohttpd/src/microspdy/structures.c 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,612 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file structures.c
+ * @brief Functions for handling most of the structures in defined
+ * in structures.h
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "structures.h"
+#include "internal.h"
+#include "session.h"
+
+
+struct SPDY_NameValue *
+SPDY_name_value_create ()
+{
+ struct SPDY_NameValue *pair;
+
+ if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
+ return NULL;
+
+ memset (pair, 0, sizeof (struct SPDY_NameValue));
+
+ return pair;
+}
+
+
+int
+SPDY_name_value_add (struct SPDY_NameValue *container,
+ const char *name,
+ const char *value)
+{
+ uint i;
+ uint len;
+ struct SPDY_NameValue *pair;
+ struct SPDY_NameValue *temp;
+ char **temp_value;
+ char *temp_string;
+
+ if(NULL == container || NULL == name || 0 == (len = strlen(name)))
+ return SPDY_INPUT_ERROR;
+
+ for(i=0; i<len; ++i)
+ {
+ if(isupper(name[i]))
+ return SPDY_INPUT_ERROR;
+ }
+
+ if(NULL == container->name && NULL == container->value)
+ {
+ //container is empty/just created
+ if (NULL == (container->name = strdup (name)))
+ {
+ return SPDY_NO;
+ }
+ if (NULL == (container->value = malloc(sizeof(char *))))
+ {
+ free(container->name);
+ return SPDY_NO;
+ }
+ if (NULL == (container->value[0] = strdup (value)))
+ {
+ free(container->value);
+ free(container->name);
+ return SPDY_NO;
+ }
+ container->num_values = 1;
+ return SPDY_YES;
+ }
+
+ pair = container;
+ while(NULL != pair)
+ {
+ if(0 == strcmp(pair->name, name))
+ {
+ //the value will be added to this pair
+ break;
+ }
+ pair = pair->next;
+ }
+
+ if(NULL == pair)
+ {
+ //the name doesn't exist in container, add new pair
+ if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
+ return SPDY_NO;
+
+ memset(pair, 0, sizeof(struct SPDY_NameValue));
+
+ if (NULL == (pair->name = strdup (name)))
+ {
+ free(pair);
+ return SPDY_NO;
+ }
+ if (NULL == (pair->value = malloc(sizeof(char *))))
+ {
+ free(pair->name);
+ free(pair);
+ return SPDY_NO;
+ }
+ if (NULL == (pair->value[0] = strdup (value)))
+ {
+ free(pair->value);
+ free(pair->name);
+ free(pair);
+ return SPDY_NO;
+ }
+ pair->num_values = 1;
+
+ temp = container;
+ while(NULL != temp->next)
+ temp = temp->next;
+ temp->next = pair;
+ pair->prev = temp;
+
+ return SPDY_YES;
+ }
+
+ //check for duplication (case sensitive)
+ for(i=0; i<pair->num_values; ++i)
+ if(0 == strcmp(pair->value[i], value))
+ return SPDY_NO;
+
+ if(strlen(pair->value[0]) > 0)
+ {
+ //the value will be appended to the others for this name
+ if (NULL == (temp_value = malloc((pair->num_values + 1) *
sizeof(char *))))
+ {
+ return SPDY_NO;
+ }
+ memcpy(temp_value, pair->value, pair->num_values * sizeof(char
*));
+ if (NULL == (temp_value[pair->num_values] = strdup (value)))
+ {
+ free(temp_value);
+ return SPDY_NO;
+ }
+ free(pair->value);
+ pair->value = temp_value;
+ ++pair->num_values;
+ return SPDY_YES;
+ }
+
+ //just replace the empty value
+
+ if (NULL == (temp_string = strdup (value)))
+ {
+ return SPDY_NO;
+ }
+ free(pair->value[0]);
+ pair->value[0] = temp_string;
+
+ return SPDY_YES;
+}
+
+
+const char * const *
+SPDY_name_value_lookup (struct SPDY_NameValue *container,
+ const char *name,
+ int *num_values)
+{
+ struct SPDY_NameValue *temp = container;
+
+ if(NULL == container || NULL == name || NULL == num_values)
+ return NULL;
+ if(NULL == container->name && NULL == container->value)
+ return NULL;
+
+ do
+ {
+ if(strcmp(name, temp->name) == 0)
+ {
+ *num_values = temp->num_values;
+ return (const char * const *)temp->value;
+ }
+
+ temp = temp->next;
+ }
+ while(NULL != temp);
+
+ return NULL;
+}
+
+
+void
+SPDY_name_value_destroy (struct SPDY_NameValue *container)
+{
+ uint i;
+ struct SPDY_NameValue *temp = container;
+
+ while(NULL != temp)
+ {
+ container = container->next;
+ free(temp->name);
+ for(i=0; i<temp->num_values; ++i)
+ free(temp->value[i]);
+ free(temp->value);
+ free(temp);
+ temp=container;
+ }
+}
+
+
+int
+SPDY_name_value_iterate (struct SPDY_NameValue *container,
+ SPDY_NameValueIterator iterator,
+ void *iterator_cls)
+{
+ int count;
+ int ret;
+ struct SPDY_NameValue *temp = container;
+
+ if(NULL == container)
+ return SPDY_INPUT_ERROR;
+
+ //check if container is an empty struct
+ if(NULL == container->name && NULL == container->value)
+ return 0;
+
+ count = 0;
+
+ if(NULL == iterator)
+ {
+ do
+ {
+ ++count;
+ temp=temp->next;
+ }
+ while(NULL != temp);
+
+ return count;
+ }
+
+ //code duplication for avoiding if here
+ do
+ {
+ ++count;
+ ret = iterator(iterator_cls, temp->name, (const char * const
*)temp->value, temp->num_values);
+ temp=temp->next;
+ }
+ while(NULL != temp && SPDY_YES == ret);
+
+ return count;
+}
+
+void
+SPDY_destroy_response(struct SPDY_Response *response)
+{
+ free(response->data);
+ free(response->headers);
+ free(response);
+}
+
+
+struct SPDYF_Response_Queue *
+SPDYF_response_queue_create(bool is_data,
+ void *data,
+ size_t data_size,
+ struct SPDY_Response *response,
+ struct SPDYF_Stream *stream,
+ bool closestream,
+
SPDYF_ResponseQueueResultCallback frqcb,
+ void *frqcb_cls,
+ SPDY_ResponseResultCallback
rrcb,
+ void *rrcb_cls)
+{
+ struct SPDYF_Response_Queue *head = NULL;
+ struct SPDYF_Response_Queue *prev;
+ struct SPDYF_Response_Queue *response_to_queue;
+ struct SPDYF_Control_Frame *control_frame;
+ struct SPDYF_Data_Frame *data_frame;
+ uint i;
+ bool is_last;
+
+ SPDYF_ASSERT(!is_data
+ || 0 == data_size && NULL != response->rcb
+ || 0 < data_size && NULL == response->rcb,
+ "either data or request->rcb must not be null");
+
+ if(is_data && data_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)
+ {
+ //separate the data in more frames and add them to the queue
+
+ prev=NULL;
+ for(i = 0; i < data_size; i += SPDY_MAX_SUPPORTED_FRAME_SIZE)
+ {
+ is_last = (i + SPDY_MAX_SUPPORTED_FRAME_SIZE) >=
data_size;
+
+ if(NULL == (response_to_queue = malloc(sizeof(struct
SPDYF_Response_Queue))))
+ goto free_and_fail;
+
+ memset(response_to_queue, 0, sizeof(struct
SPDYF_Response_Queue));
+ if(0 == i)
+ head = response_to_queue;
+
+ if(NULL == (data_frame = malloc(sizeof(struct
SPDYF_Data_Frame))))
+ {
+ free(response_to_queue);
+ goto free_and_fail;
+ }
+ memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
+ data_frame->control_bit = 0;
+ data_frame->stream_id = stream->stream_id;
+ if(is_last && closestream)
+ data_frame->flags |= SPDY_DATA_FLAG_FIN;
+
+ response_to_queue->data_frame = data_frame;
+ response_to_queue->process_response_handler =
&SPDYF_handler_write_data;
+ response_to_queue->is_data = is_data;
+ response_to_queue->stream = stream;
+ if(is_last)
+ {
+ response_to_queue->frqcb = frqcb;
+ response_to_queue->frqcb_cls = frqcb_cls;
+ response_to_queue->rrcb = rrcb;
+ response_to_queue->rrcb_cls = rrcb_cls;
+ }
+ response_to_queue->data = data + i;
+ response_to_queue->data_size = is_last
+ ? (data_size - 1) %
SPDY_MAX_SUPPORTED_FRAME_SIZE + 1
+ : SPDY_MAX_SUPPORTED_FRAME_SIZE;
+ response_to_queue->response = response;
+
+ response_to_queue->prev = prev;
+ if(NULL != prev)
+ prev->next = response_to_queue;
+ prev = response_to_queue;
+ }
+
+ return head;
+
+ //for GOTO
+ free_and_fail:
+ while(NULL != head)
+ {
+ response_to_queue = head;
+ head = head->next;
+ free(response_to_queue->data_frame);
+ free(response_to_queue);
+ }
+ return NULL;
+ }
+
+ //create only one frame for data, data with callback or control frame
+
+ if(NULL == (response_to_queue = malloc(sizeof(struct
SPDYF_Response_Queue))))
+ {
+ return NULL;
+ }
+ memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
+
+ if(is_data)
+ {
+ if(NULL == (data_frame = malloc(sizeof(struct
SPDYF_Data_Frame))))
+ {
+ free(response_to_queue);
+ return NULL;
+ }
+ memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
+ data_frame->control_bit = 0;
+ data_frame->stream_id = stream->stream_id;
+ if(closestream && NULL == response->rcb)
+ data_frame->flags |= SPDY_DATA_FLAG_FIN;
+
+ response_to_queue->data_frame = data_frame;
+ response_to_queue->process_response_handler =
&SPDYF_handler_write_data;
+ }
+ else
+ {
+ if(NULL == (control_frame = malloc(sizeof(struct
SPDYF_Control_Frame))))
+ {
+ free(response_to_queue);
+ return NULL;
+ }
+ memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
+ control_frame->control_bit = 1;
+ control_frame->version = SPDY_VERSION;
+ control_frame->type = SPDY_CONTROL_FRAME_TYPES_SYN_REPLY;
+ if(closestream)
+ control_frame->flags |= SPDY_SYN_REPLY_FLAG_FIN;
+
+ response_to_queue->control_frame = control_frame;
+ response_to_queue->process_response_handler =
&SPDYF_handler_write_syn_reply;
+ }
+
+ response_to_queue->is_data = is_data;
+ response_to_queue->stream = stream;
+ response_to_queue->frqcb = frqcb;
+ response_to_queue->frqcb_cls = frqcb_cls;
+ response_to_queue->rrcb = rrcb;
+ response_to_queue->rrcb_cls = rrcb_cls;
+ response_to_queue->data = data;
+ response_to_queue->data_size = data_size;
+ response_to_queue->response = response;
+
+ return response_to_queue;
+}
+
+
+void
+SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue)
+{
+ //data is not copied to the struct but only linked
+ //but this is not valid for GOAWAY and RST_STREAM
+ if(!response_queue->is_data
+ && (SPDY_CONTROL_FRAME_TYPES_RST_STREAM ==
response_queue->control_frame->type
+ || SPDY_CONTROL_FRAME_TYPES_GOAWAY ==
response_queue->control_frame->type))
+ {
+ free(response_queue->data);
+ }
+ if(response_queue->is_data)
+ free(response_queue->data_frame);
+ else
+ free(response_queue->control_frame);
+
+ free(response_queue);
+}
+
+
+ssize_t
+SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
+ int num_containers,
+ void **stream)
+{
+ size_t size;
+ int32_t num_pairs = 0;
+ int32_t value_size;
+ int32_t name_size;
+ int32_t temp;
+ uint i;
+ uint offset;
+ uint value_offset;
+ struct SPDY_NameValue * iterator;
+ int j;
+
+ size = 4; //for num pairs
+
+ for(j=0; j<num_containers; ++j)
+ {
+ iterator = container[j];
+ while(iterator != NULL)
+ {
+ ++num_pairs;
+ size += 4 + strlen(iterator->name); //length + string
+
+ SPDYF_ASSERT(iterator->num_values>0, "num_values is 0");
+
+ size += 4; //value length
+
+ for(i=0; i<iterator->num_values; ++i)
+ {
+ size += strlen(iterator->value[i]); // string
+ if(i/* || !strlen(iterator->value[i])*/) ++size; //NULL
separator
+ }
+
+ iterator = iterator->next;
+ }
+}
+
+ if(NULL == (*stream = malloc(size)))
+ {
+ return -1;
+ }
+
+ //put num_pairs to the stream
+ num_pairs = htonl(num_pairs);
+ memcpy(*stream, &num_pairs, 4);
+ offset = 4;
+
+ //put all other headers to the stream
+ for(j=0; j<num_containers; ++j)
+ {
+ iterator = container[j];
+ while(iterator != NULL)
+ {
+ name_size = strlen(iterator->name);
+ temp = htonl(name_size);
+ memcpy(*stream + offset, &temp, 4);
+ offset += 4;
+ strncpy(*stream + offset, iterator->name, name_size);
+ offset += name_size;
+
+ value_offset = offset;
+ offset += 4;
+ for(i=0; i<iterator->num_values; ++i)
+ {
+ if(i /*|| !strlen(iterator->value[0])*/)
+ {
+ memset(*stream + offset, 0, 1);
+ ++offset;
+ if(!i) continue;
+ }
+ strncpy(*stream + offset, iterator->value[i],
strlen(iterator->value[i]));
+ offset += strlen(iterator->value[i]);
+ }
+ value_size = offset - value_offset - 4;
+ value_size = htonl(value_size);
+ memcpy(*stream + value_offset, &value_size, 4);
+
+ iterator = iterator->next;
+ }
+}
+
+ SPDYF_ASSERT(offset == size,"offset is wrong");
+
+ return size;
+}
+
+
+int
+SPDYF_name_value_from_stream(void *stream,
+ size_t size,
+ struct SPDY_NameValue
** container)
+{
+ int32_t num_pairs;
+ int32_t value_size;
+ int32_t name_size;
+ int i;
+ uint offset = 0;
+ uint value_end_offset;
+ char *name;
+ char *value;
+
+ if(NULL == (*container = SPDY_name_value_create ()))
+ {
+ return SPDY_NO;
+ }
+
+ //get number of pairs
+ memcpy(&num_pairs, stream, 4);
+ offset = 4;
+ num_pairs = ntohl(num_pairs);
+
+ if(num_pairs > 0)
+ {
+ for(i = 0; i < num_pairs; ++i)
+ {
+ //get name size
+ memcpy(&name_size, stream + offset, 4);
+ offset += 4;
+ name_size = ntohl(name_size);
+ //get name
+ if(NULL == (name = strndup(stream + offset, name_size)))
+ {
+ SPDY_name_value_destroy(*container);
+ return SPDY_NO;
+ }
+ offset+=name_size;
+
+ //get value size
+ memcpy(&value_size, stream + offset, 4);
+ offset += 4;
+ value_size = ntohl(value_size);
+ value_end_offset = offset + value_size;
+ //get value
+ do
+ {
+ if(NULL == (value = strndup(stream + offset,
value_size)))
+ {
+ free(name);
+ SPDY_name_value_destroy(*container);
+ return SPDY_NO;
+ }
+ offset += strlen(value);
+ if(offset < value_end_offset)
+ ++offset; //NULL separator
+
+ //add name/value to the struct
+ if(SPDY_YES != SPDY_name_value_add(*container,
name, value))
+ {
+ free(name);
+ free(value);
+ SPDY_name_value_destroy(*container);
+ return SPDY_NO;
+ }
+ free(value);
+ }
+ while(offset < value_end_offset);
+
+ free(name);
+
+ if(offset != value_end_offset)
+ {
+ SPDY_name_value_destroy(*container);
+ return SPDY_INPUT_ERROR;
+ }
+ }
+ }
+
+ if(offset == size)
+ return SPDY_YES;
+
+ SPDY_name_value_destroy(*container);
+ return SPDY_INPUT_ERROR;
+}
Added: libmicrohttpd/src/microspdy/structures.h
===================================================================
--- libmicrohttpd/src/microspdy/structures.h (rev 0)
+++ libmicrohttpd/src/microspdy/structures.h 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,1128 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file structures.h
+ * @brief internal and public structures -- most of the structs used by
+ * the library are defined here
+ * @author Andrey Uzunov
+ */
+
+#ifndef STRUCTURES_H
+#define STRUCTURES_H
+
+#include "platform.h"
+#include "microspdy.h"
+#include "tls.h"
+
+
+/**
+ * All possible SPDY control frame types. The number is used in the header
+ * of the control frame.
+ */
+enum SPDY_CONTROL_FRAME_TYPES
+{
+ /**
+ * The SYN_STREAM control frame allows the sender to asynchronously
+ * create a stream between the endpoints.
+ */
+ SPDY_CONTROL_FRAME_TYPES_SYN_STREAM = 1,
+
+ /**
+ * SYN_REPLY indicates the acceptance of a stream creation by
+ * the recipient of a SYN_STREAM frame.
+ */
+ SPDY_CONTROL_FRAME_TYPES_SYN_REPLY = 2,
+
+ /**
+ * The RST_STREAM frame allows for abnormal termination of a stream.
+ * When sent by the creator of a stream, it indicates the creator
+ * wishes to cancel the stream. When sent by the recipient of a
+ * stream, it indicates an error or that the recipient did not want
+ * to accept the stream, so the stream should be closed.
+ */
+ SPDY_CONTROL_FRAME_TYPES_RST_STREAM = 3,
+
+ /**
+ * A SETTINGS frame contains a set of id/value pairs for
+ * communicating configuration data about how the two endpoints may
+ * communicate. SETTINGS frames can be sent at any time by either
+ * endpoint, are optionally sent, and are fully asynchronous. When
+ * the server is the sender, the sender can request that
+ * configuration data be persisted by the client across SPDY
+ * sessions and returned to the server in future communications.
+ */
+ SPDY_CONTROL_FRAME_TYPES_SETTINGS = 4,
+
+ /**
+ * The PING control frame is a mechanism for measuring a minimal
+ * round-trip time from the sender. It can be sent from the client
+ * or the server. Recipients of a PING frame should send an
+ * identical frame to the sender as soon as possible (if there is
+ * other pending data waiting to be sent, PING should take highest
+ * priority). Each ping sent by a sender should use a unique ID.
+ */
+ SPDY_CONTROL_FRAME_TYPES_PING = 6,
+
+ /**
+ * The GOAWAY control frame is a mechanism to tell the remote side
+ * of the connection to stop creating streams on this session. It
+ * can be sent from the client or the server.
+ */
+ SPDY_CONTROL_FRAME_TYPES_GOAWAY = 7,
+
+ /**
+ * The HEADERS frame augments a stream with additional headers. It
+ * may be optionally sent on an existing stream at any time.
+ * Specific application of the headers in this frame is
+ * application-dependent. The name/value header block within this
+ * frame is compressed.
+ */
+ SPDY_CONTROL_FRAME_TYPES_HEADERS = 8,
+
+ /**
+ * The WINDOW_UPDATE control frame is used to implement per stream
+ * flow control in SPDY. Flow control in SPDY is per hop, that is,
+ * only between the two endpoints of a SPDY connection. If there are
+ * one or more intermediaries between the client and the origin
+ * server, flow control signals are not explicitly forwarded by the
+ * intermediaries.
+ */
+ SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE = 9,
+
+ /**
+ * The CREDENTIAL control frame is used by the client to send
+ * additional client certificates to the server. A SPDY client may
+ * decide to send requests for resources from different origins on
+ * the same SPDY session if it decides that that server handles both
+ * origins. For example if the IP address associated with both
+ * hostnames matches and the SSL server certificate presented in the
+ * initial handshake is valid for both hostnames. However, because
+ * the SSL connection can contain at most one client certificate,
+ * the client needs a mechanism to send additional client
+ * certificates to the server.
+ */
+ SPDY_CONTROL_FRAME_TYPES_CREDENTIAL = 11
+};
+
+
+/**
+ * SPDY_SESSION_STATUS is used to show the current receiving state
+ * of each session, i.e. what is expected to come now, and how it should
+ * be handled.
+ */
+enum SPDY_SESSION_STATUS
+{
+ /**
+ * The session is in closing state, do not read read anything from
+ * it. Do not write anything to it.
+ */
+ SPDY_SESSION_STATUS_CLOSING = 0,
+
+ /**
+ * Wait for new SPDY frame to come.
+ */
+ SPDY_SESSION_STATUS_WAIT_FOR_HEADER = 1,
+
+ /**
+ * The standard 8 byte header of the SPDY frame was received and
+ * handled. Wait for the specific (sub)headers according to the
+ * frame type.
+ */
+ SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER = 2,
+
+ /**
+ * The specific (sub)headers were received and handled. Wait for the
+ * "body", i.e. wait for the name/value pairs compressed by zlib.
+ */
+ SPDY_SESSION_STATUS_WAIT_FOR_BODY = 3,
+
+ /**
+ * Ignore all the bytes read from the socket, e.g. larger frames.
+ */
+ SPDY_SESSION_STATUS_IGNORE_BYTES= 4,
+
+ /**
+ * The session is in pre-closing state, do not read read anything
+ * from it. In this state the output queue will be written to the
+ * socket.
+ */
+ SPDY_SESSION_STATUS_FLUSHING = 5,
+};
+
+
+/**
+ * Specific flags for the SYN_STREAM control frame.
+ */
+enum SPDY_SYN_STREAM_FLAG
+{
+ /**
+ * The sender won't send any more frames on this stream.
+ */
+ SPDY_SYN_STREAM_FLAG_FIN = 1,
+
+ /**
+ * The sender creates this stream as unidirectional.
+ */
+ SPDY_SYN_STREAM_FLAG_UNIDIRECTIONAL = 2
+};
+
+
+/**
+ * Specific flags for the SYN_REPLY control frame.
+ */
+enum SPDY_SYN_REPLY_FLAG
+{
+ /**
+ * The sender won't send any more frames on this stream.
+ */
+ SPDY_SYN_REPLY_FLAG_FIN = 1
+};
+
+
+/**
+ * Specific flags for the data frame.
+ */
+enum SPDY_DATA_FLAG
+{
+ /**
+ * The sender won't send any more frames on this stream.
+ */
+ SPDY_DATA_FLAG_FIN = 1,
+
+ /**
+ * The data in the frame is compressed.
+ * This flag appears only in the draft on ietf.org but not on
+ * chromium.org.
+ */
+ SPDY_DATA_FLAG_COMPRESS = 2
+};
+
+/**
+ * Status code within RST_STREAM control frame.
+ */
+enum SPDY_RST_STREAM_STATUS
+{
+ /**
+ * This is a generic error, and should only be used if a more
+ * specific error is not available.
+ */
+ SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR = 1,
+
+ /**
+ * This is returned when a frame is received for a stream which is
+ * not active.
+ */
+ SPDY_RST_STREAM_STATUS_INVALID_STREAM = 2,
+
+ /**
+ * Indicates that the stream was refused before any processing has
+ * been done on the stream.
+ */
+ SPDY_RST_STREAM_STATUS_REFUSED_STREAM = 3,
+
+ /**
+ * Indicates that the recipient of a stream does not support the
+ * SPDY version requested.
+ */
+ SPDY_RST_STREAM_STATUS_UNSUPPORTED_VERSION = 4,
+
+ /**
+ * Used by the creator of a stream to indicate that the stream is
+ * no longer needed.
+ */
+ SPDY_RST_STREAM_STATUS_CANCEL = 5,
+
+ /**
+ * This is a generic error which can be used when the implementation
+ * has internally failed, not due to anything in the protocol.
+ */
+ SPDY_RST_STREAM_STATUS_INTERNAL_ERROR = 6,
+
+ /**
+ * The endpoint detected that its peer violated the flow control
+ * protocol.
+ */
+ SPDY_RST_STREAM_STATUS_FLOW_CONTROL_ERROR = 7,
+
+ /**
+ * The endpoint received a SYN_REPLY for a stream already open.
+ */
+ SPDY_RST_STREAM_STATUS_STREAM_IN_USE = 8,
+
+ /**
+ * The endpoint received a data or SYN_REPLY frame for a stream
+ * which is half closed.
+ */
+ SPDY_RST_STREAM_STATUS_STREAM_ALREADY_CLOSED = 9,
+
+ /**
+ * The server received a request for a resource whose origin does
+ * not have valid credentials in the client certificate vector.
+ */
+ SPDY_RST_STREAM_STATUS_INVALID_CREDENTIALS = 10,
+
+ /**
+ * The endpoint received a frame which this implementation could not
+ * support. If FRAME_TOO_LARGE is sent for a SYN_STREAM, HEADERS,
+ * or SYN_REPLY frame without fully processing the compressed
+ * portion of those frames, then the compression state will be
+ * out-of-sync with the other endpoint. In this case, senders of
+ * FRAME_TOO_LARGE MUST close the session.
+ */
+ SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE = 11
+};
+
+
+/**
+ * Status code within GOAWAY control frame.
+ */
+enum SPDY_GOAWAY_STATUS
+{
+ /**
+ * This is a normal session teardown.
+ */
+ SPDY_GOAWAY_STATUS_OK = 0,
+
+ /**
+ * This is a generic error, and should only be used if a more
+ * specific error is not available.
+ */
+ SPDY_GOAWAY_STATUS_PROTOCOL_ERROR = 1,
+
+ /**
+ * This is a generic error which can be used when the implementation
+ * has internally failed, not due to anything in the protocol.
+ */
+ SPDY_GOAWAY_STATUS_INTERNAL_ERROR = 11
+};
+
+
+struct SPDYF_Stream;
+
+struct SPDYF_Response_Queue;
+
+/**
+ * Callback for new stream. To be used in the application layer of the
+ * lib.
+ *
+ * @param cls
+ * @param stream the new stream
+ * @return SPDY_YES on success,
+ * SPDY_NO if error occurs
+ */
+typedef int
+(*SPDYF_NewStreamCallback) (void *cls,
+ struct SPDYF_Stream * stream);
+
+
+/**
+ * Callback to be called when the response queue object was handled and
+ * the data was already sent.
+ *
+ * @param cls
+ * @param response_queue the SPDYF_Response_Queue structure which will
+ * be cleaned very soon
+ * @param status shows if actually the response was sent or it was
+ * discarded by the lib for any reason (e.g., closing
session,
+ * closing stream, stopping daemon, etc.). It is possible
that
+ * status indicates an error but part of the response (in
one
+ * or several frames) was sent to the client.
+ */
+typedef void
+(*SPDYF_ResponseQueueResultCallback) (void * cls,
+ struct
SPDYF_Response_Queue *response_queue,
+ enum
SPDY_RESPONSE_RESULT status);
+
+
+/**
+ * Representation of the control frame's headers, which are common for
+ * all types.
+ */
+struct __attribute__((__packed__)) SPDYF_Control_Frame
+{
+ uint16_t version : 15;
+ uint16_t control_bit : 1; /* always 1 for control frames */
+ uint16_t type;
+ uint32_t flags : 8;
+ uint32_t length : 24;
+};
+
+
+/**
+ * Representation of the data frame's headers.
+ */
+struct __attribute__((__packed__)) SPDYF_Data_Frame
+{
+ uint32_t stream_id : 31;
+ uint32_t control_bit : 1; /* always 0 for data frames */
+ uint32_t flags : 8;
+ uint32_t length : 24;
+};
+
+
+/**
+ * Queue of the responses, to be handled (e.g. compressed) and sent later.
+ */
+struct SPDYF_Response_Queue
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDYF_Response_Queue *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDYF_Response_Queue *prev;
+
+ /**
+ * Stream (Request) for which is the response.
+ */
+ struct SPDYF_Stream *stream;
+
+ /**
+ * Response structure with all the data (uncompressed headers) to be
sent.
+ */
+ struct SPDY_Response *response;
+
+ /**
+ * Control frame. The length field should be set after compressing
+ * the headers!
+ */
+ struct SPDYF_Control_Frame *control_frame;
+
+ /**
+ * Data frame. The length field should be set after compressing
+ * the body!
+ */
+ struct SPDYF_Data_Frame *data_frame;
+
+ /**
+ * Data to be sent: name/value pairs in control frames or body in data
frames.
+ */
+ void *data;
+
+ /**
+ * Specific handler for different frame types.
+ */
+ int (* process_response_handler)(struct SPDY_Session *session);
+
+ /**
+ * Callback to be called when the last bytes from the response was sent
+ * to the client.
+ */
+ SPDYF_ResponseQueueResultCallback frqcb;
+
+ /**
+ * Closure for frqcb.
+ */
+ void *frqcb_cls;
+
+ /**
+ * Callback to be used by the application layer.
+ */
+ SPDY_ResponseResultCallback rrcb;
+
+ /**
+ * Closure for rcb.
+ */
+ void *rrcb_cls;
+
+ /**
+ * Data size.
+ */
+ size_t data_size;
+
+ /**
+ * True if data frame should be sent. False if control frame should
+ * be sent.
+ */
+ bool is_data;
+};
+
+
+
+/**
+ * Collection of HTTP headers used in requests and responses.
+ */
+struct SPDY_NameValue
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDY_NameValue *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDY_NameValue *prev;
+
+ /**
+ * Null terminated string for name.
+ */
+ char *name;
+
+ /**
+ * Array of Null terminated strings for value. num_values is the
+ * length of the array.
+ */
+ char **value;
+
+ /**
+ * Number of values, this is >= 0.
+ */
+ uint num_values;
+};
+
+
+/**
+ * Represents a SPDY stream
+ */
+struct SPDYF_Stream
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDYF_Stream *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDYF_Stream *prev;
+
+ /**
+ * Reference to the SPDY_Session struct.
+ */
+ struct SPDY_Session *session;
+
+ /**
+ * Name value pairs, sent within the frame which created the stream.
+ */
+ struct SPDY_NameValue *headers;
+
+ /**
+ * This stream's ID.
+ */
+ uint32_t stream_id;
+
+ /**
+ * Stream to which this one is associated.
+ */
+ uint32_t assoc_stream_id;
+
+ /**
+ * Stream priority. 0 is the highest, 7 is the lowest.
+ */
+ uint8_t priority;
+
+ /**
+ * Integer specifying the index in the server's CREDENTIAL vector of
+ * the client certificate to be used for this request The value 0
+ * means no client certificate should be associated with this stream.
+ */
+ uint8_t slot;
+
+ /**
+ * If initially the stream was created as unidirectional.
+ */
+ bool flag_unidirectional;
+
+ /**
+ * If the stream won't be used for receiving frames anymore. The
+ * client has sent FLAG_FIN or the stream was terminated with
+ * RST_STREAM.
+ */
+ bool is_in_closed;
+
+ /**
+ * If the stream won't be used for sending out frames anymore. The
+ * server has sent FLAG_FIN or the stream was terminated with
+ * RST_STREAM.
+ */
+ bool is_out_closed;
+
+ /**
+ * Which entity (server/client) has created the stream.
+ */
+ bool is_server_initiator;
+};
+
+
+/**
+ * Represents a SPDY session which is just a TCP connection
+ */
+struct SPDY_Session
+{
+ /**
+ * zlib stream for decompressing all the name/pair values from the
+ * received frames. All the received compressed data must be
+ * decompressed within one context: this stream. Thus, it should be
+ * unique for the session and initialized at its creation.
+ */
+ z_stream zlib_recv_stream;
+
+ /**
+ * zlib stream for compressing all the name/pair values from the
+ * frames to be sent. All the sent compressed data must be
+ * compressed within one context: this stream. Thus, it should be
+ * unique for the session and initialized at its creation.
+ */
+ z_stream zlib_send_stream;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDY_Session *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct SPDY_Session *prev;
+
+ /**
+ * Reference to the SPDY_Daemon struct.
+ */
+ struct SPDY_Daemon *daemon;
+
+ /**
+ * Foreign address (of length addr_len).
+ */
+ struct sockaddr *addr;
+
+ /**
+ * Head of doubly-linked list of the SPDY streams belonging to the
+ * session.
+ */
+ struct SPDYF_Stream *streams_head;
+
+ /**
+ * Tail of doubly-linked list of the streams.
+ */
+ struct SPDYF_Stream *streams_tail;
+
+ /**
+ * Unique TLS context for the session. Initialized on each creation
+ * (actually when the TCP connection is established).
+ */
+ SPDYF_TLS_SESSION_CONTEXT *tls_context;
+
+ /**
+ * Head of doubly-linked list of the responses.
+ */
+ struct SPDYF_Response_Queue *response_queue_head;
+
+ /**
+ * Tail of doubly-linked list of the responses.
+ */
+ struct SPDYF_Response_Queue *response_queue_tail;
+
+ /**
+ * Buffer for reading requests.
+ */
+ void *read_buffer;
+
+ /**
+ * Buffer for writing responses.
+ */
+ void *write_buffer;
+
+ /**
+ * Specific handler for the frame that is currently being received.
+ */
+ void (*frame_handler) (struct SPDY_Session * session);
+
+ /**
+ * Closure for frame_handler.
+ */
+ void *frame_handler_cls;
+
+ /**
+ * Extra field to be used by the user with set/get func for whatever
+ * purpose he wants.
+ */
+ void *user_cls;
+
+ /**
+ * Number of bytes that the lib must ignore immediately after they
+ * are read from the TLS socket without adding them to the read buf.
+ * This is needed, for instance, when receiving frame bigger than
+ * the buffer to avoid deadlock situations.
+ */
+ size_t read_ignore_bytes;
+
+ /**
+ * Size of read_buffer (in bytes). This value indicates
+ * how many bytes we're willing to read into the buffer;
+ * the real buffer is one byte longer to allow for
+ * adding zero-termination (when needed).
+ */
+ size_t read_buffer_size;
+
+ /**
+ * Position where we currently append data in
+ * read_buffer (last valid position).
+ */
+ size_t read_buffer_offset;
+
+ /**
+ * Position until where everything was already read
+ */
+ size_t read_buffer_beginning;
+
+ /**
+ * Size of write_buffer (in bytes). This value indicates
+ * how many bytes we're willing to prepare for writing.
+ */
+ size_t write_buffer_size;
+
+ /**
+ * Position where we currently append data in
+ * write_buffer (last valid position).
+ */
+ size_t write_buffer_offset;
+
+ /**
+ * Position until where everything was already written to the socket
+ */
+ size_t write_buffer_beginning;
+
+ /**
+ * Last time this connection had any activity
+ * (reading or writing).
+ */
+ time_t last_activity;
+
+ /**
+ * Socket for this connection. Set to -1 if
+ * this connection has died (daemon should clean
+ * up in that case).
+ */
+ int socket_fd;
+
+ /**
+ * Length of the foreign address.
+ */
+ socklen_t addr_len;
+
+ /**
+ * The biggest stream ID for this session for streams initiated
+ * by the client.
+ */
+ uint32_t last_in_stream_id;
+
+ /**
+ * The biggest stream ID for this session for streams initiated
+ * by the server.
+ */
+ uint32_t last_out_stream_id;
+
+ /**
+ * This value is updated whenever SYN_REPLY or RST_STREAM are sent
+ * and is used later in GOAWAY frame.
+ * TODO it is not clear in the draft what happens when streams are
+ * not answered in the order of their IDs. Moreover, why should we
+ * send GOAWAY with the ID of received bogus SYN_STREAM with huge ID?
+ */
+ uint32_t last_replied_to_stream_id;
+
+ /**
+ * Shows the stream id of the currently handled frame. This value is
+ * to be used when sending RST_STREAM in answer to a problematic
+ * frame, e.g. larger than supported.
+ */
+ uint32_t current_stream_id;
+
+ /**
+ * Shows the current receiving state the session, i.e. what is
+ * expected to come now, and how it shold be handled.
+ */
+ enum SPDY_SESSION_STATUS status;
+
+ /**
+ * Has this socket been closed for reading (i.e.
+ * other side closed the connection)? If so,
+ * we must completely close the connection once
+ * we are done sending our response (and stop
+ * trying to read from this socket).
+ */
+ bool read_closed;
+
+ /**
+ * If the server sends GOAWAY, it must ignore all SYN_STREAMS for
+ * this session. Normally the server will soon close the TCP session.
+ */
+ bool is_goaway_sent;
+
+ /**
+ * If the server receives GOAWAY, it must not send new SYN_STREAMS
+ * on this session. Normally the client will soon close the TCP
+ * session.
+ */
+ bool is_goaway_received;
+};
+
+
+/**
+ * State and settings kept for each SPDY daemon.
+ */
+struct SPDY_Daemon
+{
+
+ /**
+ * Tail of doubly-linked list of our current, active sessions.
+ */
+ struct SPDY_Session *sessions_head;
+
+ /**
+ * Tail of doubly-linked list of our current, active sessions.
+ */
+ struct SPDY_Session *sessions_tail;
+
+ /**
+ * Tail of doubly-linked list of connections to clean up.
+ */
+ struct SPDY_Session *cleanup_head;
+
+ /**
+ * Tail of doubly-linked list of connections to clean up.
+ */
+ struct SPDY_Session *cleanup_tail;
+
+ /**
+ * Unique TLS context for the daemon. Initialized on daemon start.
+ */
+ SPDYF_TLS_DAEMON_CONTEXT *tls_context;
+
+ /**
+ * Certificate file of the server. File path is kept here.
+ */
+ char *certfile;
+
+ /**
+ * Key file for the certificate of the server. File path is
+ * kept here.
+ */
+ char *keyfile;
+
+
+ /**
+ * The address to which the listening socket is bound.
+ */
+ struct sockaddr *address;
+
+ /**
+ * Callback called when a new SPDY session is
+ * established by a client
+ */
+ SPDY_NewSessionCallback new_session_cb;
+
+ /**
+ * Callback called when a client closes the session
+ */
+ SPDY_SessionClosedCallback session_closed_cb;
+
+ /**
+ * Callback called when a client sends request
+ */
+ SPDY_NewRequestCallback new_request_cb;
+
+ /**
+ * Callback called when HTTP POST params are received
+ * after request
+ */
+ SPDY_NewPOSTDataCallback new_post_data_cb;
+
+ /**
+ * Closure argument for all the callbacks that can be used by the
client.
+ */
+ void *cls;
+
+ /**
+ * Callback called when new stream is created.
+ */
+ SPDYF_NewStreamCallback fnew_stream_cb;
+
+ /**
+ * Closure argument for all the callbacks defined in the framing layer.
+ */
+ void *fcls;
+
+ /**
+ * After how many seconds of inactivity should
+ * connections time out? Zero for no timeout.
+ */
+ time_t session_timeout;
+
+ /**
+ * Listen socket.
+ */
+ int socket_fd;
+
+ /**
+ * Daemon's options.
+ */
+ enum SPDY_DAEMON_OPTION options;
+
+ /**
+ * Daemon's flags.
+ */
+ enum SPDY_DAEMON_FLAG flags;
+
+ /**
+ * Listen port.
+ */
+ uint16_t port;
+};
+
+
+/**
+ * Represents a SPDY response.
+ */
+struct SPDY_Response
+{
+ /**
+ * Raw uncompressed stream of the name/value pairs in SPDY frame
+ * used for the HTTP headers.
+ */
+ void *headers;
+
+ /**
+ * Raw stream of the data to be sent. Equivalent to the body in HTTP
+ * response.
+ */
+ void *data;
+
+ /**
+ * Callback function to be used when the response data is provided
+ * with callbacks. In this case data must be NULL and data_size must
+ * be 0.
+ */
+ SPDY_ResponseCallback rcb;
+
+ /**
+ * Extra argument to rcb.
+ */
+ void *rcb_cls;
+
+ /**
+ * Length of headers.
+ */
+ size_t headers_size;
+
+ /**
+ * Length of data.
+ */
+ size_t data_size;
+
+ /**
+ * The callback func will be called to get that amount of bytes to
+ * put them into a DATA frame. It is either user preffered or
+ * the maximum supported by the lib value.
+ */
+ uint32_t rcb_block_size;
+};
+
+
+/* Macros for handling data and structures */
+
+
+/**
+ * Insert an element at the head of a DLL. Assumes that head, tail and
+ * element are structs with prev and next fields.
+ *
+ * @param head pointer to the head of the DLL (struct ? *)
+ * @param tail pointer to the tail of the DLL (struct ? *)
+ * @param element element to insert (struct ? *)
+ */
+#define DLL_insert(head,tail,element) do { \
+ (element)->next = (head); \
+ (element)->prev = NULL; \
+ if ((tail) == NULL) \
+ (tail) = element; \
+ else \
+ (head)->prev = element; \
+ (head) = (element); } while (0)
+
+
+/**
+ * Remove an element from a DLL. Assumes
+ * that head, tail and element are structs
+ * with prev and next fields.
+ *
+ * @param head pointer to the head of the DLL (struct ? *)
+ * @param tail pointer to the tail of the DLL (struct ? *)
+ * @param element element to remove (struct ? *)
+ */
+#define DLL_remove(head,tail,element) do { \
+ if ((element)->prev == NULL) \
+ (head) = (element)->next; \
+ else \
+ (element)->prev->next = (element)->next; \
+ if ((element)->next == NULL) \
+ (tail) = (element)->prev; \
+ else \
+ (element)->next->prev = (element)->prev; \
+ (element)->next = NULL; \
+ (element)->prev = NULL; } while (0)
+
+
+/**
+ * Convert all integers in a SPDY control frame headers structure from
+ * host byte order to network byte order.
+ *
+ * @param frame input and output structure (struct SPDY_Control_Frame *)
+ */
+#if HAVE_BIG_ENDIAN
+#define SPDYF_CONTROL_FRAME_HTON(frame)
+#else
+#define SPDYF_CONTROL_FRAME_HTON(frame) do { \
+ (*((uint16_t *) frame )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t
*) frame ))<<8);\
+ (frame)->type = htons((frame)->type); \
+ (frame)->length = HTON24((frame)->length); \
+ } while (0)
+#endif
+
+
+/**
+ * Convert all integers in a SPDY control frame headers structure from
+ * network byte order to host byte order.
+ *
+ * @param frame input and output structure (struct SPDY_Control_Frame *)
+ */
+#if HAVE_BIG_ENDIAN
+#define SPDYF_CONTROL_FRAME_NTOH(frame)
+#else
+#define SPDYF_CONTROL_FRAME_NTOH(frame) do { \
+ (*((uint16_t *) frame )) = (*((uint8_t *) (frame) +1 )) | ((*((uint8_t
*) frame ))<<8);\
+ (frame)->type = ntohs((frame)->type); \
+ (frame)->length = NTOH24((frame)->length); \
+ } while (0)
+#endif
+
+
+/**
+ * Convert all integers in a SPDY data frame headers structure from
+ * host byte order to network byte order.
+ *
+ * @param frame input and output structure (struct SPDY_Data_Frame *)
+ */
+#if HAVE_BIG_ENDIAN
+#define SPDYF_DATA_FRAME_HTON(frame)
+#else
+#define SPDYF_DATA_FRAME_HTON(frame) do { \
+ *((uint32_t *) frame ) = htonl(*((uint32_t *) frame ));\
+ (frame)->length = HTON24((frame)->length); \
+ } while (0)
+#endif
+
+
+/**
+ * Convert all integers in a SPDY data frame headers structure from
+ * network byte order to host byte order.
+ *
+ * @param frame input and output structure (struct SPDY_Data_Frame *)
+ */
+#if HAVE_BIG_ENDIAN
+#define SPDYF_DATA_FRAME_NTOH(frame)
+#else
+#define SPDYF_DATA_FRAME_NTOH(frame) do { \
+ *((uint32_t *) frame ) = ntohl(*((uint32_t *) frame ));\
+ (frame)->length = NTOH24((frame)->length); \
+ } while (0)
+#endif
+
+
+/**
+ * Creates one or more new SPDYF_Response_Queue object to be put on the
+ * response queue.
+ *
+ * @param is_data whether new data frame or new control frame will be
+ * crerated
+ * @param data the row stream which will be used as the body of the frame
+ * @param data_size length of data
+ * @param response object, part of which is the frame
+ * @param stream on which data is to be sent
+ * @param closestream TRUE if the frame must close the stream (with flag)
+ * @param frqcb callback to notify application layer when the frame
+ * has been sent or discarded
+ * @param frqcb_cls closure for frqcb
+ * @param rrcb callback used by the application layer to notify the
+ * application when the frame has been sent or discarded.
+ * frqcb will call it
+ * @param rrcb_cls closure for rrcb
+ * @return double linked list of SPDYF_Response_Queue structures: one or
+ * more frames are returned based on the size of the data
+ */
+struct SPDYF_Response_Queue *
+SPDYF_response_queue_create(bool is_data,
+ void *data,
+ size_t data_size,
+ struct SPDY_Response *response,
+ struct SPDYF_Stream *stream,
+ bool closestream,
+
SPDYF_ResponseQueueResultCallback frqcb,
+ void *frqcb_cls,
+ SPDY_ResponseResultCallback
rrcb,
+ void *rrcb_cls);
+
+
+/**
+ * Destroys SPDYF_Response_Queue structure and whatever is in it.
+ *
+ * @param response_queue to destroy
+ */
+void
+SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue);
+
+
+/**
+ * Transforms raw binary decomressed stream of headers
+ * into SPDY_NameValue, containing all of the headers and values.
+ *
+ * @param stream that is to be transformed
+ * @param size length of the stream
+ * @param container will contain the newly created SPDY_NameValue
+ * container. Should point to NULL.
+ * @return SPDY_YES on success
+ * SPDY_NO on memory error
+ * SPDY_INPUT_ERROR if the provided stream is not valid
+ */
+int
+SPDYF_name_value_from_stream(void *stream,
+ size_t size,
+ struct SPDY_NameValue
** container);
+
+
+/**
+ * Transforms array of objects of name/values tuples, containing HTTP
+ * headers, into raw binary stream. The resulting stream is ready to
+ * be compressed and sent.
+ *
+ * @param container one or more SPDY_NameValue objects. Each object
+ * contains multiple number of name/value tuples.
+ * @param num_containers length of the array
+ * @param stream will contain the resulting stream. Should point to NULL.
+ * @return length of stream or value less than 0 indicating error
+ */
+ssize_t
+SPDYF_name_value_to_stream(struct SPDY_NameValue * container[],
+ int num_containers,
+ void **stream);
+
+#endif
Added: libmicrohttpd/src/microspdy/tls.c
===================================================================
--- libmicrohttpd/src/microspdy/tls.c (rev 0)
+++ libmicrohttpd/src/microspdy/tls.c 2013-05-05 19:21:40 UTC (rev 27030)
@@ -0,0 +1,255 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file tls.c
+ * @brief TLS handling using libssl. The current code assumes that
+ * blocking I/O is in use.
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include "internal.h"
+#include "session.h"
+#include "tls.h"
+
+
+/**
+ * Callback to advertise spdy ver. 3 in Next Protocol Negotiation
+ *
+ * @param ssl openssl context for a connection
+ * @param out must be set to the raw data that is advertised in NPN
+ * @param outlen must be set to size of out
+ * @param arg
+ * @return SSL_TLSEXT_ERR_OK to do advertising
+ */
+static int
+spdyf_next_protos_advertised_cb (SSL *ssl, const unsigned char **out, unsigned
int *outlen, void *arg)
+{
+ (void)ssl;
+ (void)arg;
+ static unsigned char npn_spdy3[] = {0x06, // length of "spdy/3"
+ 0x73,0x70,0x64,0x79,0x2f,0x33};// spdy/3
+
+ *out = npn_spdy3;
+ *outlen = 7; // total length of npn_spdy3
+ return SSL_TLSEXT_ERR_OK;
+}
+
+
+void
+SPDYF_tls_global_init()
+{
+ //error strings are now not used by the lib
+ //SSL_load_error_strings();
+ //init libssl
+ SSL_library_init(); //always returns 1
+ //the table for looking up algos is not used now by the lib
+ //OpenSSL_add_all_algorithms();
+}
+
+
+void
+SPDYF_tls_global_deinit()
+{
+ //if SSL_load_error_strings was called
+ //ERR_free_strings();
+ //if OpenSSL_add_all_algorithms was called
+ //EVP_cleanup();
+}
+
+
+int
+SPDYF_tls_init(struct SPDY_Daemon *daemon)
+{
+ //create ssl context. TLSv1 used
+ if(NULL == (daemon->tls_context = SSL_CTX_new(TLSv1_server_method())))
+ {
+ SPDYF_DEBUG("Couldn't create ssl context");
+ return SPDY_NO;
+ }
+ //set options for tls
+ //TODO DH is not enabled for easier debugging
+ //SSL_CTX_set_options(daemon->tls_context, SSL_OP_SINGLE_DH_USE);
+
+ //TODO here session tickets are disabled for easier debuging with
+ //wireshark when using Chrome
+ //SSL_OP_NO_COMPRESSION disables TLS compression to avoid CRIME attack
+ SSL_CTX_set_options(daemon->tls_context, SSL_OP_NO_TICKET |
SSL_OP_NO_COMPRESSION);
+ if(1 != SSL_CTX_use_certificate_file(daemon->tls_context, daemon->certfile
, SSL_FILETYPE_PEM))
+ {
+ SPDYF_DEBUG("Couldn't load the cert file");
+ SSL_CTX_free(daemon->tls_context);
+ return SPDY_NO;
+ }
+ if(1 != SSL_CTX_use_PrivateKey_file(daemon->tls_context, daemon->keyfile,
SSL_FILETYPE_PEM))
+ {
+ SPDYF_DEBUG("Couldn't load the name file");
+ SSL_CTX_free(daemon->tls_context);
+ return SPDY_NO;
+ }
+ SSL_CTX_set_next_protos_advertised_cb(daemon->tls_context,
&spdyf_next_protos_advertised_cb, NULL);
+ //TODO only RC4-SHA is used to make it easy to debug with wireshark
+ if (1 != SSL_CTX_set_cipher_list(daemon->tls_context, "RC4-SHA"))
+ {
+ SPDYF_DEBUG("Couldn't set the desired cipher list");
+ SSL_CTX_free(daemon->tls_context);
+ return SPDY_NO;
+ }
+
+ return SPDY_YES;
+}
+
+
+void
+SPDYF_tls_deinit(struct SPDY_Daemon *daemon)
+{
+ SSL_CTX_free(daemon->tls_context);
+}
+
+
+int
+SPDYF_tls_new_session(struct SPDY_Session *session)
+{
+ int ret;
+
+ if(NULL == (session->tls_context =
SSL_new(session->daemon->tls_context)))
+ {
+ SPDYF_DEBUG("Couldn't create ssl structure");
+ return SPDY_NO;
+ }
+ if(1 != (ret = SSL_set_fd(session->tls_context, session->socket_fd)))
+ {
+ SPDYF_DEBUG("SSL_set_fd %i",ret);
+ SSL_free(session->tls_context);
+ session->tls_context = NULL;
+ return SPDY_NO;
+ }
+
+ //for non-blocking I/O SSL_accept may return -1
+ //and this function won't work
+ if(1 != (ret = SSL_accept(session->tls_context)))
+ {
+ SPDYF_DEBUG("SSL_accept %i",ret);
+ SSL_free(session->tls_context);
+ session->tls_context = NULL;
+ return SPDY_NO;
+ }
+ /* alternatively
+ SSL_set_accept_state(session->tls_context);
+ * may be called and then the negotiation will be done on reading
+ */
+
+ return SPDY_YES;
+}
+
+
+void
+SPDYF_tls_close_session(struct SPDY_Session *session)
+{
+ //SSL_shutdown sends TLS "close notify" as in TLS standard.
+ //The function may fail as it waits for the other party to also close
+ //the TLS session. The lib just sends it and will close the socket
+ //after that because the browsers don't seem to care much about
+ //"close notify"
+ SSL_shutdown(session->tls_context);
+
+ SSL_free(session->tls_context);
+}
+
+
+int
+SPDYF_tls_recv(struct SPDY_Session *session,
+ void * buffer,
+ size_t size)
+{
+ int ret;
+ int n = SSL_read(session->tls_context,
+ buffer,
+ size);
+ //if(n > 0) SPDYF_DEBUG("recvd: %i",n);
+ if (n <= 0)
+ {
+ ret = SSL_get_error(session->tls_context, n);
+ switch(ret)
+ {
+ case SSL_ERROR_ZERO_RETURN:
+ return 0;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return SPDY_TLS_ERROR_AGAIN;
+
+ case SSL_ERROR_SYSCALL:
+ if(EINTR == errno)
+ return SPDY_TLS_ERROR_AGAIN;
+
+ default:
+ return SPDY_TLS_ERROR_ERROR;
+ }
+ }
+
+ return n;
+}
+
+
+int
+SPDYF_tls_send(struct SPDY_Session *session,
+ const void * buffer,
+ size_t size)
+{
+ int ret;
+
+ int n = SSL_write(session->tls_context,
+ buffer,
+ size);
+ //if(n > 0) SPDYF_DEBUG("sent: %i",n);
+ if (n <= 0)
+ {
+ ret = SSL_get_error(session->tls_context, n);
+ switch(ret)
+ {
+ case SSL_ERROR_ZERO_RETURN:
+ return 0;
+
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return SPDY_TLS_ERROR_AGAIN;
+
+ case SSL_ERROR_SYSCALL:
+ if(EINTR == errno)
+ return SPDY_TLS_ERROR_AGAIN;
+
+ default:
+ return SPDY_TLS_ERROR_ERROR;
+ }
+ }
+
+ return n;
+}
+
+
+int
+SPDYF_tls_is_pending(struct SPDY_Session *session)
+{
+ /* From openssl docs:
+ * BUGS
+SSL_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().
+ */
+ return SSL_pending(session->tls_context) > 0 ? SPDY_YES : SPDY_NO;
+}
Added: libmicrohttpd/src/microspdy/tls.h
===================================================================
--- libmicrohttpd/src/microspdy/tls.h (rev 0)
+++ libmicrohttpd/src/microspdy/tls.h 2013-05-05 19:21:40 UTC (rev 27030)
@@ -0,0 +1,171 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2012 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file tls.h
+ * @brief TLS handling. openssl with NPN is used, but as long as the
+ * functions conform to this interface file, other
libraries
+ * can be used.
+ * @author Andrey Uzunov
+ */
+
+#ifndef TLS_H
+#define TLS_H
+
+#include "platform.h"
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+
+/* macros used in other files instead of types.
+ * useful in case of changing openssl to something else */
+#define SPDYF_TLS_SESSION_CONTEXT SSL
+#define SPDYF_TLS_DAEMON_CONTEXT SSL_CTX
+
+
+/**
+ * Used for return code when reading and writing to the TLS socket.
+ */
+enum SPDY_TLS_ERROR
+{
+ /**
+ * The connection was closed by the other party.
+ */
+ SPDY_TLS_ERROR_CLOSED = 0,
+
+ /**
+ * Any kind of error ocurred. The session has to be closed.
+ */
+ SPDY_TLS_ERROR_ERROR = -2,
+
+ /**
+ * The function had to return without processing any data. The whole
+ * cycle of events has to be called again (SPDY_run) as something
+ * either has to be written or read or the the syscall was
+ * interrupted by a signal.
+ */
+ SPDY_TLS_ERROR_AGAIN = -3,
+};
+
+
+/**
+ * Global initializing of openssl. Must be called only once in the program.
+ *
+ */
+void
+SPDYF_tls_global_init();
+
+
+/**
+ * Global deinitializing of openssl for the whole program. Should be called
+ * at the end of the program.
+ *
+ */
+void
+SPDYF_tls_global_deinit();
+
+
+/**
+ * Initializing of openssl for a specific daemon.
+ * Must be called when the daemon starts.
+ *
+ * @param daemon SPDY_Daemon for which openssl will be used. Daemon's
+ * certificate and key file are used.
+ * @return SPDY_YES on success or SPDY_NO on error
+ */
+int
+SPDYF_tls_init(struct SPDY_Daemon *daemon);
+
+
+/**
+ * Deinitializing openssl for a daemon. Should be called
+ * when the deamon is stopped.
+ *
+ * @param daemon SPDY_Daemon which is being stopped
+ */
+void
+SPDYF_tls_deinit(struct SPDY_Daemon *daemon);
+
+
+/**
+ * Initializing openssl for a specific connection. Must be called
+ * after the connection has been accepted.
+ *
+ * @param session SPDY_Session whose socket will be used by openssl
+ * @return SPDY_NO if some openssl funcs fail. SPDY_YES otherwise
+ */
+int
+SPDYF_tls_new_session(struct SPDY_Session *session);
+
+
+/**
+ * Deinitializing openssl for a specific connection. Should be called
+ * closing session's socket.
+ *
+ * @param session SPDY_Session whose socket is used by openssl
+ */
+void
+SPDYF_tls_close_session(struct SPDY_Session *session);
+
+
+/**
+ * Reading from a TLS socket. Reads available data and put it to the
+ * buffer.
+ *
+ * @param session for which data is received
+ * @param buffer where data from the socket will be written to
+ * @param size of the buffer
+ * @return number of bytes (at most size) read from the TLS connection
+ * 0 if the other party has closed the connection
+ * SPDY_TLS_ERROR code on error
+ */
+int
+SPDYF_tls_recv(struct SPDY_Session *session,
+ void * buffer,
+ size_t size);
+
+
+/**
+ * Writing to a TLS socket. Writes the data given into the buffer to the
+ * TLS socket.
+ *
+ * @param session whose context is used
+ * @param buffer from where data will be written to the socket
+ * @param size number of bytes to be taken from the buffer
+ * @return number of bytes (at most size) from the buffer that has been
+ * written to the TLS connection
+ * 0 if the other party has closed the connection
+ * SPDY_TLS_ERROR code on error
+ */
+int
+SPDYF_tls_send(struct SPDY_Session *session,
+ const void * buffer,
+ size_t size);
+
+
+/**
+ * Checks if there is data staying in the buffers of the underlying
+ * system that waits to be read.
+ *
+ * @param session which is checked
+ * @return SPDY_YES if data is pending or SPDY_NO otherwise
+ */
+int
+SPDYF_tls_is_pending(struct SPDY_Session *session);
+
+#endif
Added: libmicrohttpd/src/spdy2http/Makefile.am
===================================================================
--- libmicrohttpd/src/spdy2http/Makefile.am (rev 0)
+++ libmicrohttpd/src/spdy2http/Makefile.am 2013-05-05 19:21:40 UTC (rev
27030)
@@ -0,0 +1,35 @@
+SUBDIRS = .
+
+AM_CFLAGS = -DDATADIR=\"$(top_srcdir)/src/datadir/\"
+
+if USE_COVERAGE
+ AM_CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+if USE_PRIVATE_PLIBC_H
+ PLIBC_INCLUDE = -I$(top_srcdir)/src/include/plibc
+endif
+
+AM_CPPFLAGS = \
+ $(PLIBC_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/src/applicationlayer \
+$(LIBCURL_CPPFLAGS)
+
+if !HAVE_W32
+PERF_GET_CONCURRENT=perf_get_concurrent
+endif
+
+bin_PROGRAMS = \
+ microspdy2http
+
+microspdy2http_SOURCES = \
+ proxy.c
+microspdy2http_LDADD = \
+ $(top_builddir)/src/microspdy/libmicrospdy.la \
+ -lssl \
+ -lcrypto \
+ -lz \
+ -ldl \
+ -lcurl
Added: libmicrohttpd/src/spdy2http/proxy.c
===================================================================
--- libmicrohttpd/src/spdy2http/proxy.c (rev 0)
+++ libmicrohttpd/src/spdy2http/proxy.c 2013-05-05 19:21:40 UTC (rev 27030)
@@ -0,0 +1,625 @@
+/*
+ This file is part of libmicrospdy
+ Copyright (C) 2013 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file proxy.c
+ * @brief Translates incoming SPDY requests to http server on localhost.
+ * Uses libcurl.
+ * @author Andrey Uzunov
+ */
+
+#include "platform.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "microspdy.h"
+#include <curl/curl.h>
+#include <assert.h>
+
+
+#define PRINT_INFO(msg) do{\
+ printf("%i:%s\n", __LINE__, msg);\
+ fflush(stdout);\
+ }\
+ while(0)
+
+
+#define PRINT_INFO2(fmt, ...) do{\
+ printf("%i\n", __LINE__);\
+ printf(fmt,##__VA_ARGS__);\
+ printf("\n");\
+ fflush(stdout);\
+ }\
+ while(0)
+
+
+#define CURL_SETOPT(handle, opt, val) do{\
+ int ret; \
+ if(CURLE_OK != (ret = curl_easy_setopt(handle, opt, val))) \
+ { \
+ PRINT_INFO2("curl_easy_setopt failed (%i = %i)", opt, ret); \
+ abort(); \
+ } \
+ }\
+ while(0)
+
+
+int run = 1;
+char* http_host;
+CURLM *multi_handle;
+int still_running = 0; /* keep number of running handles */
+int http10=0;
+
+struct Proxy
+{
+ char *path;
+ struct SPDY_Request *request;
+ struct SPDY_Response *response;
+ CURL *curl_handle;
+ struct curl_slist *curl_headers;
+ struct SPDY_NameValue *headers;
+ char *version;
+ char *status_msg;
+ void *http_body;
+ size_t http_body_size;
+ ssize_t length;
+ int status;
+};
+
+
+ssize_t
+response_callback (void *cls,
+ void *buffer,
+ size_t max,
+ bool *more)
+{
+ int ret;
+ struct Proxy *proxy = (struct Proxy *)cls;
+ void *newbody;
+
+ //printf("response_callback\n");
+
+ assert(0 != proxy->length);
+
+ *more = true;
+ if(!proxy->http_body_size)//nothing to write now
+ return 0;
+
+ if(max >= proxy->http_body_size)
+ {
+ ret = proxy->http_body_size;
+ newbody = NULL;
+ }
+ else
+ {
+ ret = max;
+ if(NULL == (newbody = malloc(proxy->http_body_size - max)))
+ {
+ PRINT_INFO("no memory");
+ return -1;
+ }
+ memcpy(newbody, proxy->http_body + max, proxy->http_body_size -
max);
+ }
+ memcpy(buffer, proxy->http_body, ret);
+ free(proxy->http_body);
+ proxy->http_body = newbody;
+ proxy->http_body_size -= ret;
+
+ if(proxy->length >= 0)
+ {
+ proxy->length -= ret;
+ //printf("pr len %i", proxy->length);
+ if(proxy->length <= 0)
+ {
+ *more = false;
+ //last frame
+ proxy->length = 0;
+ }
+ }
+
+ return ret;
+}
+
+
+void
+response_done_callback(void *cls,
+ struct SPDY_Response *response,
+ struct SPDY_Request *request,
+ enum SPDY_RESPONSE_RESULT
status,
+ bool streamopened)
+{
+ (void)streamopened;
+ struct Proxy *proxy = (struct Proxy *)cls;
+ int ret;
+
+ //printf("response_done_callback\n");
+
+ //printf("answer for %s was sent\n", (char *)cls);
+
+ if(SPDY_RESPONSE_RESULT_SUCCESS != status)
+ {
+ printf("answer was NOT sent, %i\n",status);
+ }
+ if(CURLM_OK != (ret = curl_multi_remove_handle(multi_handle,
proxy->curl_handle)))
+ {
+ PRINT_INFO2("curl_multi_remove_handle failed (%i)", ret);
+ }
+ curl_slist_free_all(proxy->curl_headers);
+ curl_easy_cleanup(proxy->curl_handle);
+
+ SPDY_destroy_request(request);
+ SPDY_destroy_response(response);
+ if(!strcmp("/close",proxy->path)) run = 0;
+ free(proxy->path);
+ free(proxy);
+}
+
+
+static size_t
+curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp)
+{
+ size_t realsize = size * nmemb;
+ struct Proxy *proxy = (struct Proxy *)userp;
+ char *line = (char *)ptr;
+ char *name;
+ char *value;
+ char *status;
+ const char *const*length;
+ int i;
+ int pos;
+
+ //printf("curl_header_cb\n");
+
+ if('\r' == line[0])
+ {
+ //all headers were already handled; prepare spdy frames
+ if(NULL == (proxy->response =
SPDY_build_response_with_callback(proxy->status,
+ proxy->status_msg,
+ proxy->version,
+ proxy->headers,
+ &response_callback,
+ proxy,
+ 0)))
+ {
+ PRINT_INFO("no response");
+ abort();
+ }
+ if(NULL != (length = SPDY_name_value_lookup(proxy->headers,
+ SPDY_HTTP_HEADER_CONTENT_LENGTH,
+ &i)))
+ proxy->length = atoi(length[0]);
+ else
+ proxy->length = -1;
+ SPDY_name_value_destroy(proxy->headers);
+ free(proxy->status_msg);
+ free(proxy->version);
+
+ if(SPDY_YES != SPDY_queue_response(proxy->request,
+ proxy->response,
+ true,
+ false,
+ &response_done_callback,
+ proxy))
+ {
+ PRINT_INFO("no queue");
+ abort();
+ }
+ //printf("spdy headers queued %i\n");
+
+ return realsize;
+ }
+
+ pos = 0;
+ if(NULL == proxy->version)
+ {
+ //first line from headers
+ //version
+ for(i=pos; i<realsize && ' '!=line[i]; ++i);
+ if(i == realsize)
+ {
+ PRINT_INFO("error on parsing headers");
+ abort();
+ }
+ if(NULL == (proxy->version = strndup(line, i - pos)))
+ {
+ PRINT_INFO("no memory");
+ abort();
+ }
+ pos = i+1;
+
+ //status (number)
+ for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i]; ++i);
+ if(NULL == (status = strndup(&(line[pos]), i - pos)))
+ {
+ PRINT_INFO("no memory");
+ abort();
+ }
+ proxy->status = atoi(status);
+ free(status);
+ if(i<realsize && '\r'!=line[i])
+ {
+ //status (message)
+ pos = i+1;
+ for(i=pos; i<realsize && '\r'!=line[i]; ++i);
+ if(NULL == (proxy->status_msg = strndup(&(line[pos]), i
- pos)))
+ {
+ PRINT_INFO("no memory");
+ abort();
+ }
+ }
+ return realsize;
+ }
+
+ //other lines
+ //header name
+ for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i]; ++i)
+ line[i] = tolower(line[i]); //spdy requires lower case
+ if(NULL == (name = strndup(line, i - pos)))
+ {
+ PRINT_INFO("no memory");
+ abort();
+ }
+ if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name)
+ || 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name))
+ {
+ //forbidden in spdy, ignore
+ free(name);
+ return realsize;
+ }
+ if(i == realsize || '\r'==line[i])
+ {
+ //no value. is it possible?
+ if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, ""))
+ {
+ PRINT_INFO("SPDY_name_value_add failed");
+ abort();
+ }
+ return realsize;
+ }
+
+ //header value
+ pos = i+1;
+ while(pos<realsize && isspace(line[pos])) ++pos; //remove leading space
+ for(i=pos; i<realsize && '\r'!=line[i]; ++i);
+ if(NULL == (value = strndup(&(line[pos]), i - pos)))
+ {
+ PRINT_INFO("no memory");
+ abort();
+ }
+ if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, value))
+ {
+ PRINT_INFO("SPDY_name_value_add failed");
+ abort();
+ }
+ free(name);
+ free(value);
+
+ return realsize;
+}
+
+
+static size_t
+curl_write_cb(void *contents, size_t size, size_t nmemb, void *userp)
+{
+ size_t realsize = size * nmemb;
+ struct Proxy *proxy = (struct Proxy *)userp;
+
+ //printf("curl_write_cb %i\n", realsize);
+
+ if(NULL == proxy->http_body)
+ proxy->http_body = malloc(realsize);
+ else
+ proxy->http_body = realloc(proxy->http_body,
proxy->http_body_size + realsize);
+ if(NULL == proxy->http_body)
+ {
+ PRINT_INFO("not enough memory (realloc returned NULL)");
+ return 0;
+ }
+
+ memcpy(proxy->http_body + proxy->http_body_size, contents, realsize);
+ proxy->http_body_size += realsize;
+
+ return realsize;
+}
+
+
+int
+iterate_cb (void *cls, const char *name, const char * const * value, int
num_values)
+{
+ struct Proxy *proxy = (struct Proxy *)cls;
+ struct curl_slist **curl_headers = (&(proxy->curl_headers));
+ char *line;
+ int line_len = strlen(name) + 3; //+ ": \0"
+ int i;
+
+ for(i=0; i<num_values; ++i)
+ {
+ if(i) line_len += 2; //", "
+ line_len += strlen(value[i]);
+ }
+
+ if(NULL == (line = malloc(line_len)))
+ {
+ //no recovory
+ PRINT_INFO("no memory");
+ abort();
+ }
+ line[0] = 0;
+
+ strcat(line, name);
+ strcat(line, ": ");
+ //all spdy header names are lower case;
+ //for simplicity here we just capitalize the first letter
+ line[0] = toupper(line[0]);
+
+ for(i=0; i<num_values; ++i)
+ {
+ if(i) strcat(line, ", ");
+ strcat(line, value[i]);
+ }
+ if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line)))
+ {
+ PRINT_INFO("curl_slist_append failed");
+ abort();
+ }
+ free(line);
+
+ return SPDY_YES;
+}
+
+
+void
+standard_request_handler(void *cls,
+ struct SPDY_Request * request,
+ uint8_t priority,
+ const char *method,
+ const char *path,
+ const char *version,
+ const char *host,
+ const char *scheme,
+ struct SPDY_NameValue * headers)
+{
+ (void)cls;
+ (void)priority;
+ (void)host;
+ (void)scheme;
+
+ char *url;
+ struct Proxy *proxy;
+ int ret;
+
+ //printf("received request for '%s %s %s'\n", method, path, version);
+ if(NULL == (proxy = malloc(sizeof(struct Proxy))))
+ {
+ PRINT_INFO("No memory");
+ abort();
+ }
+ memset(proxy, 0, sizeof(struct Proxy));
+ proxy->request = request;
+ if(NULL == (proxy->headers = SPDY_name_value_create()))
+ {
+ PRINT_INFO("No memory");
+ abort();
+ }
+
+ if(-1 == asprintf(&url,"%s%s%s","http://", http_host, path))
+ {
+ PRINT_INFO("No memory");
+ abort();
+ }
+
+ if(NULL == (proxy->path = strdup(path)))
+ {
+ PRINT_INFO("No memory");
+ abort();
+ }
+
+ SPDY_name_value_iterate(headers, &iterate_cb, proxy);
+
+ if(NULL == (proxy->curl_handle = curl_easy_init()))
+ {
+ PRINT_INFO("curl_easy_init failed");
+ abort();
+ }
+
+ //CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, url);
+ free(url);
+ if(http10)
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTP_VERSION,
CURL_HTTP_VERSION_1_0);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERFUNCTION, curl_header_cb);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERDATA, proxy);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTPHEADER,
proxy->curl_headers);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
+ CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
+
+ if(CURLM_OK != (ret = curl_multi_add_handle(multi_handle,
proxy->curl_handle)))
+ {
+ PRINT_INFO2("curl_multi_add_handle failed (%i)", ret);
+ abort();
+ }
+
+ if(CURLM_OK != (ret = curl_multi_perform(multi_handle, &still_running))
+ && CURLM_CALL_MULTI_PERFORM != ret)
+ {
+ PRINT_INFO2("curl_multi_perform failed (%i)", ret);
+ abort();
+ }
+}
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned long long timeoutlong=0;
+ long curl_timeo = -1;
+ struct timeval timeout;
+ int ret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ fd_set curl_rs;
+ fd_set curl_ws;
+ fd_set curl_es;
+ int maxfd = -1;
+ struct SPDY_Daemon *daemon;
+
+ //signal(SIGPIPE, SIG_IGN);
+
+ if(argc != 6)
+ {
+ printf("Usage: %s cert-file key-file host port
http/1.0(yes/no)\n", argv[0]);
+ return 1;
+ }
+
+ SPDY_init();
+
+ daemon = SPDY_start_daemon(atoi(argv[4]),
+ argv[1],
+ argv[2],
+ NULL,
+ NULL,
+
&standard_request_handler,
+ NULL,
+ NULL,
+
SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
+ 1800,
+
SPDY_DAEMON_OPTION_END);
+
+ if(NULL==daemon){
+ printf("no daemon\n");
+ return 1;
+ }
+
+ multi_handle = curl_multi_init();
+
+ if(NULL==multi_handle){
+ PRINT_INFO("no multi_handle");
+ abort();
+ }
+
+ if(!strcmp("yes", argv[5]))
+ http10 = 1;
+
+ http_host = argv[3];
+ timeout.tv_usec = 0;
+
+ do
+ {
+ //printf("still %i\n", still_running);
+ FD_ZERO(&rs);
+ FD_ZERO(&ws);
+ FD_ZERO(&es);
+ FD_ZERO(&curl_rs);
+ FD_ZERO(&curl_ws);
+ FD_ZERO(&curl_es);
+
+ if(still_running > 0)
+ timeout.tv_sec = 0; //return immediately
+ else
+ {
+ ret = SPDY_get_timeout(daemon, &timeoutlong);
+ if(SPDY_NO == ret)
+ timeout.tv_sec = 1;
+ else
+ timeout.tv_sec = timeoutlong;
+ }
+ timeout.tv_usec = 0;
+
+ maxfd = SPDY_get_fdset (daemon,
+ &rs,
+ &ws,
+ &es);
+ assert(-1 != maxfd);
+
+ ret = select(maxfd+1, &rs, &ws, &es, &timeout);
+
+ switch(ret) {
+ case -1:
+ PRINT_INFO2("select error: %i", errno);
+ break;
+ case 0:
+ break;
+ default:
+ SPDY_run(daemon);
+ break;
+ }
+
+ timeout.tv_sec = 0;
+ if(still_running > 0)
+ {
+ if(CURLM_OK != (ret = curl_multi_timeout(multi_handle,
&curl_timeo)))
+ {
+ PRINT_INFO2("curl_multi_timeout failed (%i)",
ret);
+ abort();
+ }
+ if(curl_timeo >= 0 && curl_timeo < 500)
+ timeout.tv_usec = curl_timeo * 1000;
+ else
+ timeout.tv_usec = 500000;
+ }
+ else continue;
+ //else timeout.tv_usec = 500000;
+
+ if(CURLM_OK != (ret = curl_multi_fdset(multi_handle, &curl_rs,
&curl_ws, &curl_es, &maxfd)))
+ {
+ PRINT_INFO2("curl_multi_fdset failed (%i)", ret);
+ abort();
+ }
+ if(-1 == maxfd)
+ {
+ PRINT_INFO("maxfd is -1");
+ //continue;
+ ret = 0;
+ }
+ else
+ ret = select(maxfd+1, &curl_rs, &curl_ws, &curl_es, &timeout);
+
+ switch(ret) {
+ case -1:
+ PRINT_INFO2("select error: %i", errno);
+ break;
+ case 0: /* timeout */
+ //break or not
+ default: /* action */
+ if(CURLM_OK != (ret =
curl_multi_perform(multi_handle, &still_running))
+ && CURLM_CALL_MULTI_PERFORM != ret)
+ {
+ PRINT_INFO2("curl_multi_perform failed
(%i)", ret);
+ abort();
+ }
+ break;
+ }
+ }
+ while(run);
+
+ curl_multi_cleanup(multi_handle);
+
+ SPDY_stop_daemon(daemon);
+
+ SPDY_deinit();
+
+ return 0;
+}
+
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r27030 - in libmicrohttpd: . doc m4 src src/datadir src/examples src/include src/microspdy src/spdy2http,
gnunet <=