gnunet-svn
[Top][All Lists]
Advanced

[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;
+}
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]