瀏覽代碼

killing libmicrospdy

Christian Grothoff 10 年之前
父節點
當前提交
fdc3e17e30
共有 59 個文件被更改,包括 7 次插入22164 次删除
  1. 3 0
      ChangeLog
  2. 0 3
      Makefile.am
  3. 0 77
      configure.ac
  4. 0 13
      libmicrospdy.pc.in
  5. 0 124
      m4/ax_check_openssl.m4
  6. 2 14
      src/Makefile.am
  7. 0 2856
      src/datadir/spdy-draft.txt
  8. 1 39
      src/examples/Makefile.am
  9. 0 322
      src/examples/mhd2spdy.c
  10. 0 422
      src/examples/mhd2spdy_http.c
  11. 0 54
      src/examples/mhd2spdy_http.h
  12. 0 1150
      src/examples/mhd2spdy_spdy.c
  13. 0 102
      src/examples/mhd2spdy_spdy.h
  14. 0 162
      src/examples/mhd2spdy_structures.c
  15. 0 296
      src/examples/mhd2spdy_structures.h
  16. 0 487
      src/examples/spdy_event_loop.c
  17. 0 353
      src/examples/spdy_fileserver.c
  18. 0 236
      src/examples/spdy_response_with_callback.c
  19. 1 5
      src/include/Makefile.am
  20. 0 1380
      src/include/microspdy.h
  21. 0 40
      src/microspdy/Makefile.am
  22. 0 41
      src/microspdy/alstructures.c
  23. 0 79
      src/microspdy/alstructures.h
  24. 0 748
      src/microspdy/applicationlayer.c
  25. 0 31
      src/microspdy/applicationlayer.h
  26. 0 441
      src/microspdy/compression.c
  27. 0 117
      src/microspdy/compression.h
  28. 0 544
      src/microspdy/daemon.c
  29. 0 130
      src/microspdy/daemon.h
  30. 0 40
      src/microspdy/internal.c
  31. 0 199
      src/microspdy/internal.h
  32. 0 90
      src/microspdy/io.c
  33. 0 216
      src/microspdy/io.h
  34. 0 280
      src/microspdy/io_openssl.c
  35. 0 166
      src/microspdy/io_openssl.h
  36. 0 194
      src/microspdy/io_raw.c
  37. 0 158
      src/microspdy/io_raw.h
  38. 0 1769
      src/microspdy/session.c
  39. 0 281
      src/microspdy/session.h
  40. 0 169
      src/microspdy/stream.c
  41. 0 76
      src/microspdy/stream.h
  42. 0 638
      src/microspdy/structures.c
  43. 0 1246
      src/microspdy/structures.h
  44. 0 29
      src/spdy2http/Makefile.am
  45. 0 1411
      src/spdy2http/proxy.c
  46. 0 115
      src/testspdy/Makefile.am
  47. 0 59
      src/testspdy/common.c
  48. 0 38
      src/testspdy/common.h
  49. 0 49
      src/testspdy/test_daemon_start_stop.c
  50. 0 66
      src/testspdy/test_daemon_start_stop_many.c
  51. 0 289
      src/testspdy/test_misc.c
  52. 0 1012
      src/testspdy/test_new_connection.c
  53. 0 973
      src/testspdy/test_notls.c
  54. 0 255
      src/testspdy/test_proxies.c
  55. 0 1029
      src/testspdy/test_request_response.c
  56. 0 320
      src/testspdy/test_request_response_with_callback.c
  57. 0 47
      src/testspdy/test_requests_with_assets.c
  58. 0 338
      src/testspdy/test_session_timeout.c
  59. 0 346
      src/testspdy/test_struct_namevalue.c

+ 3 - 0
ChangeLog

@@ -1,3 +1,6 @@
+Tue Dec  1 14:05:13 CET 2015
+	SPDY is dead, killing experimental libmicrospdy. -CG
+
 Tue Dec  1 10:01:12 CET 2015
 	New logic for controlling socket buffer modes.
 	Eliminated delay before last packet in response and before

+ 0 - 3
Makefile.am

@@ -8,9 +8,6 @@ EXTRA_DIST = acinclude.m4 libmicrohttpd.pc.in libmicrospdy.pc.in  \
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libmicrohttpd.pc 
-if ENABLE_SPDY
-pkgconfig_DATA += libmicrospdy.pc
-endif
 
 if BUILD_DOC
 SUBDIRS += doc

+ 0 - 77
configure.ac

@@ -595,77 +595,6 @@ AC_CHECK_LIB([[magic]], [[magic_open]],
   AM_CONDITIONAL(HAVE_MAGIC, false))
 
 
-# optional: libmicrospdy support. Enabled by default if not on W32
-AC_ARG_ENABLE([spdy],
-		AS_HELP_STRING([--enable-spdy],
-			[enable build libmicrospdy (yes, no, auto) [auto]]),
-		[enable_spdy=${enableval}],
-		[ AS_IF([[test "x$os_is_windows" = "xyes"]], [enable_spdy=no]) ])
-
-if test "$enable_spdy" != "no"
-then
-  AX_CHECK_OPENSSL([ have_openssl=yes ],[ have_openssl=no ])
-  if test "x$have_openssl" = "xyes"
-  then
-    # check OpenSSL headers
-    SAVE_CPP_FLAGS="$CPPFLAGS"
-    CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS"
-    AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h], [ have_openssl=yes ],[ have_openssl=no ])
-    if test "x$have_openssl" = "xyes"
-    then
-      # check OpenSSL libs
-      SAVE_LIBS="$LIBS"
-      SAVE_LD_FLAGS="$LDFLAGS"
-      LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS"
-      LIBS="$OPENSSL_LIBS $LIBS"
-      AC_CHECK_FUNC([SSL_CTX_set_next_protos_advertised_cb],
-        [
-          AC_CHECK_FUNC([SSL_library_init], [ have_openssl=yes ],[ have_openssl=no ])
-        ],[ have_openssl=no ])
-      LIBS="$SAVE_LIBS"
-      LDFLAGS="$SAVE_LD_FLAGS"
-    fi
-    CPPFLAGS="$SAVE_CPP_FLAGS"
-  fi
-  if test "x$have_openssl" = "xyes"
-  then
-    enable_spdy=yes
-  else
-    AS_IF([[test "x$enable_spdy" = "xyes" ]], [AC_MSG_ERROR([[libmicrospdy cannot be enabled without OpenSSL.]])])
-    have_openssl=no
-    enable_spdy=no
-  fi
-else
-  # OpenSSL is used only for libmicrospdy
-  have_openssl=no
-fi
-AM_CONDITIONAL([HAVE_OPENSSL], [test "x$have_openssl" = "xyes"])
-
-if test "$enable_spdy" = "yes"
-then
- AC_DEFINE([SPDY_SUPPORT],[1],[include libmicrospdy support])
-else
- AC_DEFINE([SPDY_SUPPORT],[0],[disable libmicrospdy support])
-fi
-AM_CONDITIONAL(ENABLE_SPDY, [test "x$enable_spdy" != "xno"])
-AC_MSG_CHECKING(whether we have OpenSSL and thus can support libmicrospdy)
-AC_MSG_RESULT($enable_spdy)
-
-# for pkg-config
-SPDY_LIBDEPS="$OPENSSL_LIBS"
-
-SPDY_LIB_LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS"
-SPDY_LIB_CFLAGS="$CFLAGS"
-SPDY_LIB_CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS"
-AC_SUBST(SPDY_LIB_LDFLAGS)
-AC_SUBST(SPDY_LIB_CFLAGS)
-AC_SUBST(SPDY_LIB_CPPFLAGS)
-# for pkg-config
-AC_SUBST(SPDY_LIBDEPS)
-
-AC_CHECK_HEADERS([spdylay/spdylay.h], [ have_spdylay="yes" ], [have_spdylay="no"])
-AM_CONDITIONAL(HAVE_SPDYLAY, [test "x$have_spdylay" = "xyes"])
-
 # large file support (> 4 GB)
 AC_SYS_LARGEFILE
 AC_FUNC_FSEEKO
@@ -946,7 +875,6 @@ AC_SUBST(LDFLAGS)
 
 AC_CONFIG_FILES([
 libmicrohttpd.pc
-libmicrospdy.pc
 w32/VS2013/microhttpd_dll_res_vc.rc
 Makefile
 contrib/Makefile
@@ -958,12 +886,9 @@ src/Makefile
 src/include/Makefile
 src/platform/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
 
@@ -989,8 +914,6 @@ AC_MSG_NOTICE([libmicrohttpd ${PACKAGE_VERSION} Configuration Summary:
   epoll support:     ${enable_epoll=no}
   build docs:        ${enable_doc}
   build examples:    ${enable_examples}
-  libmicrospdy:      ${enable_spdy}
-  spdylay (testing): ${have_spdylay}
 ])
 
 if test "x$enable_https" = "xyes"

+ 0 - 13
libmicrospdy.pc.in

@@ -1,13 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-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}

+ 0 - 124
m4/ax_check_openssl.m4

@@ -1,124 +0,0 @@
-# ===========================================================================
-#     http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]])
-#
-# DESCRIPTION
-#
-#   Look for OpenSSL in a number of default spots, or in a user-selected
-#   spot (via --with-openssl).  Sets
-#
-#     OPENSSL_INCLUDES to the include directives required
-#     OPENSSL_LIBS to the -l directives required
-#     OPENSSL_LDFLAGS to the -L or -R flags required
-#
-#   and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately
-#
-#   This macro sets OPENSSL_INCLUDES such that source files should use the
-#   openssl/ directory in include directives:
-#
-#     #include <openssl/hmac.h>
-#
-# LICENSE
-#
-#   Copyright (c) 2009,2010 Zmanda Inc. <http://www.zmanda.com/>
-#   Copyright (c) 2009,2010 Dustin J. Mitchell <[email protected]>
-#
-#   Copying and distribution of this file, with or without modification, are
-#   permitted in any medium without royalty provided the copyright notice
-#   and this notice are preserved. This file is offered as-is, without any
-#   warranty.
-
-#serial 8
-
-AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL])
-AC_DEFUN([AX_CHECK_OPENSSL], [
-    found=false
-    AC_ARG_WITH([openssl],
-        [AS_HELP_STRING([--with-openssl=DIR],
-            [root of the OpenSSL directory])],
-        [
-            case "$withval" in
-            "" | y | ye | yes | n | no)
-            AC_MSG_ERROR([Invalid --with-openssl value])
-              ;;
-            *) ssldirs="$withval"
-              ;;
-            esac
-        ], [
-            # if pkg-config is installed and openssl has installed a .pc file,
-            # then use that information and don't search ssldirs
-            AC_PATH_PROG([PKG_CONFIG], [pkg-config])
-            if test x"$PKG_CONFIG" != x""; then
-                OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null`
-                if test $? = 0; then
-                    OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null`
-                    OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null`
-                    found=true
-                fi
-            fi
-
-            # no such luck; use some default ssldirs
-            if ! $found; then
-                ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
-            fi
-        ]
-        )
-
-
-    # note that we #include <openssl/foo.h>, so the OpenSSL headers have to be in
-    # an 'openssl' subdirectory
-
-    if ! $found; then
-        OPENSSL_INCLUDES=
-        for ssldir in $ssldirs; do
-            AC_MSG_CHECKING([for openssl/ssl.h in $ssldir])
-            if test -f "$ssldir/include/openssl/ssl.h"; then
-                OPENSSL_INCLUDES="-I$ssldir/include"
-                OPENSSL_LDFLAGS="-L$ssldir/lib"
-                OPENSSL_LIBS="-lssl -lcrypto"
-                found=true
-                AC_MSG_RESULT([yes])
-                break
-            else
-                AC_MSG_RESULT([no])
-            fi
-        done
-
-        # if the file wasn't found, well, go ahead and try the link anyway -- maybe
-        # it will just work!
-    fi
-
-    # try the preprocessor and linker with our new flags,
-    # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS
-
-    AC_MSG_CHECKING([whether compiling and linking against OpenSSL works])
-    echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \
-        "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD
-
-    save_LIBS="$LIBS"
-    save_LDFLAGS="$LDFLAGS"
-    save_CPPFLAGS="$CPPFLAGS"
-    LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS"
-    LIBS="$OPENSSL_LIBS $LIBS"
-    CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS"
-    AC_LINK_IFELSE(
-        [AC_LANG_PROGRAM([#include <openssl/ssl.h>], [SSL_new(NULL)])],
-        [
-            AC_MSG_RESULT([yes])
-            $1
-        ], [
-            AC_MSG_RESULT([no])
-            $2
-        ])
-    CPPFLAGS="$save_CPPFLAGS"
-    LDFLAGS="$save_LDFLAGS"
-    LIBS="$save_LIBS"
-
-    AC_SUBST([OPENSSL_INCLUDES])
-    AC_SUBST([OPENSSL_LIBS])
-    AC_SUBST([OPENSSL_LDFLAGS])
-])

+ 2 - 14
src/Makefile.am

@@ -7,19 +7,8 @@ zzuftests = testzzuf
 endif
 endif
 endif
-if ENABLE_SPDY
-if HAVE_OPENSSL
-microspdy = microspdy
-if HAVE_CURL
-microspdy += spdy2http
-endif
-#if HAVE_SPDYLAY
-microspdy += testspdy
-#endif
-endif
-endif
 
-SUBDIRS = include platform microhttpd $(microspdy) $(curltests) $(zzuftests) .
+SUBDIRS = include platform microhttpd $(curltests) $(zzuftests) .
 
 if BUILD_EXAMPLES
 SUBDIRS += examples
@@ -27,5 +16,4 @@ endif
 
 EXTRA_DIST = \
  datadir/cert-and-key.pem \
- datadir/cert-and-key-for-wireshark.pem \
- datadir/spdy-draft.txt
+ datadir/cert-and-key-for-wireshark.pem 

+ 0 - 2856
src/datadir/spdy-draft.txt

@@ -1,2856 +0,0 @@
-
-
-
-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: [email protected]
-
-
-   Roberto Peon
-   Google, Inc
-
-   Email: [email protected]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Belshe & Peon            Expires August 4, 2012                [Page 51]
-

+ 1 - 39
src/examples/Makefile.am

@@ -13,17 +13,6 @@ if USE_COVERAGE
   AM_CFLAGS += --coverage
 endif
 
-if ENABLE_SPDY
-spdyex = \
-  spdy_event_loop \
-  spdy_fileserver \
-  spdy_response_with_callback
-
-if HAVE_SPDYLAY
-spdyex += mhd2spdy
-endif
-endif
-
 
 # example programs
 noinst_PROGRAMS = \
@@ -37,8 +26,7 @@ noinst_PROGRAMS = \
  fileserver_example \
  fileserver_example_dirs \
  fileserver_example_external_select \
- refuse_post_example \
- $(spdyex)
+ refuse_post_example 
 
 
 if ENABLE_HTTPS
@@ -98,15 +86,6 @@ demo_https_LDADD = \
  $(top_builddir)/src/microhttpd/libmicrohttpd.la  \
  $(PTHREAD_LIBS) -lmagic
 
-mhd2spdy_SOURCES = \
- mhd2spdy.c \
- mhd2spdy_spdy.c mhd2spdy_spdy.h \
- mhd2spdy_http.c mhd2spdy_http.h \
- mhd2spdy_structures.c mhd2spdy_structures.h
-mhd2spdy_LDADD = \
- $(top_builddir)/src/microhttpd/libmicrohttpd.la  \
- -lssl -lcrypto -lspdylay
-
 benchmark_SOURCES = \
  benchmark.c
 benchmark_CPPFLAGS = \
@@ -179,20 +158,3 @@ 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 \
- -lz
-
-spdy_fileserver_SOURCES = \
- spdy_fileserver.c
-spdy_fileserver_LDADD = \
-  $(top_builddir)/src/microspdy/libmicrospdy.la \
- -lz
-
-spdy_response_with_callback_SOURCES = \
- spdy_response_with_callback.c
-spdy_response_with_callback_LDADD = \
-  $(top_builddir)/src/microspdy/libmicrospdy.la \
- -lz

+ 0 - 322
src/examples/mhd2spdy.c

@@ -1,322 +0,0 @@
-/*
-    Copyright 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 mhd2spdy.c
- * @brief  The main file of the HTTP-to-SPDY proxy with the 'main' function
- *         and event loop. No threads are used.
- *         Currently only GET is supported.
- *         TODOs:
- *         - non blocking SSL connect
- *         - check certificate
- *         - on closing spdy session, close sockets for all requests
- * @author Andrey Uzunov
- */
- 
- 
-#include "mhd2spdy_structures.h"
-#include "mhd2spdy_spdy.h"
-#include "mhd2spdy_http.h"
-
-
-static int run = 1;
-//static int spdy_close = 0;
-
-
-static void
-catch_signal(int signal)
-{
-  (void)signal;
-  //spdy_close = 1;
-  run = 0;
-}
-
-
-void
-print_stat()
-{
-  if(!glob_opt.statistics)
-    return;
-  
-  printf("--------------------------\n");
-  printf("Statistics (TLS overhead is ignored when used):\n");
-  //printf("HTTP bytes received: %lld\n", glob_stat.http_bytes_received);
-  //printf("HTTP bytes sent: %lld\n", glob_stat.http_bytes_sent);
-  printf("SPDY bytes sent: %lld\n", glob_stat.spdy_bytes_sent);
-  printf("SPDY bytes received: %lld\n", glob_stat.spdy_bytes_received);
-  printf("SPDY bytes received and dropped: %lld\n", glob_stat.spdy_bytes_received_and_dropped);
-}
-
-
-int
-run_everything ()
-{	
-  unsigned long long timeoutlong=0;
-  struct timeval timeout;
-  int ret;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int maxfd = -1;
-  int maxfd_s = -1;
-  struct MHD_Daemon *daemon;
-  nfds_t spdy_npollfds = 1;
-  struct URI * spdy2http_uri = NULL;
-  struct SPDY_Connection *connection;
-  struct SPDY_Connection *connections[MAX_SPDY_CONNECTIONS];
-  struct SPDY_Connection *connection_for_delete;
-
-  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
-    PRINT_INFO("signal failed");
-    
-  if (signal(SIGINT, catch_signal) == SIG_ERR)
-    PRINT_INFO("signal failed");
-
-  glob_opt.streams_opened = 0;
-  glob_opt.responses_pending = 0;
-  //glob_opt.global_memory = 0;
-
-  srand(time(NULL));
-  
-  if(init_parse_uri(&glob_opt.uri_preg))
-    DIE("Regexp compilation failed");
-    
-  if(NULL != glob_opt.spdy2http_str)
-  {
-    ret = parse_uri(&glob_opt.uri_preg, glob_opt.spdy2http_str, &spdy2http_uri);
-    if(ret != 0)
-      DIE("spdy_parse_uri failed");
-  }
-
-  SSL_load_error_strings();
-  SSL_library_init();
-  glob_opt.ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-  if(glob_opt.ssl_ctx == NULL) {
-    PRINT_INFO2("SSL_CTX_new %s", ERR_error_string(ERR_get_error(), NULL));
-    abort();
-  }
-  spdy_ssl_init_ssl_ctx(glob_opt.ssl_ctx, &glob_opt.spdy_proto_version);
-
-  daemon = MHD_start_daemon ( 
-          MHD_SUPPRESS_DATE_NO_CLOCK,
-          glob_opt.listen_port,
-          NULL, NULL, &http_cb_request, NULL,
-          MHD_OPTION_URI_LOG_CALLBACK, &http_cb_log, NULL,
-          MHD_OPTION_NOTIFY_COMPLETED, &http_cb_request_completed, NULL,
-          MHD_OPTION_END);
-  if(NULL==daemon)
-    DIE("MHD_start_daemon failed");
-
-  do
-  {
-    timeout.tv_sec = 0;
-    timeout.tv_usec = 0;
-  
-    if(NULL == glob_opt.spdy_connection && NULL != glob_opt.spdy2http_str)
-    {
-      glob_opt.spdy_connection = spdy_connect(spdy2http_uri, spdy2http_uri->port, strcmp("https", spdy2http_uri->scheme)==0);
-      if(NULL == glob_opt.spdy_connection && glob_opt.only_proxy)
-        PRINT_INFO("cannot connect to the proxy");
-    }
-
-    FD_ZERO(&rs);
-    FD_ZERO(&ws);
-    FD_ZERO(&es);
-
-    ret = MHD_get_timeout(daemon, &timeoutlong);
-    if(MHD_NO == ret || timeoutlong > 5000)
-      timeout.tv_sec = 5;
-    else
-    {
-      timeout.tv_sec = timeoutlong / 1000;
-      timeout.tv_usec = (timeoutlong % 1000) * 1000;
-    }
-    
-    if(MHD_NO == MHD_get_fdset (daemon,
-                                  &rs,
-                                  &ws, 
-                                  &es,
-                                  &maxfd))
-    {
-      PRINT_INFO("MHD_get_fdset error");
-    }
-    assert(-1 != maxfd);
-    
-    maxfd_s = spdy_get_selectfdset(
-                                  &rs,
-                                  &ws, 
-                                  &es,
-                                  connections, MAX_SPDY_CONNECTIONS, &spdy_npollfds);
-    if(maxfd_s > maxfd) 
-      maxfd = maxfd_s;
- 
-    PRINT_INFO2("MHD timeout %lld %lld", (unsigned long long)timeout.tv_sec, (unsigned long long)timeout.tv_usec);
-
-    glob_opt.spdy_data_received = false;
-      
-    ret = select(maxfd+1, &rs, &ws, &es, &timeout);
-    PRINT_INFO2("timeout now %lld %lld ret is %i", (unsigned long long)timeout.tv_sec, (unsigned long long)timeout.tv_usec, ret);
-
-    switch(ret)
-    {
-      case -1:
-        PRINT_INFO2("select error: %i", errno);
-        break;
-      case 0:
-        //break;
-      default:
-      PRINT_INFO("run");
-        //MHD_run_from_select(daemon,&rs, &ws, &es); //not closing FDs at some time in past
-        MHD_run(daemon);
-        spdy_run_select(&rs, &ws, &es, connections, spdy_npollfds);
-        if(glob_opt.spdy_data_received)
-        {
-          PRINT_INFO("MHD run again");
-          //MHD_run_from_select(daemon,&rs, &ws, &es); //not closing FDs at some time in past
-          MHD_run(daemon);
-        }
-        break;
-    }
-  }
-  while(run);
-
-  MHD_stop_daemon (daemon);
-  
-  //TODO SSL_free brakes
-  spdy_free_connection(glob_opt.spdy_connection);
-  
-  connection = glob_opt.spdy_connections_head;
-  while(NULL != connection)
-  {    
-    connection_for_delete = connection;
-    connection = connection_for_delete->next;
-    glob_opt.streams_opened -= connection_for_delete->streams_opened;
-    DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection_for_delete);
-    spdy_free_connection(connection_for_delete);
-  }
-  
-  free_uri(spdy2http_uri);
-  
-  deinit_parse_uri(&glob_opt.uri_preg);
-  
-  SSL_CTX_free(glob_opt.ssl_ctx);
-  ERR_free_strings();
-  EVP_cleanup();
-    
-  PRINT_INFO2("spdy streams: %i; http requests: %i", glob_opt.streams_opened, glob_opt.responses_pending);
-  //PRINT_INFO2("memory allocated %zu bytes", glob_opt.global_memory);
-  
-  print_stat();
-
-  return 0;
-}
-
-
-void
-display_usage()
-{
-  printf(
-    "Usage: mhd2spdy [-ovs] [-b <SPDY2HTTP-PROXY>] -p <PORT>\n\n"
-    "OPTIONS:\n"
-    "    -p, --port            Listening port.\n"
-    "    -b, --backend-proxy   If set, he proxy will send requests to\n"
-    "                          that SPDY server or proxy. Set the address\n"
-    "                          in the form 'http://host:port'. Use 'https'\n"
-    "                          for SPDY over TLS, or 'http' for plain SPDY\n"
-    "                          communication with the backend.\n"
-    "    -o, --only-proxy      If set, the proxy will always forward the\n"
-    "                          requests to the backend proxy. If not set,\n"
-    "                          the proxy will first try to establsh SPDY\n"
-    "                          connection to the requested server. If the\n"
-    "                          server does not support SPDY and TLS, the\n"
-    "                          backend proxy will be used for the request.\n"
-    "    -v, --verbose         Print debug information.\n"
-    "    -s, --statistics      Print simple statistics on exit.\n\n"
-
-  );
-}
-
-
-int
-main (int argc,
-      char *const *argv)
-{   
-  int getopt_ret;
-  int option_index;
-  struct option long_options[] = {
-    {"port",  required_argument, 0, 'p'},
-    {"backend-proxy",  required_argument, 0, 'b'},
-    {"verbose",  no_argument, 0, 'v'},
-    {"only-proxy",  no_argument, 0, 'o'},
-    {"statistics",  no_argument, 0, 's'},
-    {0, 0, 0, 0}
-  };
-  
-  while (1)
-  {
-    getopt_ret = getopt_long( argc, argv, "p:b:vos", long_options, &option_index);
-    if (getopt_ret == -1)
-      break;
-
-    switch(getopt_ret)
-    {
-      case 'p':
-        glob_opt.listen_port = atoi(optarg);
-        break;
-        
-      case 'b':
-        glob_opt.spdy2http_str = strdup(optarg);
-        if(NULL == glob_opt.spdy2http_str)
-          return 1;
-        break;
-        
-      case 'v':
-        glob_opt.verbose = true;
-        break;
-        
-      case 'o':
-        glob_opt.only_proxy = true;
-        break;
-        
-      case 's':
-        glob_opt.statistics = true;
-        break;
-        
-      case 0:
-        PRINT_INFO("0 from getopt");
-        break;
-        
-      case '?':
-        display_usage();
-        return 1;
-        
-      default:
-        DIE("default from getopt");
-    }
-  }
-  
-  if(
-    0 == glob_opt.listen_port
-    || (glob_opt.only_proxy && NULL == glob_opt.spdy2http_str)
-    )
-  {
-    display_usage();
-    return 1;
-  }
-    
-  return run_everything();
-}

+ 0 - 422
src/examples/mhd2spdy_http.c

@@ -1,422 +0,0 @@
-/*
-    Copyright 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 mhd2spdy_http.c
- * @brief  HTTP part of the proxy. libmicrohttpd is used for the server side.
- * @author Andrey Uzunov
- */
- 
-#include "mhd2spdy_structures.h"
-#include "mhd2spdy_http.h"
-#include "mhd2spdy_spdy.h"
-
-
-void *
-http_cb_log(void * cls,
-const char * uri)
-{
-  (void)cls;
-  
-  struct HTTP_URI * http_uri;
-  
-  PRINT_INFO2("log uri '%s'\n", uri);
-  
-  //TODO not freed once in a while
-  if(NULL == (http_uri = au_malloc(sizeof(struct HTTP_URI ))))
-    return NULL;
-  http_uri->uri = strdup(uri);
-  return http_uri;
-}
-
-
-static int
-http_cb_iterate(void *cls,
-                 enum MHD_ValueKind kind,
-                 const char *name,
-                 const char *value)
-{
-  (void)kind;
-  
-  static char * const forbidden[] = {"Transfer-Encoding",
-    "Proxy-Connection",
-    "Keep-Alive",
-    "Connection"};
-  static int forbidden_size = 4;
-  int i;
-	struct SPDY_Headers *spdy_headers = (struct SPDY_Headers *)cls;
-	
-	if(0 == strcasecmp(name, "Host"))
-    spdy_headers->nv[9] = (char *)value;
-  else
-  {
-    for(i=0; i<forbidden_size; ++i)
-      if(0 == strcasecmp(forbidden[i], name))
-        return MHD_YES;
-    spdy_headers->nv[spdy_headers->cnt++] = (char *)name;
-    spdy_headers->nv[spdy_headers->cnt++] = (char *)value;
-  }
-	
-	return MHD_YES;
-}
-
-
-static ssize_t
-http_cb_response (void *cls,
-                        uint64_t pos,
-                        char *buffer,
-                        size_t max)
-{
-  (void)pos;
-  
-	int ret;
-	struct Proxy *proxy = (struct Proxy *)cls;
-	void *newbody;
-  const union MHD_ConnectionInfo *info;
-  int val = 1;
-  
-  PRINT_INFO2("http_cb_response for %s", proxy->url);
-  
-  if(proxy->spdy_error)
-    return MHD_CONTENT_READER_END_WITH_ERROR;
-  
-	if(0 == proxy->http_body_size && (proxy->done || !proxy->spdy_active))
-  {
-    PRINT_INFO("sent end of stream");
-    return MHD_CONTENT_READER_END_OF_STREAM;
-  }
-	
-	if(!proxy->http_body_size)//nothing to write now
-  {
-    //flush data
-    info = MHD_get_connection_info (proxy->http_connection,
-         MHD_CONNECTION_INFO_CONNECTION_FD);
-    ret = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
-    if(ret == -1) {
-      DIE("setsockopt");
-    }
-    
-    PRINT_INFO("FLUSH data");
-		return 0;
-  }
-	
-	if(max >= proxy->http_body_size)
-	{
-		ret = proxy->http_body_size;
-		newbody = NULL;
-	}
-	else
-	{
-		ret = max;
-		if(NULL == (newbody = au_malloc(proxy->http_body_size - max)))
-		{
-			PRINT_INFO("no memory");
-			return MHD_CONTENT_READER_END_WITH_ERROR;
-		}
-		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;
-	}
-	
-	PRINT_INFO2("response_callback, size: %i",ret);
-	
-	return ret;
-}
-
-
-static void
-http_cb_response_done(void *cls)
-{
-  (void)cls;
-  //TODO remove
-}
-
-int
-http_cb_request (void *cls,
-                struct MHD_Connection *connection,
-                const char *url,
-                const char *method,
-                const char *version,
-                const char *upload_data,
-                size_t *upload_data_size,
-                void **ptr)
-{
-  (void)cls;
-  (void)url;
-  (void)upload_data;
-  (void)upload_data_size;
-  
-  int ret;
-  struct Proxy *proxy;
-  struct SPDY_Headers spdy_headers;
-  bool with_body = false;
-  struct HTTP_URI *http_uri;
-  const char *header_value;
-
-  if (NULL == ptr || NULL == *ptr)
-    return MHD_NO;
-    
-  http_uri = (struct HTTP_URI *)*ptr;
-    
-  if(NULL == http_uri->proxy)
-  {
-    //first call for this request
-    if (0 != strcmp (method, MHD_HTTP_METHOD_GET) && 0 != strcmp (method, MHD_HTTP_METHOD_POST))
-    {
-      free(http_uri->uri);
-      free(http_uri);
-      PRINT_INFO2("unexpected method %s", method);
-      return MHD_NO;
-    }
-    
-    if(NULL == (proxy = au_malloc(sizeof(struct Proxy))))
-    {
-      free(http_uri->uri);
-      free(http_uri);
-      PRINT_INFO("No memory");
-      return MHD_NO; 
-    }
-    
-    ++glob_opt.responses_pending;
-    proxy->id = rand();
-    proxy->http_active = true;
-    proxy->http_connection = connection;
-    http_uri->proxy = proxy;
-    return MHD_YES;
-  }
-  
-  proxy = http_uri->proxy;
-  
-  if(proxy->spdy_error || proxy->http_error)
-    return MHD_NO; // handled at different place TODO? leaks?
-
-  if(proxy->spdy_active)
-  {
-    if(0 == strcmp (method, MHD_HTTP_METHOD_POST))
-    {
-      PRINT_INFO("POST processing");
-        
-      int rc= spdylay_session_resume_data(proxy->spdy_connection->session, proxy->stream_id);
-      PRINT_INFO2("rc is %i stream is %i", rc, proxy->stream_id);
-      proxy->spdy_connection->want_io |= WANT_WRITE;
-      
-      if(0 == *upload_data_size)
-      {
-      PRINT_INFO("POST http EOF");
-        proxy->receiving_done = true;
-        return MHD_YES;
-      }
-      
-      if(!copy_buffer(upload_data, *upload_data_size, &proxy->received_body, &proxy->received_body_size))
-      {
-        //TODO handle it better?
-        PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
-        return MHD_NO;
-      }
-      
-      *upload_data_size = 0;
-                               
-      return MHD_YES;
-    }
-  
-    //already handled
-    PRINT_INFO("unnecessary call to http_cb_request");
-    return MHD_YES;
-  }
-  
-  //second call for this request
-
-  PRINT_INFO2("received request for '%s %s %s'", method, http_uri->uri, version);
-
-  proxy->url = http_uri->uri;
-  
-  header_value = MHD_lookup_connection_value(connection,
-    MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
-  
-  with_body = 0 == strcmp (method, MHD_HTTP_METHOD_POST)
-    && (NULL == header_value || 0 != strcmp ("0", header_value));
-    
-  PRINT_INFO2("body will be sent %i", with_body);
-    
-  ret = parse_uri(&glob_opt.uri_preg, proxy->url, &proxy->uri);
-  if(ret != 0)
-    DIE("parse_uri failed");
-  proxy->http_uri = http_uri;
-
-  spdy_headers.num = MHD_get_connection_values (connection,
-                       MHD_HEADER_KIND,
-                       NULL,
-                       NULL);
-  if(NULL == (spdy_headers.nv = au_malloc(((spdy_headers.num + 5) * 2 + 1) * sizeof(char *))))
-    DIE("no memory");
-  spdy_headers.nv[0] = ":method";     spdy_headers.nv[1] = method;
-  spdy_headers.nv[2] = ":path";       spdy_headers.nv[3] = proxy->uri->path_and_more;
-  spdy_headers.nv[4] = ":version";    spdy_headers.nv[5] = (char *)version;
-  spdy_headers.nv[6] = ":scheme";     spdy_headers.nv[7] = proxy->uri->scheme;
-  spdy_headers.nv[8] = ":host";       spdy_headers.nv[9] = NULL;
-  //nv[14] = NULL;
-  spdy_headers.cnt = 10;
-  MHD_get_connection_values (connection,
-                       MHD_HEADER_KIND,
-                       &http_cb_iterate,
-                       &spdy_headers);
-                       
-  spdy_headers.nv[spdy_headers.cnt] = NULL;
-  if(NULL == spdy_headers.nv[9])
-    spdy_headers.nv[9] = proxy->uri->host_and_port;
-
-  if(0 != spdy_request(spdy_headers.nv, proxy, with_body))
-  {
-    free(spdy_headers.nv);
-    //free_proxy(proxy);
-    
-    return MHD_NO;
-  }
-  free(spdy_headers.nv);
-  
-  proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
-                         4096,
-                         &http_cb_response,
-                         proxy,
-                         &http_cb_response_done);
-
-  if (NULL == proxy->http_response)
-    DIE("no response");
-  
-  if(MHD_NO == MHD_add_response_header (proxy->http_response,
-                 "Proxy-Connection", "keep-alive"))
-    PRINT_INFO("SPDY_name_value_add failed: ");
-  if(MHD_NO == MHD_add_response_header (proxy->http_response,
-                 "Connection", "Keep-Alive"))
-    PRINT_INFO("SPDY_name_value_add failed: ");
-  if(MHD_NO == MHD_add_response_header (proxy->http_response,
-                 "Keep-Alive", "timeout=5, max=100"))
-    PRINT_INFO("SPDY_name_value_add failed: ");
-    
-  proxy->spdy_active = true;
-  
-  return MHD_YES;
-}
-
-
-void
-http_create_response(struct Proxy* proxy,
-                     char **nv)
-{
-  size_t i;
-  
-  if(!proxy->http_active)
-    return;
-  
-  for(i = 0; nv[i]; i += 2) {
-    if(0 == strcmp(":status", nv[i]))
-    {
-      char tmp[4];
-      memcpy(&tmp,nv[i+1],3);
-      tmp[3]=0;
-      proxy->status = atoi(tmp);
-      continue;
-    }
-    else if(0 == strcmp(":version", nv[i]))
-    {
-      proxy->version = nv[i+1];
-      continue;
-    }
-    else if(0 == strcmp("content-length", nv[i]))
-    {
-      continue;
-    }
-
-    char *header = *(nv+i);
-    if(MHD_NO == MHD_add_response_header (proxy->http_response,
-                   header, nv[i+1]))
-    {
-      PRINT_INFO2("SPDY_name_value_add failed: '%s' '%s'", header, nv[i+1]);
-    }
-    PRINT_INFO2("adding '%s: %s'",header, nv[i+1]);
-  }
-  
-  if(MHD_NO == MHD_queue_response (proxy->http_connection, proxy->status, proxy->http_response)){
-    PRINT_INFO("No queue");
-    //TODO
-    //abort();
-    proxy->http_error = true;
-  }
-  
-  MHD_destroy_response (proxy->http_response);
-  proxy->http_response = NULL;
-}
-
-void
-http_cb_request_completed (void *cls,
-                                   struct MHD_Connection *connection,
-                                   void **con_cls,
-                                   enum MHD_RequestTerminationCode toe)
-{
-  (void)cls;
-  (void)connection;
-  struct HTTP_URI *http_uri;
-  struct Proxy *proxy;
-  
-  http_uri = (struct HTTP_URI *)*con_cls;
-  if(NULL == http_uri)
-    return;
-  proxy = (struct Proxy *)http_uri->proxy;
-  assert(NULL != proxy);
-  
-  PRINT_INFO2("http_cb_request_completed %i for %s; id %i",toe, http_uri->uri, proxy->id);
-  
-  if(NULL != proxy->http_response)
-  {
-    MHD_destroy_response (proxy->http_response);
-    proxy->http_response = NULL;
-  }
-  
-  if(proxy->spdy_active)
-  {
-    proxy->http_active = false;
-    if(MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
-    {
-      proxy->http_error = true;
-      if(proxy->stream_id > 0 /*&& NULL != proxy->spdy_connection->session*/)
-      {
-        //send RST_STREAM_STATUS_CANCEL
-        PRINT_INFO2("send rst_stream %i %i",proxy->spdy_active, proxy->stream_id );
-        spdylay_submit_rst_stream(proxy->spdy_connection->session, proxy->stream_id, 5);
-      }
-      /*else
-      {
-        DLL_remove(proxy->spdy_connection->proxies_head, proxy->spdy_connection->proxies_tail, proxy); 
-        free_proxy(proxy);
-      }*/
-    }
-  }
-  else
-  {
-    PRINT_INFO2("proxy free http id %i ", proxy->id);
-    free_proxy(proxy);
-  }
-    
-  --glob_opt.responses_pending;
-}

+ 0 - 54
src/examples/mhd2spdy_http.h

@@ -1,54 +0,0 @@
-/*
-    Copyright 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 mhd2spdy_http.h
- * @brief  HTTP part of the proxy. libmicrohttpd is used for the server side.
- * @author Andrey Uzunov
- */
- 
-#ifndef HTTP_H
-#define HTTP_H
-
-#include "mhd2spdy_structures.h"
-
-
-int
-http_cb_request (void *cls,
-                struct MHD_Connection *connection,
-                const char *url,
-                const char *method,
-                const char *version,
-                const char *upload_data,
-                size_t *upload_data_size,
-                void **ptr);
-
-
-void * http_cb_log(void * cls, const char * uri);
-
-
-void
-http_create_response(struct Proxy* proxy, char **nv);
-
-
-void
-http_cb_request_completed (void *cls,
-                                   struct MHD_Connection *connection,
-                                   void **con_cls,
-                                   enum MHD_RequestTerminationCode toe);
-
-#endif

+ 0 - 1150
src/examples/mhd2spdy_spdy.c

@@ -1,1150 +0,0 @@
-/*
- *
- * Copyright (c) 2012 Tatsuhiro Tsujikawa
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * @file mhd2spdy_spdy.c
- * @brief  SPDY part of the proxy. libspdylay is used for the client side.
- *         The example spdycli.c from spdylay was used as basis;
- *         however, multiple changes were made.
- * @author Tatsuhiro Tsujikawa
- * @author Andrey Uzunov
- */
-
-#include "mhd2spdy_structures.h"
-#include "mhd2spdy_spdy.h"
-#include "mhd2spdy_http.h"
-
-
-/*
- * Prints error containing the function name |func| and message |msg|
- * and exit.
- */
-static void
-spdy_dief(const char *func,
-          const char *msg)
-{
-  fprintf(stderr, "FATAL: %s: %s\n", func, msg);
-  exit(EXIT_FAILURE);
-}
-
-
-/*
- * Prints error containing the function name |func| and error code
- * |error_code| and exit.
- */
-void
-spdy_diec(const char *func,
-          int error_code)
-{
-  fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
-          spdylay_strerror(error_code));
-  exit(EXIT_FAILURE);
-}
-
-
-static ssize_t
-spdy_cb_data_source_read(spdylay_session *session, int32_t stream_id, uint8_t *buf, size_t length, int *eof, spdylay_data_source *source, void *user_data)
-{
-  (void)session;
-  (void)stream_id;
-  (void)user_data;
-
-  ssize_t ret;
-  assert(NULL != source);
-  assert(NULL != source->ptr);
-	struct Proxy *proxy = (struct Proxy *)(source->ptr);
-	void *newbody;
-
-
-  if(length < 1)
-  {
-    PRINT_INFO("spdy_cb_data_source_read: length is 0");
-    return 0;
-	}
-
-	if(!proxy->received_body_size)//nothing to write now
-  {
-    if(proxy->receiving_done)
-    {
-      PRINT_INFO("POST spdy EOF");
-      *eof = 1;
-    }
-      PRINT_INFO("POST SPDYLAY_ERR_DEFERRED");
-		return SPDYLAY_ERR_DEFERRED;//TODO SPDYLAY_ERR_DEFERRED should be used
-  }
-
-	if(length >= proxy->received_body_size)
-	{
-		ret = proxy->received_body_size;
-		newbody = NULL;
-	}
-	else
-	{
-		ret = length;
-		if(NULL == (newbody = malloc(proxy->received_body_size - length)))
-		{
-			PRINT_INFO("no memory");
-			return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE;
-		}
-		memcpy(newbody, proxy->received_body + length, proxy->received_body_size - length);
-	}
-	memcpy(buf, proxy->received_body, ret);
-	free(proxy->received_body);
-	proxy->received_body = newbody;
-	proxy->received_body_size -= ret;
-
-  if(0 == proxy->received_body_size && proxy->receiving_done)
-    {
-      PRINT_INFO("POST spdy EOF");
-    *eof = 1;
-  }
-
-  PRINT_INFO2("given POST bytes to spdylay: %zd", ret);
-
-  return ret;
-}
-
-
-/*
- * The implementation of spdylay_send_callback type. Here we write
- * |data| with size |length| to the network and return the number of
- * bytes actually written. See the documentation of
- * spdylay_send_callback for the details.
- */
-static ssize_t
-spdy_cb_send(spdylay_session *session,
-             const uint8_t *data,
-             size_t length,
-             int flags,
-             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  //PRINT_INFO("spdy_cb_send called");
-  struct SPDY_Connection *connection;
-  ssize_t rv;
-  connection = (struct SPDY_Connection*)user_data;
-  connection->want_io = IO_NONE;
-
-  if(glob_opt.ignore_rst_stream
-    && 16 == length
-    && 0x80 == data[0]
-    && 0x00 == data[2]
-    && 0x03 == data[3]
-    )
-  {
-    PRINT_INFO2("ignoring RST_STREAM for stream_id %i %i %i %i", data[8], data[9], data[10], data[11]);
-    glob_opt.ignore_rst_stream = false;
-    return 16;
-  }
-  glob_opt.ignore_rst_stream = false;
-
-  if(connection->is_tls)
-  {
-    ERR_clear_error();
-    rv = SSL_write(connection->ssl, data, length);
-    if(rv < 0) {
-      int err = SSL_get_error(connection->ssl, rv);
-      if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
-        connection->want_io |= (err == SSL_ERROR_WANT_READ ?
-                               WANT_READ : WANT_WRITE);
-        rv = SPDYLAY_ERR_WOULDBLOCK;
-      } else {
-        rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-      }
-    }
-  }
-  else
-  {
-    rv = write(connection->fd,
-            data,
-            length);
-
-    if (rv < 0)
-    {
-      switch(errno)
-      {
-        case EAGAIN:
-  #if EAGAIN != EWOULDBLOCK
-        case EWOULDBLOCK:
-  #endif
-          connection->want_io |= WANT_WRITE;
-          rv = SPDYLAY_ERR_WOULDBLOCK;
-          break;
-
-        default:
-          rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-      }
-    }
-  }
-
-  PRINT_INFO2("%zd bytes written by spdy", rv);
-
-  if(rv > 0)
-    UPDATE_STAT(glob_stat.spdy_bytes_sent, rv);
-
-  return rv;
-}
-
-
-/*
- * The implementation of spdylay_recv_callback type. Here we read data
- * from the network and write them in |buf|. The capacity of |buf| is
- * |length| bytes. Returns the number of bytes stored in |buf|. See
- * the documentation of spdylay_recv_callback for the details.
- */
-static ssize_t
-spdy_cb_recv(spdylay_session *session,
-             uint8_t *buf,
-             size_t length,
-             int flags,
-             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  struct SPDY_Connection *connection;
-  ssize_t rv;
-
-  connection = (struct SPDY_Connection*)user_data;
-  //prevent monopolizing everything
-  if(!(++connection->counter % 10)) return SPDYLAY_ERR_WOULDBLOCK;
-  connection->want_io = IO_NONE;
-  if(connection->is_tls)
-  {
-    ERR_clear_error();
-    rv = SSL_read(connection->ssl, buf, length);
-    if(rv < 0) {
-      int err = SSL_get_error(connection->ssl, rv);
-      if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
-        connection->want_io |= (err == SSL_ERROR_WANT_READ ?
-                               WANT_READ : WANT_WRITE);
-        rv = SPDYLAY_ERR_WOULDBLOCK;
-      } else {
-        rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-      }
-    } else if(rv == 0) {
-      rv = SPDYLAY_ERR_EOF;
-    }
-  }
-  else
-  {
-    rv = read(connection->fd,
-            buf,
-            length);
-
-    if (rv < 0)
-    {
-      switch(errno)
-      {
-        case EAGAIN:
-  #if EAGAIN != EWOULDBLOCK
-        case EWOULDBLOCK:
-  #endif
-          connection->want_io |= WANT_READ;
-          rv = SPDYLAY_ERR_WOULDBLOCK;
-          break;
-
-        default:
-          rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-      }
-    }
-    else if(rv == 0)
-      rv = SPDYLAY_ERR_EOF;
-  }
-
-  if(rv > 0)
-    UPDATE_STAT(glob_stat.spdy_bytes_received, rv);
-
-  return rv;
-}
-
-
-static void
-spdy_cb_before_ctrl_send(spdylay_session *session,
-                    spdylay_frame_type type,
-                    spdylay_frame *frame,
-                    void *user_data)
-{
-  (void)user_data;
-
-  int32_t stream_id;
-  struct Proxy *proxy;
-
-  switch(type) {
-    case SPDYLAY_SYN_STREAM:
-      stream_id = frame->syn_stream.stream_id;
-      proxy = spdylay_session_get_stream_user_data(session, stream_id);
-      proxy->stream_id = stream_id;
-      ++glob_opt.streams_opened;
-      ++proxy->spdy_connection->streams_opened;
-      PRINT_INFO2("opening stream: str open %i; %s", glob_opt.streams_opened, proxy->url);
-      break;
-    case SPDYLAY_RST_STREAM:
-      //try to ignore duplicate RST_STREAMs
-      //TODO this will ignore RST_STREAMs also for bogus data
-      glob_opt.ignore_rst_stream = NULL==spdylay_session_get_stream_user_data(session, frame->rst_stream.stream_id);
-      PRINT_INFO2("sending RST_STREAM for %i; ignore %i; status %i",
-        frame->rst_stream.stream_id,
-        glob_opt.ignore_rst_stream,
-        frame->rst_stream.status_code);
-    break;
-    default:
-      break;
-  }
-}
-
-
-void
-spdy_cb_on_ctrl_recv(spdylay_session *session,
-                    spdylay_frame_type type,
-                    spdylay_frame *frame,
-                    void *user_data)
-{
-  (void)user_data;
-
-  char **nv;
-  int32_t stream_id;
-  struct Proxy * proxy;
-
-  switch(type) {
-    case SPDYLAY_SYN_REPLY:
-      nv = frame->syn_reply.nv;
-      stream_id = frame->syn_reply.stream_id;
-    break;
-    case SPDYLAY_RST_STREAM:
-      stream_id = frame->rst_stream.stream_id;
-    break;
-    case SPDYLAY_HEADERS:
-      nv = frame->headers.nv;
-      stream_id = frame->headers.stream_id;
-    break;
-    default:
-      return;
-    break;
-  }
-
-  proxy = spdylay_session_get_stream_user_data(session, stream_id);
-  if(NULL == proxy)
-  {
-    PRINT_INFO2("received frame type %i for unkonwn stream id %i", type, stream_id);
-    return;
-    //DIE("no proxy obj");
-  }
-
-  switch(type) {
-    case SPDYLAY_SYN_REPLY:
-      PRINT_INFO2("received headers for %s", proxy->url);
-      http_create_response(proxy, nv);
-    break;
-    case SPDYLAY_RST_STREAM:
-      PRINT_INFO2("received reset stream for %s", proxy->url);
-      proxy->spdy_error = true;
-    break;
-    case SPDYLAY_HEADERS:
-      PRINT_INFO2("received headers for %s", proxy->url);
-      http_create_response(proxy, nv);
-    break;
-    default:
-      return;
-    break;
-  }
-
-  glob_opt.spdy_data_received = true;
-}
-
-
-/*
- * The implementation of spdylay_on_stream_close_callback type. We use
- * this function to know the response is fully received. Since we just
- * fetch 1 resource in this program, after reception of the response,
- * we submit GOAWAY and close the session.
- */
-static void
-spdy_cb_on_stream_close(spdylay_session *session,
-                       int32_t stream_id,
-                       spdylay_status_code status_code,
-                       void *user_data)
-{
-  (void)status_code;
-  (void)user_data;
-
-  struct Proxy * proxy = spdylay_session_get_stream_user_data(session, stream_id);
-
-  assert(NULL != proxy);
-
-  --glob_opt.streams_opened;
-  --proxy->spdy_connection->streams_opened;
-  PRINT_INFO2("closing stream: str opened %i; remove proxy %i", glob_opt.streams_opened, proxy->id);
-
-  DLL_remove(proxy->spdy_connection->proxies_head, proxy->spdy_connection->proxies_tail, proxy);
-  if(proxy->http_active)
-  {
-    proxy->spdy_active = false;
-  }
-  else
-  {
-    free_proxy(proxy);
-  }
-}
-
-
-/*
- * The implementation of spdylay_on_data_chunk_recv_callback type. We
- * use this function to print the received response body.
- */
-static void
-spdy_cb_on_data_chunk_recv(spdylay_session *session,
-                          uint8_t flags,
-                          int32_t stream_id,
-                          const uint8_t *data,
-                          size_t len,
-                          void *user_data)
-{
-  (void)flags;
-  (void)user_data;
-
-  struct Proxy *proxy;
-  proxy = spdylay_session_get_stream_user_data(session, stream_id);
-
-  if(NULL == proxy)
-  {
-    PRINT_INFO("proxy in spdy_cb_on_data_chunk_recv is NULL)");
-    return;
-	}
-
-  if(!copy_buffer(data, len, &proxy->http_body, &proxy->http_body_size))
-  {
-    //TODO handle it better?
-    PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
-    return;
-  }
-  /*
-	if(NULL == proxy->http_body)
-		proxy->http_body = au_malloc(len);
-  else
-		proxy->http_body = realloc(proxy->http_body, proxy->http_body_size + len);
-	if(NULL == proxy->http_body)
-	{
-		PRINT_INFO("not enough memory (realloc returned NULL)");
-		return ;
-	}
-
-	memcpy(proxy->http_body + proxy->http_body_size, data, len);
-	proxy->http_body_size += len;
-  */
-  PRINT_INFO2("received data for %s; %zu bytes", proxy->url, len);
-  glob_opt.spdy_data_received = true;
-}
-
-
-static void
-spdy_cb_on_data_recv(spdylay_session *session,
-		                 uint8_t flags,
-                     int32_t stream_id,
-                     int32_t length,
-                     void *user_data)
-{
-  (void)length;
-  (void)user_data;
-
-	if(flags & SPDYLAY_DATA_FLAG_FIN)
-	{
-    struct Proxy *proxy;
-    proxy = spdylay_session_get_stream_user_data(session, stream_id);
-    proxy->done = true;
-    PRINT_INFO2("last data frame received for %s", proxy->url);
-	}
-}
-
-
-/*
- * Setup callback functions. Spdylay API offers many callback
- * functions, but most of them are optional. The send_callback is
- * always required. Since we use spdylay_session_recv(), the
- * recv_callback is also required.
- */
-static void
-spdy_setup_spdylay_callbacks(spdylay_session_callbacks *callbacks)
-{
-  memset(callbacks, 0, sizeof(spdylay_session_callbacks));
-  callbacks->send_callback = spdy_cb_send;
-  callbacks->recv_callback = spdy_cb_recv;
-  callbacks->before_ctrl_send_callback = spdy_cb_before_ctrl_send;
-  callbacks->on_ctrl_recv_callback = spdy_cb_on_ctrl_recv;
-  callbacks->on_stream_close_callback = spdy_cb_on_stream_close;
-  callbacks->on_data_chunk_recv_callback = spdy_cb_on_data_chunk_recv;
-  callbacks->on_data_recv_callback = spdy_cb_on_data_recv;
-}
-
-
-/*
- * Callback function for SSL/TLS NPN. Since this program only supports
- * SPDY protocol, if server does not offer SPDY protocol the Spdylay
- * library supports, we terminate program.
- */
-static int
-spdy_cb_ssl_select_next_proto(SSL* ssl,
-                                unsigned char **out,
-                                unsigned char *outlen,
-                                const unsigned char *in,
-                                unsigned int inlen,
-                                void *arg)
-{
-  (void)ssl;
-
-  int rv;
-  uint16_t *spdy_proto_version;
-
-  /* spdylay_select_next_protocol() selects SPDY protocol version the
-     Spdylay library supports. */
-  rv = spdylay_select_next_protocol(out, outlen, in, inlen);
-  if(rv <= 0) {
-    PRINT_INFO("Server did not advertise spdy/2 or spdy/3 protocol.");
-    return rv;
-  }
-  spdy_proto_version = (uint16_t*)arg;
-  *spdy_proto_version = rv;
-  return SSL_TLSEXT_ERR_OK;
-}
-
-
-/*
- * Setup SSL context. We pass |spdy_proto_version| to get negotiated
- * SPDY protocol version in NPN callback.
- */
-void
-spdy_ssl_init_ssl_ctx(SSL_CTX *ssl_ctx,
-                      uint16_t *spdy_proto_version)
-{
-  /* Disable SSLv2 and enable all workarounds for buggy servers */
-  SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);
-  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
-  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
-  /* Set NPN callback */
-  SSL_CTX_set_next_proto_select_cb(ssl_ctx, spdy_cb_ssl_select_next_proto,
-                                   spdy_proto_version);
-}
-
-
-static int
-spdy_ssl_handshake(SSL *ssl,
-                   int fd)
-{
-  int rv;
-
-  if(SSL_set_fd(ssl, fd) == 0)
-    spdy_dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
-
-  ERR_clear_error();
-  rv = SSL_connect(ssl);
-  if(rv <= 0)
-    PRINT_INFO2("SSL_connect %s", ERR_error_string(ERR_get_error(), NULL));
-
-  return rv;
-}
-
-
-/*
- * Connects to the host |host| and port |port|.  This function returns
- * the file descriptor of the client socket.
- */
-static int
-spdy_socket_connect_to(const char *host,
-                       uint16_t port)
-{
-  struct addrinfo hints;
-  int fd = -1;
-  int rv;
-  char service[NI_MAXSERV];
-  struct addrinfo *res, *rp;
-
-  //TODO checks
-  snprintf(service, sizeof(service), "%u", port);
-  memset(&hints, 0, sizeof(struct addrinfo));
-  hints.ai_family = AF_UNSPEC;
-  hints.ai_socktype = SOCK_STREAM;
-  rv = getaddrinfo(host, service, &hints, &res);
-  if(rv != 0)
-  {
-	  printf("%s\n",host);
-    spdy_dief("getaddrinfo", gai_strerror(rv));
-  }
-  for(rp = res; rp; rp = rp->ai_next)
-  {
-    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-    if(fd == -1)
-      continue;
-    while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
-          errno == EINTR);
-    if(rv == 0)
-      break;
-    MHD_socket_close_ (fd);
-    fd = -1;
-  }
-  freeaddrinfo(res);
-
-  return fd;
-}
-
-
-static void
-spdy_socket_make_non_block(int fd)
-{
-  int flags;
-  int rv;
-
-  while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
-
-  if(flags == -1)
-    spdy_dief("fcntl", strerror(errno));
-
-  while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
-
-  if(rv == -1)
-    spdy_dief("fcntl", strerror(errno));
-}
-
-
-/*
- * Setting TCP_NODELAY is not mandatory for the SPDY protocol.
- */
-static void
-spdy_socket_set_tcp_nodelay(int fd)
-{
-  int val = 1;
-  int rv;
-
-  rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
-  if(rv == -1)
-    spdy_dief("setsockopt", strerror(errno));
-}
-
-/*
- * Update |pollfd| based on the state of |connection|.
- */
- /*
-void
-spdy_ctl_poll(struct pollfd *pollfd,
-              struct SPDY_Connection *connection)
-{
-  pollfd->events = 0;
-  if(spdylay_session_want_read(connection->session) ||
-     connection->want_io & WANT_READ)
-  {
-    pollfd->events |= POLLIN;
-  }
-  if(spdylay_session_want_write(connection->session) ||
-     connection->want_io & WANT_WRITE)
-  {
-    pollfd->events |= POLLOUT;
-  }
-}*/
-
-
-/*
- * Update |selectfd| based on the state of |connection|.
- */
-bool
-spdy_ctl_select(fd_set * read_fd_set,
-                fd_set * write_fd_set,
-                fd_set * except_fd_set,
-                struct SPDY_Connection *connection)
-{
-  (void)except_fd_set;
-
-  bool ret = false;
-
-  if(spdylay_session_want_read(connection->session) ||
-     connection->want_io & WANT_READ)
-  {
-    FD_SET(connection->fd, read_fd_set);
-    ret = true;
-  }
-  if(spdylay_session_want_write(connection->session) ||
-     connection->want_io & WANT_WRITE)
-  {
-    FD_SET(connection->fd, write_fd_set);
-    ret = true;
-  }
-
-  return ret;
-}
-
-
-/*
- * Performs the network I/O.
- */
-int
-spdy_exec_io(struct SPDY_Connection *connection)
-{
-  int rv;
-
-  rv = spdylay_session_recv(connection->session);
-  if(rv != 0)
-  {
-    PRINT_INFO2("spdylay_session_recv %i", rv);
-    return rv;
-  }
-  rv = spdylay_session_send(connection->session);
-  if(rv != 0)
-    PRINT_INFO2("spdylay_session_send %i", rv);
-
-  return rv;
-}
-
-
-/*
- * Fetches the resource denoted by |uri|.
- */
-struct SPDY_Connection *
-spdy_connect(const struct URI *uri,
-             uint16_t port,
-             bool is_tls)
-{
-  spdylay_session_callbacks callbacks;
-  int fd;
-  SSL *ssl=NULL;
-  struct SPDY_Connection * connection = NULL;
-  int rv;
-
-  spdy_setup_spdylay_callbacks(&callbacks);
-
-  /* Establish connection and setup SSL */
-  PRINT_INFO2("connecting to %s:%i", uri->host, port);
-  fd = spdy_socket_connect_to(uri->host, port);
-  if(fd == -1)
-  {
-    PRINT_INFO("Could not open file descriptor");
-    return NULL;
-  }
-
-  if(is_tls)
-  {
-    ssl = SSL_new(glob_opt.ssl_ctx);
-    if(ssl == NULL) {
-      spdy_dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
-    }
-
-    //TODO non-blocking
-    /* To simplify the program, we perform SSL/TLS handshake in blocking
-       I/O. */
-    glob_opt.spdy_proto_version = 0;
-    rv = spdy_ssl_handshake(ssl, fd);
-    if(rv <= 0 || (glob_opt.spdy_proto_version != 3 && glob_opt.spdy_proto_version != 2))
-    {
-      PRINT_INFO("Closing SSL");
-      //no spdy on the other side
-      goto free_and_fail;
-    }
-  }
-  else
-  {
-    glob_opt.spdy_proto_version = 3;
-  }
-
-  if(NULL == (connection = au_malloc(sizeof(struct SPDY_Connection))))
-    goto free_and_fail;
-
-  connection->is_tls = is_tls;
-  connection->ssl = ssl;
-  connection->want_io = IO_NONE;
-  if(NULL == (connection->host = strdup(uri->host)))
-    goto free_and_fail;
-
-  /* Here make file descriptor non-block */
-  spdy_socket_make_non_block(fd);
-  spdy_socket_set_tcp_nodelay(fd);
-
-  PRINT_INFO2("[INFO] SPDY protocol version = %d\n", glob_opt.spdy_proto_version);
-  rv = spdylay_session_client_new(&(connection->session), glob_opt.spdy_proto_version,
-                                  &callbacks, connection);
-  if(rv != 0) {
-    spdy_diec("spdylay_session_client_new", rv);
-  }
-
-  connection->fd = fd;
-
-	return connection;
-
-	//for GOTO
-	free_and_fail:
-  if(NULL != connection)
-  {
-    free(connection->host);
-    free(connection);
-  }
-
-  if(is_tls)
-    SSL_shutdown(ssl);
-
-  MHD_socket_close_ (fd);
-
-  if(is_tls)
-    SSL_free(ssl);
-
-  return NULL;
-}
-
-
-void
-spdy_free_connection(struct SPDY_Connection * connection)
-{
-  struct Proxy *proxy;
-  struct Proxy *proxy_next;
-
-  if(NULL != connection)
-  {
-    for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy_next)
-    {
-      proxy_next = proxy->next;
-      DLL_remove(connection->proxies_head, connection->proxies_tail, proxy);
-      proxy->spdy_active = false;
-      proxy->spdy_error = true;
-      PRINT_INFO2("spdy_free_connection for id %i", proxy->id);
-      if(!proxy->http_active)
-      {
-        free_proxy(proxy);
-      }
-    }
-    spdylay_session_del(connection->session);
-    SSL_free(connection->ssl);
-    free(connection->host);
-    free(connection);
-    //connection->session = NULL;
-  }
-}
-
-
-int
-spdy_request(const char **nv,
-             struct Proxy *proxy,
-             bool with_body)
-{
-  int ret;
-  uint16_t port;
-  struct SPDY_Connection *connection;
-  spdylay_data_provider post_data;
-
-  if(glob_opt.only_proxy)
-  {
-    connection = glob_opt.spdy_connection;
-  }
-  else
-  {
-    connection = glob_opt.spdy_connections_head;
-    while(NULL != connection)
-    {
-      if(0 == strcasecmp(proxy->uri->host, connection->host))
-        break;
-      connection = connection->next;
-    }
-
-    if(NULL == connection)
-    {
-      //connect to host
-      port = proxy->uri->port;
-      if(0 == port) port = 443;
-      connection = spdy_connect(proxy->uri, port, true);
-      if(NULL != connection)
-      {
-        DLL_insert(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection);
-        glob_opt.total_spdy_connections++;
-      }
-      else
-        connection = glob_opt.spdy_connection;
-    }
-  }
-
-  if(NULL == connection)
-  {
-    PRINT_INFO("there is no proxy!");
-    return -1;
-  }
-
-  proxy->spdy_connection = connection;
-  if(with_body)
-  {
-    post_data.source.ptr = proxy;
-    post_data.read_callback = &spdy_cb_data_source_read;
-    ret = spdylay_submit_request(connection->session, 0, nv, &post_data, proxy);
-  }
-  else
-    ret = spdylay_submit_request(connection->session, 0, nv, NULL, proxy);
-
-  if(ret != 0) {
-    spdy_diec("spdylay_spdy_submit_request", ret);
-  }
-  PRINT_INFO2("adding proxy %i", proxy->id);
-  if(NULL != connection->proxies_head)
-    PRINT_INFO2("before proxy %i", connection->proxies_head->id);
-  DLL_insert(connection->proxies_head, connection->proxies_tail, proxy);
-
-  return ret;
-}
-
-/*
-void
-spdy_get_pollfdset(struct pollfd fds[],
-                   struct SPDY_Connection *connections[],
-                   unsigned int max_size,
-                   nfds_t *real_size)
-{
-  struct SPDY_Connection *connection;
-  struct Proxy *proxy;
-
-  *real_size = 0;
-  if(max_size<1)
-    return;
-
-  if(NULL != glob_opt.spdy_connection)
-  {
-    spdy_ctl_poll(&(fds[*real_size]), glob_opt.spdy_connection);
-    if(!fds[*real_size].events)
-    {
-      //PRINT_INFO("TODO drop connection");
-      glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened;
-
-      for(proxy = glob_opt.spdy_connection->proxies_head; NULL != proxy; proxy=proxy->next)
-      {
-        abort();
-        DLL_remove(glob_opt.spdy_connection->proxies_head, glob_opt.spdy_connection->proxies_tail, proxy);
-        proxy->spdy_active = false;
-      }
-      spdy_free_connection(glob_opt.spdy_connection);
-      glob_opt.spdy_connection = NULL;
-    }
-    else
-    {
-      fds[*real_size].fd = glob_opt.spdy_connection->fd;
-      connections[*real_size] = glob_opt.spdy_connection;
-      ++(*real_size);
-    }
-  }
-
-  connection = glob_opt.spdy_connections_head;
-
-  while(NULL != connection && *real_size < max_size)
-  {
-    assert(!glob_opt.only_proxy);
-    spdy_ctl_poll(&(fds[*real_size]), connection);
-    if(!fds[*real_size].events)
-    {
-      //PRINT_INFO("TODO drop connection");
-      glob_opt.streams_opened -= connection->streams_opened;
-      DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection);
-      glob_opt.total_spdy_connections--;
-
-      for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy->next)
-      {
-        abort();
-        DLL_remove(connection->proxies_head, connection->proxies_tail, proxy);
-        proxy->spdy_active = false;
-      }
-      spdy_free_connection(connection);
-    }
-    else
-    {
-      fds[*real_size].fd = connection->fd;
-      connections[*real_size] = connection;
-      ++(*real_size);
-    }
-    connection = connection->next;
-  }
-
-  //, "TODO max num of conn reached; close something"
-  assert(NULL == connection);
-}
-*/
-
-int
-spdy_get_selectfdset(fd_set * read_fd_set,
-                      fd_set * write_fd_set,
-                      fd_set * except_fd_set,
-                      struct SPDY_Connection *connections[],
-                      unsigned int max_size,
-                      nfds_t *real_size)
-{
-  struct SPDY_Connection *connection;
-  struct SPDY_Connection *next_connection;
-  bool ret;
-  int maxfd = 0;
-
-  *real_size = 0;
-  if(max_size<1)
-    return 0;
-
-  if(NULL != glob_opt.spdy_connection)
-  {
-    ret = spdy_ctl_select(read_fd_set,
-				 write_fd_set,
-				 except_fd_set, glob_opt.spdy_connection);
-    if(!ret)
-    {
-      glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened;
-
-      PRINT_INFO("spdy_free_connection in spdy_get_selectfdset");
-      spdy_free_connection(glob_opt.spdy_connection);
-      glob_opt.spdy_connection = NULL;
-    }
-    else
-    {
-      connections[*real_size] = glob_opt.spdy_connection;
-      ++(*real_size);
-      if(maxfd < glob_opt.spdy_connection->fd) maxfd = glob_opt.spdy_connection->fd;
-    }
-  }
-
-  connection = glob_opt.spdy_connections_head;
-
-  while(NULL != connection && *real_size < max_size)
-  {
-    assert(!glob_opt.only_proxy);
-    ret = spdy_ctl_select(read_fd_set,
-				 write_fd_set,
-				 except_fd_set, connection);
-
-    next_connection = connection->next;
-    if(!ret)
-    {
-      glob_opt.streams_opened -= connection->streams_opened;
-      DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection);
-      glob_opt.total_spdy_connections--;
-
-      PRINT_INFO("spdy_free_connection in spdy_get_selectfdset");
-      spdy_free_connection(connection);
-    }
-    else
-    {
-      connections[*real_size] = connection;
-      ++(*real_size);
-      if(maxfd < connection->fd) maxfd = connection->fd;
-    }
-    connection = next_connection;
-  }
-
-  //, "TODO max num of conn reached; close something"
-  assert(NULL == connection);
-
-  return maxfd;
-}
-
-/*
-void
-spdy_run(struct pollfd fds[],
-         struct SPDY_Connection *connections[],
-         int size)
-{
-  int i;
-  int ret;
-  struct Proxy *proxy;
-
-  for(i=0; i<size; ++i)
-  {
-    //  PRINT_INFO2("exec about to be called for %s", connections[i]->host);
-    if(fds[i].revents & (POLLIN | POLLOUT))
-    {
-      ret = spdy_exec_io(connections[i]);
-      //PRINT_INFO2("%i",ret);
-      //if((spdy_pollfds[i].revents & POLLHUP) || (spdy_pollfds[0].revents & POLLERR))
-      //  PRINT_INFO("SPDY SPDY_Connection error");
-
-      //TODO POLLRDHUP
-      // always close on ret != 0?
-
-      if(0 != ret)
-      {
-        glob_opt.streams_opened -= connections[i]->streams_opened;
-        if(connections[i] == glob_opt.spdy_connection)
-        {
-          glob_opt.spdy_connection = NULL;
-        }
-        else
-        {
-          DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]);
-          glob_opt.total_spdy_connections--;
-        }
-        for(proxy = connections[i]->proxies_head; NULL != proxy; proxy=proxy->next)
-        {
-        abort();
-          DLL_remove(connections[i]->proxies_head, connections[i]->proxies_tail, proxy);
-          proxy->spdy_active = false;
-          proxy->spdy_error = true;
-          PRINT_INFO2("spdy_free_connection for id %i", proxy->id);
-        }
-        PRINT_INFO("spdy_free_connection in loop");
-        spdy_free_connection(connections[i]);
-      }
-    }
-    else
-      PRINT_INFO("not called");
-  }
-}
-*/
-
-void
-spdy_run_select(fd_set * read_fd_set,
-                fd_set * write_fd_set,
-                fd_set * except_fd_set,
-                struct SPDY_Connection *connections[],
-                int size)
-{
-  int i;
-  int ret;
-
-  for(i=0; i<size; ++i)
-  {
-    //  PRINT_INFO2("exec about to be called for %s", connections[i]->host);
-    if(FD_ISSET(connections[i]->fd, read_fd_set) || FD_ISSET(connections[i]->fd, write_fd_set) || FD_ISSET(connections[i]->fd, except_fd_set))
-    {
-      //raise(SIGINT);
-      ret = spdy_exec_io(connections[i]);
-
-      if(0 != ret)
-      {
-        glob_opt.streams_opened -= connections[i]->streams_opened;
-        if(connections[i] == glob_opt.spdy_connection)
-        {
-          glob_opt.spdy_connection = NULL;
-        }
-        else
-        {
-          DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]);
-          glob_opt.total_spdy_connections--;
-        }
-        PRINT_INFO("in spdy_run_select");
-        spdy_free_connection(connections[i]);
-      }
-    }
-    else
-    {
-      PRINT_INFO("not called");
-      //PRINT_INFO2("connection->want_io %i",connections[i]->want_io);
-      //PRINT_INFO2("read %i",spdylay_session_want_read(connections[i]->session));
-      //PRINT_INFO2("write %i",spdylay_session_want_write(connections[i]->session));
-      //raise(SIGINT);
-    }
-  }
-}

+ 0 - 102
src/examples/mhd2spdy_spdy.h

@@ -1,102 +0,0 @@
-/*
-    Copyright 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 mhd2spdy_spdy.h
- * @brief  SPDY part of the proxy. libspdylay is used for the client side.
- * @author Andrey Uzunov
- */
- 
-#ifndef SPDY_H
-#define SPDY_H
-
-#include "mhd2spdy_structures.h"
-
-
-struct SPDY_Connection *
-spdy_connect(const struct URI *uri,
-             uint16_t port,
-             bool is_tls);
-
-
-void
-spdy_ctl_poll(struct pollfd *pollfd,
-              struct SPDY_Connection *connection);
-
-
-bool
-spdy_ctl_select(fd_set * read_fd_set,
-                fd_set * write_fd_set, 
-                fd_set * except_fd_set,
-                struct SPDY_Connection *connection);
-
-
-int
-spdy_exec_io(struct SPDY_Connection *connection);
-
-
-void
-spdy_diec(const char *func,
-          int error_code);
-
-
-int 
-spdy_request(const char **nv,
-             struct Proxy *proxy,
-             bool with_body);
-
-
-void
-spdy_ssl_init_ssl_ctx(SSL_CTX *ssl_ctx,
-                      uint16_t *spdy_proto_version);
-
-
-void
-spdy_free_connection(struct SPDY_Connection * connection);
-
-
-void
-spdy_get_pollfdset(struct pollfd fds[],
-                   struct SPDY_Connection *connections[],
-                   unsigned int max_size,
-                   nfds_t *real_size);
-
-
-int
-spdy_get_selectfdset(fd_set * read_fd_set,
-                    fd_set * write_fd_set, 
-                    fd_set * except_fd_set,
-                    struct SPDY_Connection *connections[],
-                    unsigned int max_size,
-                    nfds_t *real_size);
-
-
-void
-spdy_run(struct pollfd fds[],
-        struct SPDY_Connection *connections[],
-        int size);
-
-
-void
-spdy_run_select(fd_set * read_fd_set,
-                fd_set * write_fd_set, 
-                fd_set * except_fd_set,
-                struct SPDY_Connection *connections[],
-                int size);
-
-
-#endif

+ 0 - 162
src/examples/mhd2spdy_structures.c

@@ -1,162 +0,0 @@
-/*
-    Copyright 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 mhd2spdy_structures.h
- * @brief  Common functions, macros.
- * @author Andrey Uzunov
- */
- 
-#include "mhd2spdy_structures.h"
-
-
-void
-free_uri(struct URI * uri)
-{
-  if(NULL != uri)
-  {
-    free(uri->full_uri);
-    free(uri->scheme);
-    free(uri->host_and_port);
-    free(uri->host);
-    free(uri->path);
-    free(uri->path_and_more);
-    free(uri->query);
-    free(uri->fragment);
-    uri->port = 0;
-    free(uri);
-  }
-}
-
-
-int
-init_parse_uri(regex_t * preg)
-{
-  // RFC 2396
-  // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
-      /*
-        scheme    = $2
-      authority = $4
-      path      = $5
-      query     = $7
-      fragment  = $9
-      */
-  
-  return regcomp(preg, "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", REG_EXTENDED);
-}
-
-void
-deinit_parse_uri(regex_t * preg)
-{
-  regfree(preg);
-}
-  
-int
-parse_uri(regex_t * preg,
-          char * full_uri,
-          struct URI ** uri)
-{
-  int ret;
-  char *colon;
-  long long port;
-  size_t nmatch = 10;
-  regmatch_t pmatch[10];
-
-  if (0 != (ret = regexec(preg, full_uri, nmatch, pmatch, 0)))
-    return ret;
-    
-  *uri = au_malloc(sizeof(struct URI));
-  if(NULL == *uri)
-    return -200;
-    
-  (*uri)->full_uri = strdup(full_uri);
-  
-  asprintf(&((*uri)->scheme), "%.*s",pmatch[2].rm_eo - pmatch[2].rm_so, &full_uri[pmatch[2].rm_so]);
-  asprintf(&((*uri)->host_and_port), "%.*s",pmatch[4].rm_eo - pmatch[4].rm_so, &full_uri[pmatch[4].rm_so]);
-  asprintf(&((*uri)->path), "%.*s",pmatch[5].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]);
-  asprintf(&((*uri)->path_and_more), "%.*s",pmatch[9].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]);
-  asprintf(&((*uri)->query), "%.*s",pmatch[7].rm_eo - pmatch[7].rm_so, &full_uri[pmatch[7].rm_so]);
-  asprintf(&((*uri)->fragment), "%.*s",pmatch[9].rm_eo - pmatch[9].rm_so, &full_uri[pmatch[9].rm_so]);
-  
-  colon = strrchr((*uri)->host_and_port, ':');
-  if(NULL == colon)
-  {
-    (*uri)->host = strdup((*uri)->host_and_port);
-    (*uri)->port = 0;
-   
-    return 0;
-  }
-  
-  port = atoi(colon  + 1);
-  if(port<1 || port >= 256 * 256)
-  {
-    free_uri(*uri);
-    return -100;
-  }
-  (*uri)->port = port;
-  asprintf(&((*uri)->host), "%.*s", (int)(colon - (*uri)->host_and_port), (*uri)->host_and_port);
-  
-  return 0;
-}
-
-
-void
-free_proxy(struct Proxy *proxy)
-{
-  PRINT_INFO2("free proxy called for '%s'", proxy->url);
-  if(NULL != proxy->http_body && proxy->http_body_size > 0)
-    UPDATE_STAT(glob_stat.spdy_bytes_received_and_dropped, proxy->http_body_size);
-  free(proxy->http_body);
-  free_uri(proxy->uri);
-	free(proxy->url);
-	free(proxy->http_uri);
-	free(proxy);
-}
-
-
-void *au_malloc(size_t size)
-{
-  void *new_memory;
-  
-  new_memory = malloc(size);
-  if(NULL != new_memory)
-  {
-    glob_opt.global_memory += size;
-    memset(new_memory, 0, size);
-  }
-  return new_memory;
-}
-
-
-bool
-copy_buffer(const void *src, size_t src_size, void **dst, size_t *dst_size)
-{
-  if(0 == src_size)
-    return true;
-  
-  if(NULL == *dst)
-		*dst = malloc(src_size);
-	else
-		*dst = realloc(*dst, src_size + *dst_size);
-	if(NULL == *dst)
-		return false;
-
-	memcpy(*dst + *dst_size, src, src_size);
-	*dst_size += src_size;
-  
-  return true;
-}

+ 0 - 296
src/examples/mhd2spdy_structures.h

@@ -1,296 +0,0 @@
-/*
-    Copyright 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 mhd2spdy_structures.h
- * @brief  Common structures, functions, macros and global variables.
- * @author Andrey Uzunov
- */
-#ifndef STRUCTURES_H
-#define STRUCTURES_H
-
-#define _GNU_SOURCE
- 
-#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 <assert.h>
-#include <microhttpd.h>
-#include <signal.h>
-#include <poll.h>
-#include <fcntl.h>
-#include <regex.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <spdylay/spdylay.h>
-#include <getopt.h>
-
-
-/* WANT_READ if SSL connection needs more input; or WANT_WRITE if it
-   needs more output; or IO_NONE. This is necessary because SSL/TLS
-   re-negotiation is possible at any time. Spdylay API offers
-   similar functions like spdylay_session_want_read() and
-   spdylay_session_want_write() but they do not take into account
-   SSL connection. */
-enum
-{
-  IO_NONE,
-  WANT_READ,
-  WANT_WRITE
-};
-
-
-struct Proxy;
-
-
-struct SPDY_Connection {
-  SSL *ssl;
-  spdylay_session *session;
-  struct SPDY_Connection *prev;
-  struct SPDY_Connection *next;
-  struct Proxy *proxies_head;
-  struct Proxy *proxies_tail;
-  char *host;
-  int fd;
-  int want_io;
-  uint counter;
-  uint streams_opened;
-  bool is_tls;
-};
-
-
-struct URI
-{
-  char * full_uri;
-  char * scheme;
-  char * host_and_port;
-  char * host;
-  char * path;
-  char * path_and_more;
-  char * query;
-  char * fragment;
-  uint16_t port;
-};
-
-
-struct HTTP_URI;
-
-
-struct Proxy
-{
-	struct MHD_Connection *http_connection;
-	struct MHD_Response *http_response;
-	struct URI *uri;
-  struct HTTP_URI *http_uri;
-  struct SPDY_Connection *spdy_connection;
-  struct Proxy *next;
-  struct Proxy *prev;
-	char *url;
-	char *version;
-	void *http_body;
-	void *received_body;
-	size_t http_body_size;
-	size_t received_body_size;
-	ssize_t length;
-	int status;
-	int id;
-  int32_t stream_id;
-	bool done;
-	bool http_error;
-	bool spdy_error;
-  bool http_active;
-  bool spdy_active;
-  bool receiving_done;
-};
-
-
-struct HTTP_URI
-{
-  char * uri;
-  struct Proxy * proxy;
-};
-
-
-struct SPDY_Headers
-{
-  const char **nv;
-  int num;
-  int cnt;
-};
-
-
-struct global_options
-{
-  char *spdy2http_str;
-  struct SPDY_Connection *spdy_connection;
-  struct SPDY_Connection *spdy_connections_head;
-  struct SPDY_Connection *spdy_connections_tail;
-  int streams_opened;
-  int responses_pending;
-  regex_t uri_preg;
-  size_t global_memory;
-  SSL_CTX *ssl_ctx;
-  uint32_t total_spdy_connections;
-  uint16_t spdy_proto_version;
-  uint16_t listen_port;
-  bool verbose;
-  bool only_proxy;
-  bool spdy_data_received;
-  bool statistics;
-  bool ignore_rst_stream;
-}
-glob_opt;
-
-
-struct global_statistics
-{
-  //unsigned long long http_bytes_sent;
-  //unsigned long long http_bytes_received;
-  unsigned long long spdy_bytes_sent;
-  unsigned long long spdy_bytes_received;
-  unsigned long long spdy_bytes_received_and_dropped;
-}
-glob_stat;
-
-
-//forbidden headers
-#define SPDY_HTTP_HEADER_TRANSFER_ENCODING "transfer-encoding"
-#define SPDY_HTTP_HEADER_PROXY_CONNECTION "proxy-connection"
-#define SPDY_HTTP_HEADER_KEEP_ALIVE "keep-alive"
-#define SPDY_HTTP_HEADER_CONNECTION "connection"
-
-#define MAX_SPDY_CONNECTIONS 100
-
-#define SPDY_MAX_OUTLEN 4096
-
-/**
- * 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)
-
-
-#define PRINT_INFO(msg) do{\
-  if(glob_opt.verbose){\
-	printf("%i:%s\n", __LINE__, msg);\
-	fflush(stdout);\
-	}\
-  }\
-	while(0)
-
-
-#define PRINT_INFO2(fmt, ...) do{\
-  if(glob_opt.verbose){\
-	printf("%i\n", __LINE__);\
-	printf(fmt,##__VA_ARGS__);\
-	printf("\n");\
-	fflush(stdout);\
-	}\
-	}\
-	while(0)
-  
-
-#define DIE(msg) do{\
-	printf("FATAL ERROR (line %i): %s\n", __LINE__, msg);\
-	fflush(stdout);\
-  exit(EXIT_FAILURE);\
-	}\
-	while(0)
-  
-  
-#define UPDATE_STAT(stat, value) do{\
-  if(glob_opt.statistics)\
-  {\
-    stat += value;\
-  }\
-  }\
-  while(0)
-
-
-void
-free_uri(struct URI * uri);
-
-
-int
-init_parse_uri(regex_t * preg);
-
-
-void
-deinit_parse_uri(regex_t * preg);
-
-
-int
-parse_uri(regex_t * preg,
-          char * full_uri,
-          struct URI ** uri);
-
-
-void
-free_proxy(struct Proxy *proxy);
-
-
-void *
-au_malloc(size_t size);
-
-
-bool
-copy_buffer(const void *src, size_t src_size, void **dst, size_t *dst_size);
-
-#endif

+ 0 - 487
src/examples/spdy_event_loop.c

@@ -1,487 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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>
-#ifndef MINGW
-#include <arpa/inet.h>
-#endif
-//#include "../framinglayer/structures.h"
-//#include "../applicationlayer/alstructures.h"
-
-static int run = 1;
-
-static int run2 = 1;
-
-	
-static uint64_t loops;
-
-static time_t start;
-
-
-static void
-new_session_callback (void *cls,
-						struct SPDY_Session * session)
-{
-  (void)cls;
-  
-	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));
-		
-	}
-}
-
-
-static void
-session_closed_handler (void *cls,
-						struct SPDY_Session * session,
-						int by_client)
-{
-  (void)cls;
-  (void)session;
-  
-	//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;
-}
-
-
-static 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);
-}
-
-/*
-static 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);
-}
-*/
-
-
-static int
-append_headers_to_data (void *cls,
-                           const char *name, const char * const *value, int num_values)
-{
-	char **data = 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;
-}  
-
-
-static 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,
-            bool more)
-{
-  (void)more;
-  
-	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();
-	}
-}
-
-
-static int
-new_post_data_cb (void * cls,
-					 struct SPDY_Request *request,
-					 const void * buf,
-					 size_t size,
-					 bool more)
-{
-  (void)cls;
-  (void)request;
-  (void)more;
-  
-	printf("DATA:\n===============================\n");
-  write(0, buf, size);
-	printf("\n===============================\n");
-  return SPDY_YES;
-}
-
-
-static void 
-sig_handler(int signo)
-{
-  (void)signo;
-  
-  printf("received signal\n");
-}
-
-
-int
-main (int argc, char *const *argv)
-{	
-	if(argc != 2) return 1;
-	
-	#ifndef MINGW
-	if (signal(SIGPIPE, sig_handler) == SIG_ERR)
-		printf("\ncan't catch SIGPIPE\n");
-	#endif
-	
-	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]),
-	 DATA_DIR "cert-and-key.pem",
-	 DATA_DIR "cert-and-key.pem",
-	&new_session_callback,&session_closed_handler,&standard_request_handler,&new_post_data_cb,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,
-	 DATA_DIR "cert-and-key.pem",
-	 DATA_DIR "cert-and-key.pem",
-	&new_session_callback,NULL,&standard_request_handler,&new_post_data_cb,&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);
-		if(SPDY_NO == ret || timeoutlong > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-    
-		printf("ret=%i; timeoutlong=%llu; sec=%llu; usec=%llu\n", ret, timeoutlong, (long long unsigned)timeout.tv_sec, (long long unsigned)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("%lu loops in %llu secs\n", loops, (long long unsigned)(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;
-}
-

+ 0 - 353
src/examples/spdy_fileserver.c

@@ -1,353 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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
- */
-
-//for asprintf
-#define _GNU_SOURCE
-
-#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 {\
-		unsigned int __len = strlen(fname);\
-		if (__len < 4 || '.' != (fname)[__len - 4]) \
-		{	\
-			(mime) = strdup("application/octet-stream");\
-			printf("MIME for %s is applic...\n", (fname));\
-		}\
-    else {\
-      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);
-
-    if (NULL == buf)
-      return NULL;
-    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;
-	(void)status;
-	//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,
-            bool more)
-{
-	(void)cls;
-	(void)request;
-	(void)priority;
-	(void)host;
-	(void)scheme;
-	(void)headers;
-	(void)method;
-	(void)version;
-	(void)more;
-
-	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%p %i %zd\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, "%zd", 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];
-
-	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 > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-
-		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;
-}
-

+ 0 - 236
src/examples/spdy_response_with_callback.c

@@ -1,236 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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
- */
- 
-//for asprintf
-#define _GNU_SOURCE 
-
-#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"
-
-static int run = 1;
-
-
-static 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;
-}
-
-
-static void
-response_done_callback(void *cls,
-		       struct SPDY_Response *response,
-		       struct SPDY_Request *request,
-		       enum SPDY_RESPONSE_RESULT status,
-		       bool streamopened)
-{
-	(void)streamopened;
-	(void)status;
-  
-	printf("answer for %s was sent\n", (char *)cls);
-	
-	SPDY_destroy_request(request);
-	SPDY_destroy_response(response);
-	free(cls);
-}
-
-
-static 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,
-            bool more)
-{
-	(void)cls;
-	(void)request;
-	(void)priority;
-	(void)host;
-	(void)scheme;
-	(void)headers;
-	(void)more;
-	
-	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(DATA_DIR "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]),
-								DATA_DIR "cert-and-key.pem",
-								DATA_DIR "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;
-	}
-	
-	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 > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-		
-		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;
-}
-

+ 1 - 5
src/include/Makefile.am

@@ -1,10 +1,6 @@
 # This Makefile.am is in the public domain
 SUBDIRS = .
 
-if ENABLE_SPDY
-microspdy = microspdy.h
-endif
-
-include_HEADERS = microhttpd.h $(microspdy)
+include_HEADERS = microhttpd.h 
 
 EXTRA_DIST = platform.h platform_interface.h w32functions.h autoinit_funcs.h

+ 0 - 1380
src/include/microspdy.h

@@ -1,1380 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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.<p>
- *
- * The library does not check if anything at the application layer --
- * requests and responses -- is correct. For example, it
- * is up to the user to check if a client is sending HTTP body but the
- * method is GET.<p>
- *
- * The SPDY flow control is just partially implemented: the receiving
- * window is updated, and the client is notified, to prevent a client
- * from stop sending POST body data, for example.
- */
-#ifndef SPDY_MICROSPDY_H
-#define SPDY_MICROSPDY_H
-
-#include <zlib.h>
-#include <stdbool.h>
-
-/* While we generally would like users to use a configure-driven
-   build process which detects which headers are present and
-   hence works on any platform, we use "standard" includes here
-   to build out-of-the-box for beginning users on common systems.
-
-   Once you have a proper build system and go for more exotic
-   platforms, you should define MHD_PLATFORM_H in some header that
-   you always include *before* "microhttpd.h".  Then the following
-   "standard" includes won't be used (which might be a good
-   idea, especially on platforms where they do not exist). */
-#ifndef MHD_PLATFORM_H
-#include <unistd.h>
-#include <stdarg.h>
-#include <stdint.h>
-#ifdef __MINGW32__
-#include <ws2tcpip.h>
-#else
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#endif
-#endif
-
-#ifndef _MHD_EXTERN
-#define _MHD_EXTERN extern
-#endif
-
-/**
- * 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 IO sybsystem flags used by SPDY_init() and SPDY_deinit().<p>
- *
- * The values are used internally as flags, that is why they must be
- * powers of 2.
- */
-enum SPDY_IO_SUBSYSTEM
-{
-
-  /**
-   * No subsystem. For internal use.
-   */
-  SPDY_IO_SUBSYSTEM_NONE = 0,
-
-  /**
-   * Default TLS implementation provided by openSSL/libssl.
-   */
-  SPDY_IO_SUBSYSTEM_OPENSSL = 1,
-
-  /**
-   * No TLS is used.
-   */
-  SPDY_IO_SUBSYSTEM_RAW = 2
-};
-
-
-/**
- * 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,
-
-  /**
-   * IO subsystem type used by daemon and all its sessions. If not set,
-   * TLS provided by openssl is used. Must be followed by a
-   * SPDY_IO_SUBSYSTEM value.
-   */
-  SPDY_DAEMON_OPTION_IO_SUBSYSTEM = 8,
-
-  /**
-   * Maximum number of frames to be written to the socket at once. The
-   * library tries to send max_num_frames in a single call to SPDY_run
-   * for a single session. This means no requests can be received nor
-   * other sessions can send data as long the current one has enough
-   * frames to send and there is no error on writing. Thus, a big value
-   * will affect the performance. Small value gives fairnes for sessions.
-   * Must be followed by a positive integer (uin32_t). If not set, the
-   * default value 10 will be used.
-   */
-  SPDY_DAEMON_OPTION_MAX_NUM_FRAMES = 16
-};
-
-
-/**
- * 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,
-
-  /**
-   * All sessions' sockets will be set with TCP_NODELAY if the flag is
-   * used. Option considered only by SPDY_IO_SUBSYSTEM_RAW.
-   */
-  SPDY_DAEMON_FLAG_NO_DELAY = 2
-};
-
-
-/**
- * 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. The functions is called whenever
- * a reqest comes, but will also be called if more headers/trailers are
- * received.
- *
- * @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
- * @param more a flag saying if more data related to the request is
- *        expected to be received. HTTP body may arrive (e.g. POST data);
- *        then SPDY_NewDataCallback will be called for the connection.
- *        It is also possible that more headers/trailers arrive;
- *        then the same callback will be invoked. The user should detect
- *        that it is not the first invocation of the function for that
- *        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,
-                            bool more);
-
-
-/**
- * Callback for received new data chunk (HTTP body) from a given
- * request (e.g. POST data).
- *
- * @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. Note that it
- *             may be 0.
- * @param more false if this is the last chunk from the 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_NewDataCallback) (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.
- *
- * @param io_subsystem the IO subsystem that will
- *        be initialized. Several can be used with bitwise OR. If no
- *        parameter is set, the default openssl subsystem will be used.
- * @return #SPDY_YES if the library was correctly initialized and its
- * 			functions can be used now;
- * 			#SPDY_NO on error
- */
-_MHD_EXTERN int
-(SPDY_init) (enum SPDY_IO_SUBSYSTEM io_subsystem, ...);
-#define SPDY_init() SPDY_init (SPDY_IO_SUBSYSTEM_OPENSSL)
-
-
-/**
- * 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.
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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 body (POST data) is 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
- */
-_MHD_EXTERN 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_NewDataCallback 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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 milliseconds)
- * @return #SPDY_YES on success
- *         #SPDY_NO if no connections exist that
- * 			would necessiate the use of a timeout right now
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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 handler to the new empty structure or NULL on error
- */
-_MHD_EXTERN struct SPDY_NameValue *
-SPDY_name_value_create (void);
-
-
-/**
- * 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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 @a iterator
- * @return number of entries iterated over
- */
-_MHD_EXTERN 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.
- *
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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 @a data. It can be 0, then the lib will send only
- * 				headers
- * @return NULL on error, handle to response object on success
- */
-_MHD_EXTERN 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 @a 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
- */
-_MHD_EXTERN 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 @a rrcb
- * @return #SPDY_NO on error or #SPDY_YES on success
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN const struct SPDY_Settings *
-SPDY_settings_create (void);
-
-
-/**
- * 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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
- */
-_MHD_EXTERN 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 @a rttcb
- * @return #SPDY_NO on error or #SPDY_YES on success
- */
-_MHD_EXTERN int
-SPDY_send_ping (struct SPDY_Session *session,
-                SPDY_PingCallback rttcb,
-                void *rttcb_cls);
-
-#endif

+ 0 - 40
src/microspdy/Makefile.am

@@ -1,40 +0,0 @@
-# This Makefile.am is in the public domain
-AM_CPPFLAGS = \
-  -I$(top_srcdir)/src/include \
-  -I$(top_srcdir)/src/microspdy
-
-AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS)
-
-
-lib_LTLIBRARIES = \
-  libmicrospdy.la
-
-libmicrospdy_la_SOURCES = \
-  io.h io.c \
-  io_openssl.h io_openssl.c \
-  io_raw.h io_raw.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_LIBADD = \
-  $(SPDY_LIBDEPS)
-
-libmicrospdy_la_LDFLAGS = \
-  $(SPDY_LIB_LDFLAGS)
-
-libmicrospdy_la_CPPFLAGS = \
-  $(AM_CPPFLAGS) $(SPDY_LIB_CPPFLAGS) \
-  -DBUILDING_MHD_LIB=1
-
-libmicrospdy_la_CFLAGS = -Wextra \
-  $(AM_CFLAGS) $(SPDY_LIB_CFLAGS)
-
-
-if USE_COVERAGE
-  AM_CFLAGS += --coverage
-endif

+ 0 - 41
src/microspdy/alstructures.c

@@ -1,41 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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);
-}

+ 0 - 79
src/microspdy/alstructures.h

@@ -1,79 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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

+ 0 - 748
src/microspdy/applicationlayer.c

@@ -1,748 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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"
-
-
-void
-spdy_callback_response_done(void *cls,
-						struct SPDY_Response *response,
-						struct SPDY_Request *request,
-						enum SPDY_RESPONSE_RESULT status,
-						bool streamopened)
-{
-	(void)cls;
-	(void)status;
-	(void)streamopened;
-  
-	SPDY_destroy_request(request);
-	SPDY_destroy_response(response);
-}
-
-
-/**
- * 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;
-	unsigned int 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]))
-        {
-          SPDY_destroy_request(request);
-					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,
-            !stream->is_in_closed);
-            
-  stream->cls = request;
-
-	return SPDY_YES;
-
-	//for GOTO
-	free_and_fail:
-	
-	SPDY_name_value_destroy(headers);
-	return SPDY_NO;
-}
-
-
-/**
- * TODO
- */
-static int
-spdy_handler_new_data (void * cls,
-					 struct SPDYF_Stream *stream,
-					 const void * buf,
-					 size_t size,
-					 bool more)
-{
-  return stream->session->daemon->received_data_cb(cls, stream->cls, buf, size, more);
-}
-
-
-
-/**
- * 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) (enum SPDY_IO_SUBSYSTEM io_subsystem, ...)
-{
-	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_ASSERT(SPDY_IO_SUBSYSTEM_NONE == spdyf_io_initialized,
-		"SPDY_init must be called only once per program or after SPDY_deinit");
-    
-  if(SPDY_IO_SUBSYSTEM_OPENSSL & io_subsystem)
-  {
-    SPDYF_openssl_global_init();
-    spdyf_io_initialized |= SPDY_IO_SUBSYSTEM_OPENSSL;
-  }
-  else if(SPDY_IO_SUBSYSTEM_RAW & io_subsystem)
-  {
-    SPDYF_raw_global_init();
-    spdyf_io_initialized |= SPDY_IO_SUBSYSTEM_RAW;
-  }
-  
-	SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE != spdyf_io_initialized,
-		"SPDY_init could not find even one IO subsystem");
-    
-	return SPDY_YES;
-}
-
-
-void
-SPDY_deinit ()
-{
-	SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE != spdyf_io_initialized,
-		"SPDY_init has not been called!");
-    
-  if(SPDY_IO_SUBSYSTEM_OPENSSL & spdyf_io_initialized)
-    SPDYF_openssl_global_deinit();
-  else if(SPDY_IO_SUBSYSTEM_RAW & spdyf_io_initialized)
-    SPDYF_raw_global_deinit();
-  
-  spdyf_io_initialized = SPDY_IO_SUBSYSTEM_NONE;
-}
-
-
-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_NewDataCallback npdcb,
-		     void * cls,
-		     ...)
-{
-	struct SPDY_Daemon *daemon;
-	va_list valist;
-	
-	if(SPDY_IO_SUBSYSTEM_NONE == spdyf_io_initialized)
-	{
-		SPDYF_DEBUG("library not initialized");
-		return NULL;
-	}
-  /*
-   * for now make this checks in framing layer
-	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,
-		      &spdy_handler_new_data,
-		      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; //TODO maybe array in stack is enough
-	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 && !SPDYF_name_value_is_empty(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);
-  all_headers = NULL;
-	
-	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;
-}

+ 0 - 31
src/microspdy/applicationlayer.h

@@ -1,31 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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

+ 0 - 441
src/microspdy/compression.c

@@ -1,441 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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;
-	unsigned int 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;
-}

+ 0 - 117
src/microspdy/compression.h

@@ -1,117 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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

+ 0 - 544
src/microspdy/daemon.c

@@ -1,544 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 microspdy/daemon.c
- * @brief  daemon functionality
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "structures.h"
-#include "internal.h"
-#include "session.h"
-#include "io.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) * 1000;
-				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;
-			case SPDY_DAEMON_OPTION_IO_SUBSYSTEM:
-				daemon->io_subsystem = va_arg (valist, enum SPDY_IO_SUBSYSTEM);
-				break;
-			case SPDY_DAEMON_OPTION_MAX_NUM_FRAMES:
-				daemon->max_num_frames = va_arg (valist, uint32_t);
-				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_NewDataCallback npdcb,
-					SPDYF_NewStreamCallback fnscb,
-					SPDYF_NewDataCallback fndcb,
-					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(SPDY_YES != spdyf_parse_options_va (daemon, valist))
-	{
-		SPDYF_DEBUG("parse");
-		goto free_and_fail;
-	}
-
-  if(0 == daemon->max_num_frames)
-    daemon->max_num_frames = SPDYF_NUM_SENT_FRAMES_AT_ONCE;
-
-	if(!port && NULL == daemon->address)
-	{
-		SPDYF_DEBUG("Port is 0");
-		goto free_and_fail;
-	}
-  if(0 == daemon->io_subsystem)
-    daemon->io_subsystem = SPDY_IO_SUBSYSTEM_OPENSSL;
-
-  if(SPDY_YES != SPDYF_io_set_daemon(daemon, daemon->io_subsystem))
-		goto free_and_fail;
-
-  if(SPDY_IO_SUBSYSTEM_RAW != daemon->io_subsystem)
-  {
-    if (NULL == certfile
-      || NULL == (daemon->certfile = strdup (certfile)))
-    {
-      SPDYF_DEBUG("strdup (certfile)");
-      goto free_and_fail;
-    }
-    if (NULL == keyfile
-      || NULL == (daemon->keyfile = strdup (keyfile)))
-    {
-      SPDYF_DEBUG("strdup (keyfile)");
-      goto free_and_fail;
-    }
-  }
-
-	daemon->new_session_cb = nscb;
-	daemon->session_closed_cb = sccb;
-	daemon->new_request_cb = nrcb;
-	daemon->received_data_cb = npdcb;
-	daemon->cls = cls;
-	daemon->fcls = fcls;
-	daemon->fnew_stream_cb = fnscb;
-	daemon->freceived_data_cb = fndcb;
-
-#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;
-	}
-
-  addrlen = sizeof (struct sockaddr_in6);
-
-	if(NULL == daemon->address)
-	{
-		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;
-	}
-
-  if(AF_INET6 == daemon->address->sa_family)
-  {
-    afamily = PF_INET6;
-  }
-  else
-  {
-    afamily = 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;
-	}
-
-  addrlen = sizeof (struct sockaddr_in);
-
-	if(NULL == daemon->address)
-	{
-		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 != daemon->fio_init(daemon))
-	{
-		SPDYF_DEBUG("tls");
-		goto free_and_fail;
-	}
-
-	return daemon;
-
-	//for GOTO
-	free_and_fail:
-	if(daemon->socket_fd > 0)
-		(void)MHD_socket_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)
-{
-	daemon->fio_deinit(daemon);
-
-	shutdown (daemon->socket_fd, SHUT_RDWR);
-	spdyf_close_all_sessions (daemon);
-	(void)MHD_socket_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)
-{
-	unsigned long long earliest_deadline = 0;
-	unsigned long long 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 == pos->fio_is_pending(pos))
-		{
-			earliest_deadline = 0;
-			break;
-		}
-	}
-
-	if (!have_timeout)
-		return SPDY_NO;
-	if (earliest_deadline <= now)
-		*timeout = 0;
-	else
-		*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 == pos->fio_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) || pos->fio_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);
-}

+ 0 - 130
src/microspdy/daemon.h

@@ -1,130 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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"
-
-
-/**
- * Global flags containing the initialized IO subsystems.
- */
-enum SPDY_IO_SUBSYSTEM spdyf_io_initialized;
-
-
-/**
- * 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 fndcb callback called when new data -- within a data frame --
- *        is received by the server
- * @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_NewDataCallback npdcb,
-					SPDYF_NewStreamCallback fnscb,
-					SPDYF_NewDataCallback fndcb,
-					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 milliseconds)
- * @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

+ 0 - 40
src/microspdy/internal.c

@@ -1,40 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 microspdy/internal.c
- * @brief  internal functions and macros for the framing layer
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "structures.h"
-
-
-unsigned long long
-SPDYF_monotonic_time (void)
-{
-#ifdef HAVE_CLOCK_GETTIME
-#ifdef CLOCK_MONOTONIC
-  struct timespec ts;
-  if (0 == clock_gettime (CLOCK_MONOTONIC, &ts))
-    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
-#endif
-#endif
-  return time (NULL) * 1000;
-}

+ 0 - 199
src/microspdy/internal.h

@@ -1,199 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 microspdy/internal.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 "platform_interface.h"
-#include "microspdy.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
-
-/**
- * initial size of window for each stream (this is for the data
- * within data frames that can be handled)
- */
-#define SPDYF_INITIAL_WINDOW_SIZE 65536
-
-/**
- * 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 expr (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 milliseconds
- */
-unsigned long long
-SPDYF_monotonic_time(void);
-
-#endif

+ 0 - 90
src/microspdy/io.c

@@ -1,90 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 io.c
- * @brief Generic functions for IO.
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "structures.h"
-#include "internal.h"
-#include "io.h"
-
-
-int
-SPDYF_io_set_daemon(struct SPDY_Daemon *daemon,
-                    enum SPDY_IO_SUBSYSTEM io_subsystem)
-{
-  switch(io_subsystem)
-  {
-    case SPDY_IO_SUBSYSTEM_OPENSSL:
-      daemon->fio_init = &SPDYF_openssl_init;
-      daemon->fio_deinit = &SPDYF_openssl_deinit;
-      break;
-      
-    case SPDY_IO_SUBSYSTEM_RAW:
-      daemon->fio_init = &SPDYF_raw_init;
-      daemon->fio_deinit = &SPDYF_raw_deinit;
-      break;
-      
-    case SPDY_IO_SUBSYSTEM_NONE:
-    default:
-      SPDYF_DEBUG("Unsupported subsystem");
-      return SPDY_NO;
-  }
-  
-  return SPDY_YES;
-}
-
-
-int
-SPDYF_io_set_session(struct SPDY_Session *session,
-                     enum SPDY_IO_SUBSYSTEM io_subsystem)
-{
-  switch(io_subsystem)
-  {
-    case SPDY_IO_SUBSYSTEM_OPENSSL:
-      session->fio_new_session = &SPDYF_openssl_new_session;
-      session->fio_close_session = &SPDYF_openssl_close_session;
-      session->fio_is_pending = &SPDYF_openssl_is_pending;
-      session->fio_recv = &SPDYF_openssl_recv;
-      session->fio_send = &SPDYF_openssl_send;
-      session->fio_before_write = &SPDYF_openssl_before_write;
-      session->fio_after_write = &SPDYF_openssl_after_write;
-      break;
-      
-    case SPDY_IO_SUBSYSTEM_RAW:
-      session->fio_new_session = &SPDYF_raw_new_session;
-      session->fio_close_session = &SPDYF_raw_close_session;
-      session->fio_is_pending = &SPDYF_raw_is_pending;
-      session->fio_recv = &SPDYF_raw_recv;
-      session->fio_send = &SPDYF_raw_send;
-      session->fio_before_write = &SPDYF_raw_before_write;
-      session->fio_after_write = &SPDYF_raw_after_write;
-      break;
-      
-    case SPDY_IO_SUBSYSTEM_NONE:
-    default:
-      SPDYF_DEBUG("Unsupported subsystem");
-      return SPDY_NO;
-  }
-  
-  return SPDY_YES;
-}

+ 0 - 216
src/microspdy/io.h

@@ -1,216 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 io.h
- * @brief  Signatures for IO functions.
- * @author Andrey Uzunov
- */
-
-#ifndef IO_H
-#define IO_H
-
-#include "platform.h"
-#include "io_openssl.h"
-#include "io_raw.h"
-
-
-/**
- * Used for return code when reading and writing to the TLS socket.
- */
-enum SPDY_IO_ERROR
-{
-	/**
-	 * The connection was closed by the other party.
-	 */
-	SPDY_IO_ERROR_CLOSED = 0,
-	
-	/**
-	 * Any kind of error ocurred. The session has to be closed.
-	 */
-	SPDY_IO_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_IO_ERROR_AGAIN = -3,
-};
-
-
-/**
- * Global initializing. Must be called only once in the program.
- *
- */
-typedef void
-(*SPDYF_IOGlobalInit) ();
-
-
-/**
- * Global deinitializing for the whole program. Should be called
- * at the end of the program.
- *
- */
-typedef void
-(*SPDYF_IOGlobalDeinit) ();
-
-
-/**
- * Initializing of io context for a specific daemon.
- * Must be called when the daemon starts.
- *
- * @param daemon SPDY_Daemon for which io will be used. Daemon's
- * 				certificate and key file are used for tls.
- * @return SPDY_YES on success or SPDY_NO on error
- */
-typedef int
-(*SPDYF_IOInit) (struct SPDY_Daemon *daemon);
-
-
-/**
- * Deinitializing io context for a daemon. Should be called
- * when the deamon is stopped.
- *
- * @param daemon SPDY_Daemon which is being stopped
- */
-typedef void
-(*SPDYF_IODeinit) (struct SPDY_Daemon *daemon);
-
-
-/**
- * Initializing io for a specific connection. Must be called
- * after the connection has been accepted.
- *
- * @param session SPDY_Session whose socket will be used
- * @return SPDY_NO if some funcs inside fail. SPDY_YES otherwise
- */
-typedef int
-(*SPDYF_IONewSession) (struct SPDY_Session *session);
-
-
-/**
- * Deinitializing io for a specific connection. Should be called
- * closing session's socket.
- *
- * @param session SPDY_Session whose socket is used
- */
-typedef void
-(*SPDYF_IOCloseSession) (struct SPDY_Session *session);
-
-
-/**
- * Reading from session's 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 connection
- *         0 if the other party has closed the connection
- *         SPDY_IO_ERROR code on error
- */
-typedef int
-(*SPDYF_IORecv) (struct SPDY_Session *session,
-				void * buffer,
-				size_t size);
-
-
-/**
- * Writing to session's socket. Writes the data given into the buffer to the
- *  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 connection
- *         0 if the other party has closed the connection
- *         SPDY_IO_ERROR code on error
- */
-typedef int
-(*SPDYF_IOSend) (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. In case of TLS, this will call
- * something like SSL_pending().
- *
- * @param session which is checked
- * @return SPDY_YES if data is pending or SPDY_NO otherwise
- */
-typedef int
-(*SPDYF_IOIsPending) (struct SPDY_Session *session);
-
-
-/**
- * Called just before frames are about to be processed and written
- * to the socket.
- *
- * @param session
- * @return SPDY_NO if writing must not happen in the call;
- *         SPDY_YES otherwise
- */
-typedef int
-(*SPDYF_IOBeforeWrite) (struct SPDY_Session *session);
-
-
-/**
- * Called just after frames have been processed and written
- * to the socket.
- *
- * @param session
- * @param was_written has the same value as the write function for the
- *        session will return 
- * @return returned value will be used by the write function to return
- */
-typedef int
-(*SPDYF_IOAfterWrite) (struct SPDY_Session *session,
-                       int was_written);
-
-
-/**
- * Sets callbacks for the daemon with regard to the IO subsystem.
- *
- * @param daemon
- * @param io_subsystem the IO subsystem that will
- *        be initialized and used by daemon.
- * @return SPDY_YES on success or SPDY_NO otherwise
- */
-int
-SPDYF_io_set_daemon(struct SPDY_Daemon *daemon,
-                    enum SPDY_IO_SUBSYSTEM io_subsystem);
-
-
-/**
- * Sets callbacks for the session with regard to the IO subsystem.
- *
- * @param session
- * @param io_subsystem the IO subsystem that will
- *        be initialized and used by session.
- * @return SPDY_YES on success or SPDY_NO otherwise
- */
-int
-SPDYF_io_set_session(struct SPDY_Session *session,
-                     enum SPDY_IO_SUBSYSTEM io_subsystem);
-
-#endif

+ 0 - 280
src/microspdy/io_openssl.c

@@ -1,280 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 io_openssl.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 "io_openssl.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_openssl_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_openssl_global_deinit()
-{
-	//if SSL_load_error_strings was called
-    //ERR_free_strings();
-    //if OpenSSL_add_all_algorithms was called
-    //EVP_cleanup();
-}
-
-
-int
-SPDYF_openssl_init(struct SPDY_Daemon *daemon)
-{
-    int options;
-    //create ssl context. TLSv1 used
-    if(NULL == (daemon->io_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->io_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
-    options = SSL_OP_NO_TICKET;
-#ifdef SSL_OP_NO_COMPRESSION
-    options |= SSL_OP_NO_COMPRESSION;
-#elif OPENSSL_VERSION_NUMBER >= 0x00908000L /* workaround for OpenSSL 0.9.8 */
-    sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
-#endif
-
-    SSL_CTX_set_options(daemon->io_context, options);
-    if(1 != SSL_CTX_use_certificate_file(daemon->io_context, daemon->certfile , SSL_FILETYPE_PEM))
-    {
-		SPDYF_DEBUG("Couldn't load the cert file");
-		SSL_CTX_free(daemon->io_context);
-		return SPDY_NO;
-	}
-    if(1 != SSL_CTX_use_PrivateKey_file(daemon->io_context, daemon->keyfile, SSL_FILETYPE_PEM))
-    {
-		SPDYF_DEBUG("Couldn't load the name file");
-		SSL_CTX_free(daemon->io_context);
-		return SPDY_NO;
-	}
-    SSL_CTX_set_next_protos_advertised_cb(daemon->io_context, &spdyf_next_protos_advertised_cb, NULL);
-    if (1 != SSL_CTX_set_cipher_list(daemon->io_context, "HIGH"))
-    {
-		SPDYF_DEBUG("Couldn't set the desired cipher list");
-		SSL_CTX_free(daemon->io_context);
-		return SPDY_NO;
-	}
-
-	return SPDY_YES;
-}
-
-
-void
-SPDYF_openssl_deinit(struct SPDY_Daemon *daemon)
-{
-    SSL_CTX_free(daemon->io_context);
-}
-
-
-int
-SPDYF_openssl_new_session(struct SPDY_Session *session)
-{
-	int ret;
-
-	if(NULL == (session->io_context = SSL_new(session->daemon->io_context)))
-    {
-		SPDYF_DEBUG("Couldn't create ssl structure");
-		return SPDY_NO;
-	}
-	if(1 != (ret = SSL_set_fd(session->io_context, session->socket_fd)))
-    {
-		SPDYF_DEBUG("SSL_set_fd %i",ret);
-		SSL_free(session->io_context);
-		session->io_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->io_context)))
-    {
-		SPDYF_DEBUG("SSL_accept %i",ret);
-		SSL_free(session->io_context);
-		session->io_context = NULL;
-		return SPDY_NO;
-	}
-	/* alternatively
-	SSL_set_accept_state(session->io_context);
-	* may be called and then the negotiation will be done on reading
-	*/
-
-	return SPDY_YES;
-}
-
-
-void
-SPDYF_openssl_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->io_context);
-
-	SSL_free(session->io_context);
-}
-
-
-int
-SPDYF_openssl_recv(struct SPDY_Session *session,
-				void * buffer,
-				size_t size)
-{
-	int ret;
-	int n = SSL_read(session->io_context,
-					buffer,
-					size);
-	//if(n > 0) SPDYF_DEBUG("recvd: %i",n);
-	if (n <= 0)
-	{
-		ret = SSL_get_error(session->io_context, n);
-		switch(ret)
-		{
-			case SSL_ERROR_ZERO_RETURN:
-				return 0;
-
-			case SSL_ERROR_WANT_READ:
-			case SSL_ERROR_WANT_WRITE:
-				return SPDY_IO_ERROR_AGAIN;
-
-			case SSL_ERROR_SYSCALL:
-				if(EINTR == errno)
-					return SPDY_IO_ERROR_AGAIN;
-				return SPDY_IO_ERROR_ERROR;
-			default:
-				return SPDY_IO_ERROR_ERROR;
-		}
-	}
-
-	return n;
-}
-
-
-int
-SPDYF_openssl_send(struct SPDY_Session *session,
-				const void * buffer,
-				size_t size)
-{
-	int ret;
-
-	int n = SSL_write(session->io_context,
-					buffer,
-					size);
-	//if(n > 0) SPDYF_DEBUG("sent: %i",n);
-	if (n <= 0)
-	{
-		ret = SSL_get_error(session->io_context, n);
-		switch(ret)
-		{
-			case SSL_ERROR_ZERO_RETURN:
-				return 0;
-
-			case SSL_ERROR_WANT_READ:
-			case SSL_ERROR_WANT_WRITE:
-				return SPDY_IO_ERROR_AGAIN;
-
-			case SSL_ERROR_SYSCALL:
-				if(EINTR == errno)
-					return SPDY_IO_ERROR_AGAIN;
-				return SPDY_IO_ERROR_ERROR;
-			default:
-				return SPDY_IO_ERROR_ERROR;
-		}
-	}
-
-	return n;
-}
-
-
-int
-SPDYF_openssl_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->io_context) > 0 ? SPDY_YES : SPDY_NO;
-}
-
-
-int
-SPDYF_openssl_before_write(struct SPDY_Session *session)
-{
-  (void)session;
-
-  return SPDY_YES;
-}
-
-
-int
-SPDYF_openssl_after_write(struct SPDY_Session *session, int was_written)
-{
-  (void)session;
-
-  return was_written;
-}

+ 0 - 166
src/microspdy/io_openssl.h

@@ -1,166 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 io_openssl.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 IO_OPENSSL_H
-#define IO_OPENSSL_H
-
-#include "platform.h"
-#include "io.h"
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <openssl/rand.h>
-
-
-/**
- * Global initializing of openssl. Must be called only once in the program.
- *
- */
-void
-SPDYF_openssl_global_init();
-
-
-/**
- * Global deinitializing of openssl for the whole program. Should be called
- * at the end of the program.
- *
- */
-void
-SPDYF_openssl_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_openssl_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_openssl_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_openssl_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_openssl_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_IO_ERROR code on error
- */
-int
-SPDYF_openssl_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_IO_ERROR code on error
- */
-int
-SPDYF_openssl_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_openssl_is_pending(struct SPDY_Session *session);
-
-
-/**
- * Nothing.
- *
- * @param session
- * @return SPDY_NO if writing must not happen in the call;
- *         SPDY_YES otherwise
- */
-int
-SPDYF_openssl_before_write(struct SPDY_Session *session);
-
-
-/**
- * Nothing.
- *
- * @param session
- * @param was_written has the same value as the write function for the
- *        session will return 
- * @return returned value will be used by the write function to return
- */
-int
-SPDYF_openssl_after_write(struct SPDY_Session *session, int was_written);
-
-
-#endif

+ 0 - 194
src/microspdy/io_raw.c

@@ -1,194 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 io_raw.c
- * @brief  IO for SPDY without TLS.
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "internal.h"
-#include "session.h"
-#include "io_raw.h"
-//TODO put in in the right place
-#include <netinet/tcp.h>
-
-
-void
-SPDYF_raw_global_init()
-{
-}
-
-
-void
-SPDYF_raw_global_deinit()
-{
-}
-
-
-int
-SPDYF_raw_init(struct SPDY_Daemon *daemon)
-{
-  (void)daemon;
-  
-	return SPDY_YES;
-}
-
-
-void
-SPDYF_raw_deinit(struct SPDY_Daemon *daemon)
-{
-  (void)daemon;
-}
-
-
-int
-SPDYF_raw_new_session(struct SPDY_Session *session)
-{	
-  int fd_flags;
-  int val = 1;
-  int ret;
-  
-	//setting the socket to be non-blocking
-	fd_flags = fcntl (session->socket_fd, F_GETFL);
-	if ( -1 == fd_flags
-		|| 0 != fcntl (session->socket_fd, F_SETFL, fd_flags | O_NONBLOCK))
-		SPDYF_DEBUG("WARNING: Couldn't set the new connection to be non-blocking");
-  
-  if(SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)
-  {
-    ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
-    if(-1 == ret)
-      SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_NODELAY");
-  }
-  
-	return SPDY_YES;
-}
-
-
-void
-SPDYF_raw_close_session(struct SPDY_Session *session)
-{
-  (void)session;
-}
-
-
-int
-SPDYF_raw_recv(struct SPDY_Session *session,
-				void * buffer,
-				size_t size)
-{
-	int n = read(session->socket_fd, 
-					buffer,
-					size);
-	//if(n > 0) SPDYF_DEBUG("recvd: %i",n);
-	if (n < 0)
-	{
-		switch(errno)
-		{				
-			case EAGAIN:
-#if EAGAIN != EWOULDBLOCK
-      case EWOULDBLOCK:
-#endif
-			case EINTR:
-        return SPDY_IO_ERROR_AGAIN;
-				
-			default:
-				return SPDY_IO_ERROR_ERROR;
-		}
-	}
-
-	return n;
-}
-
-
-int
-SPDYF_raw_send(struct SPDY_Session *session,
-				const void * buffer,
-				size_t size)
-{
-	int n = write(session->socket_fd, 
-					buffer,
-					size);
-	//if(n > 0) SPDYF_DEBUG("sent: %i",n);
-	if (n < 0)
-	{
-		switch(errno)
-		{				
-			case EAGAIN:
-#if EAGAIN != EWOULDBLOCK
-      case EWOULDBLOCK:
-#endif
-			case EINTR:
-        return SPDY_IO_ERROR_AGAIN;
-				
-			default:
-				return SPDY_IO_ERROR_ERROR;
-		}
-	}
-	
-	return n;
-}
-
-
-int
-SPDYF_raw_is_pending(struct SPDY_Session *session)
-{
-  (void)session;
-  
-	return SPDY_NO;
-}
-
-
-int
-SPDYF_raw_before_write(struct SPDY_Session *session)
-{
-#if HAVE_DECL_TCP_CORK
-  if(0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags))
-  {
-    int val = 1;
-    int ret;
-    
-    ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_CORK, &val, (socklen_t)sizeof(val));
-    if(-1 == ret)
-      SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_CORK");
-  }
-#endif
-  
-	return SPDY_YES;
-}
-
-
-int
-SPDYF_raw_after_write(struct SPDY_Session *session, int was_written)
-{
-#if HAVE_DECL_TCP_CORK
-  if(SPDY_YES == was_written && 0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags))
-  {
-    int val = 0;
-    int ret;
-    
-    ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_CORK, &val, (socklen_t)sizeof(val));
-    if(-1 == ret)
-      SPDYF_DEBUG("WARNING: Couldn't unset the new connection to TCP_CORK");
-  }
-  
-#endif
-	return was_written;
-}

+ 0 - 158
src/microspdy/io_raw.h

@@ -1,158 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 io_raw.h
- * @brief  IO for SPDY without TLS.
- * @author Andrey Uzunov
- */
-
-#ifndef IO_RAW_H
-#define IO_RAW_H
-
-#include "platform.h"
-
-
-/**
- * Must be called only once in the program.
- *
- */
-void
-SPDYF_raw_global_init();
-
-
-/**
- * Should be called
- * at the end of the program.
- *
- */
-void
-SPDYF_raw_global_deinit();
-
-
-/**
- * Must be called when the daemon starts.
- *
- * @param daemon SPDY_Daemon 
- * @return SPDY_YES on success or SPDY_NO on error
- */
-int
-SPDYF_raw_init(struct SPDY_Daemon *daemon);
-
-
-/**
- * Should be called
- * when the deamon is stopped.
- *
- * @param daemon SPDY_Daemon which is being stopped
- */
-void
-SPDYF_raw_deinit(struct SPDY_Daemon *daemon);
-
-
-/**
- * Must be called
- * after the connection has been accepted.
- *
- * @param session SPDY_Session whose socket will be used
- * @return SPDY_NO if some funcs fail. SPDY_YES otherwise
- */
-int
-SPDYF_raw_new_session(struct SPDY_Session *session);
-
-
-/**
- * Should be called
- * closing session's socket.
- *
- * @param session SPDY_Session whose socket is used
- */
-void
-SPDYF_raw_close_session(struct SPDY_Session *session);
-
-
-/**
- * Reading from 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 connection
- *         0 if the other party has closed the connection
- *         SPDY_IO_ERROR code on error
- */
-int
-SPDYF_raw_recv(struct SPDY_Session *session,
-				void * buffer,
-				size_t size);
-
-
-/**
- * Writing to socket. Writes the data given into the buffer to the
- * 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 connection
- *         0 if the other party has closed the connection
- *         SPDY_IO_ERROR code on error
- */
-int
-SPDYF_raw_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. Always returns SPDY_NO, as we do not
- * use a subsystem here.
- *
- * @param session which is checked
- * @return SPDY_YES if data is pending or SPDY_NO otherwise
- */
-int
-SPDYF_raw_is_pending(struct SPDY_Session *session);
-
-
-/**
- * Sets TCP_CORK.
- *
- * @param session
- * @return SPDY_NO if writing must not happen in the call;
- *         SPDY_YES otherwise
- */
-int
-SPDYF_raw_before_write(struct SPDY_Session *session);
-
-
-/**
- * Unsets TCP_CORK.
- *
- * @param session
- * @param was_written has the same value as the write function for the
- *        session will return 
- * @return returned value will be used by the write function to return
- */
-int
-SPDYF_raw_after_write(struct SPDY_Session *session, int was_written);
-
-#endif

+ 0 - 1769
src/microspdy/session.c

@@ -1,1769 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 "stream.h"
-#include "io.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;
-  unsigned int 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->streams_head,
-                                              SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR))
-        {
-          //no memory, try later to send RST
-          free(name_value_strm);
-          return;
-        }
-    }
-  else
-    {
-      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;
-    }
-
-  //SPDYF_DEBUG("syn_stream received: id %i", session->current_stream_id);
-
-  //change state to wait for new frame
-  free(name_value_strm);
-  session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
-  free(frame);
-}
-
-
-/**
- * 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;
-		}
-
-    //SPDYF_DEBUG("goaway received: status %i", status);
-	}
-
-	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; //for debug
-	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); //for debug
-	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)
-{
-  int ret;
-  struct SPDYF_Data_Frame * frame;
-  struct SPDYF_Stream * stream;
-
-	SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status
-		|| SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status,
-		"the function is called wrong");
-
-  //SPDYF_DEBUG("DATA frame received (POST?). Ignoring");
-
-  //SPDYF_SIGINT("");
-
-	frame = (struct SPDYF_Data_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)
-	{
-    stream = SPDYF_stream_find(frame->stream_id, session);
-
-    if(NULL == stream || stream->is_in_closed || NULL == session->daemon->received_data_cb)
-    {
-      if(NULL == session->daemon->received_data_cb)
-      SPDYF_DEBUG("No callback for DATA frame set; Ignoring DATA frame!");
-
-      //TODO send error?
-
-      //TODO for now ignore frame
-      session->read_buffer_beginning += frame->length;
-      session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
-      free(frame);
-      return;
-    }
-
-    ret = session->daemon->freceived_data_cb(session->daemon->cls,
-                                      stream,
-                                      session->read_buffer + session->read_buffer_beginning,
-                                      frame->length,
-                                      0 == (SPDY_DATA_FLAG_FIN & frame->flags));
-
-    session->read_buffer_beginning += frame->length;
-
-    stream->window_size -= frame->length;
-
-    //TODO close in and send rst maybe
-    SPDYF_ASSERT(SPDY_YES == ret, "Cancel POST data is not yet implemented");
-
-    if(SPDY_DATA_FLAG_FIN & frame->flags)
-    {
-      stream->is_in_closed = true;
-    }
-    else if(stream->window_size < SPDYF_INITIAL_WINDOW_SIZE / 2)
-    {
-      //very simple implementation of flow control
-      //when the window's size is under the half of the initial value,
-      //increase it again up to the initial value
-
-      //prepare WINDOW_UPDATE
-      if(SPDY_YES == SPDYF_prepare_window_update(session, stream,
-            SPDYF_INITIAL_WINDOW_SIZE - stream->window_size))
-      {
-        stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
-      }
-      //else: do it later
-    }
-
-    //SPDYF_DEBUG("data received: id %i", frame->stream_id);
-
-    session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER;
-    free(frame);
-	}
-}
-
-
-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;
-
-  //SPDYF_DEBUG("syn_reply sent: id %i", 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_DEBUG("goaway sent: status %i", NTOH31(*(uint32_t*)(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)
-		{
-			free(session->write_buffer);
-      session->write_buffer = NULL;
-
-      //send RST_STREAM
-      if(SPDY_YES == (ret = SPDYF_prepare_rst_stream(session,
-        response_queue->stream,
-        SPDY_RST_STREAM_STATUS_INTERNAL_ERROR)))
-      {
-        return SPDY_NO;
-      }
-
-      //else no memory
-			//for now close session
-			//TODO what?
-			session->status = SPDY_SESSION_STATUS_CLOSING;
-
-			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);
-        session->write_buffer = NULL;
-				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_DEBUG("data sent: id %i", NTOH31(data_frame.stream_id));
-
-	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_DEBUG("rst_stream sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32));
-
-	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_window_update (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; // delta-window-size 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 WINDOW_UPDATE
-	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 and delta-window-size to write buffer
-	memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8);
-	session->write_buffer_offset +=  8;
-
-  //SPDYF_DEBUG("window_update sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32));
-
-	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 = session->fio_recv(session,
-					session->read_buffer + session->read_buffer_offset,
-					session->read_buffer_size - session->read_buffer_offset);
-
-	switch(bytes_read)
-	{
-		case SPDY_IO_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_IO_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_IO_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)
-{
-	unsigned 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;
-
-  if(SPDY_NO == session->fio_before_write(session))
-    return SPDY_NO;
-
-	for(i=0;
-		only_one_frame
-		? i < 1
-		: i < session->max_num_frames;
-		++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
-        ++i;
-				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
-          ++i;
-					break;
-				}
-      }
-		}
-
-		session->last_activity = SPDYF_monotonic_time();
-
-		//actual write to the IO
-		bytes_written = session->fio_send(session,
-			session->write_buffer + session->write_buffer_beginning,
-			session->write_buffer_offset - session->write_buffer_beginning);
-
-		switch(bytes_written)
-		{
-			case SPDY_IO_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_IO_ERROR_ERROR:
-				//any kind of error in the TLS subsystem
-				//forbid more writing
-				session->status = SPDY_SESSION_STATUS_CLOSING;
-				return SPDY_YES;
-
-			case SPDY_IO_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_on_write(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;
-	return session->fio_after_write(session, 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);
-				SPDYF_DATA_FRAME_NTOH(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 > 0 ? session->streams_head : NULL, //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
-	session->fio_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 ret;
-	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;
-
-	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;
-  session->max_num_frames = daemon->max_num_frames;
-
-  ret = SPDYF_io_set_session(session, daemon->io_subsystem);
-  SPDYF_ASSERT(SPDY_YES == ret, "Somehow daemon->io_subsystem iswrong here");
-
-	//init TLS context, handshake will be done
-	if(SPDY_YES != session->fio_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)))
-    {
-		session->fio_close_session(session);
-		goto free_and_fail;
-	}
-
-	//address of the client
-	if (NULL == (session->addr = malloc (addr_len)))
-    {
-		session->fio_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))
-    {
-		session->fio_close_session(session);
-		goto free_and_fail;
-	}
-	if(SPDY_YES != SPDYF_zlib_inflate_init(&session->zlib_recv_stream))
-    {
-		session->fio_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);
-	(void)MHD_socket_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;
-
-	(void)MHD_socket_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,
-					struct SPDYF_Stream * stream,
-					enum SPDY_RST_STREAM_STATUS status)
-{
-	struct SPDYF_Response_Queue *response_to_queue;
-	struct SPDYF_Control_Frame *control_frame;
-	uint32_t *data;
-	uint32_t stream_id;
-
-  if(NULL == stream)
-    stream_id = 0;
-  else
-    stream_id = stream->stream_id;
-
-	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;
-	response_to_queue->stream = stream;
-
-	SPDYF_queue_response (response_to_queue,
-						session,
-						-1);
-
-	return SPDY_YES;
-}
-
-
-int
-SPDYF_prepare_window_update (struct SPDY_Session *session,
-					struct SPDYF_Stream * stream,
-					int32_t delta_window_size)
-{
-	struct SPDYF_Response_Queue *response_to_queue;
-	struct SPDYF_Control_Frame *control_frame;
-	uint32_t *data;
-
-  SPDYF_ASSERT(NULL != stream, "stream cannot be NULL");
-
-	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->stream_id);
-	*(data + 1) = HTON31(delta_window_size);
-
-	control_frame->control_bit = 1;
-	control_frame->version = SPDY_VERSION;
-	control_frame->type = SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE;
-	control_frame->flags = 0;
-
-	response_to_queue->control_frame = control_frame;
-	response_to_queue->process_response_handler = &SPDYF_handler_write_window_update;
-	response_to_queue->data = data;
-	response_to_queue->data_size = 8;
-	response_to_queue->stream = stream;
-
-	SPDYF_queue_response (response_to_queue,
-						session,
-						-1);
-
-	return SPDY_YES;
-}

+ 0 - 281
src/microspdy/session.h

@@ -1,281 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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.
- * @param only_one_frame when true, the function will write at most one
- *        SPDY frame to the underlying IO subsystem;
- *        when false, the function will write up to
- *        session->max_num_frames SPDY frames
- * @return SPDY_YES if the session's internal writing state has changed:
- *         something was written and/or session's status was
- *         changed and/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. 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 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,
-					struct SPDYF_Stream * stream,
-					enum SPDY_RST_STREAM_STATUS status);
-
-
-/**
- * Prepares WINDOW_UPDATE frame to tell the other party that more
- * data can be sent on the stream. The frame will be put at the head of
- * the queue.
- * 
- * @param session SPDY session
- * @param stream stream to which the changed window will apply
- * @param delta_window_size how much the window grows
- * @return SPDY_NO on memory error or
- * 			SPDY_YES on success
- */
-int
-SPDYF_prepare_window_update (struct SPDY_Session *session,
-					struct SPDYF_Stream * stream,
-					int32_t delta_window_size);
-          
-
-/**
- * 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);
-
-
-/**
- * Handler called by session_write to fill the write buffer based on the
- * control frame (WINDOW_UPDATE) 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_window_update (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

+ 0 - 169
src/microspdy/stream.c

@@ -1,169 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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;
-	stream->window_size = SPDYF_INITIAL_WINDOW_SIZE;
-	
-	//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_on_write(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;
-				
-		}
-	}
-}
-
-
-//TODO add function *on_read
-
-
-struct SPDYF_Stream * 
-SPDYF_stream_find(uint32_t stream_id, struct SPDY_Session * session)
-{
-  struct SPDYF_Stream * stream = session->streams_head;
-  
-  while(NULL != stream && stream_id != stream->stream_id)
-  {
-    stream = stream->next;
-  }
-  
-  return stream;
-}

+ 0 - 76
src/microspdy/stream.h

@@ -1,76 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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_on_write(struct SPDYF_Response_Queue *response_queue);
-
-
-/**
- * Find and return a session's stream, based on stream's ID.
- *
- * @param stream_id to search for
- * @param session whose streams are considered
- * @return SPDY_Stream with the desired ID. Can be NULL.
- */
-struct SPDYF_Stream * 
-SPDYF_stream_find(uint32_t stream_id, struct SPDY_Session * session);
-
-#endif

+ 0 - 638
src/microspdy/structures.c

@@ -1,638 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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"
-//TODO not for here?
-#include <ctype.h>
-
-
-int
-SPDYF_name_value_is_empty(struct SPDY_NameValue *container)
-{
-  SPDYF_ASSERT(NULL != container, "NULL is not an empty container!");
-  return (NULL == container->name && NULL == container->value) ? SPDY_YES : SPDY_NO;
-}
-
-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)
-{
-	unsigned int i;
-	unsigned int len;
-	struct SPDY_NameValue *pair;
-	struct SPDY_NameValue *temp;
-	char **temp_value;
-	char *temp_string;
-
-	if(NULL == container || NULL == name || NULL == value || 0 == (len = strlen(name)))
-		return SPDY_INPUT_ERROR;
-  //TODO there is old code handling value==NULL
-  //update it to handle strlen(value)==0
-
-	for(i=0; i<len; ++i)
-	{
-	  if(isupper((int) name[i]))
-			return SPDY_INPUT_ERROR;
-	}
-
-	if(SPDYF_name_value_is_empty(container))
-	{
-		//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 == value)
-      container->value[0] = NULL;
-		else */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 == value)
-      pair->value[0] = NULL;
-		else */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(SPDYF_name_value_is_empty(container))
-		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)
-{
-	unsigned int 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(SPDYF_name_value_is_empty(container))
-		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)
-{
-  if(NULL == response)
-    return;
-	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;
-	unsigned int 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);
-}
-
-
-/* Needed by testcase to be extern -- should this be
-   in the header? */
-_MHD_EXTERN 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;
-	unsigned int i;
-	unsigned int offset;
-	unsigned int 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)
-      {
-        //if(NULL == iterator->value[i])
-        //  continue;
-        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;
-        }
-        //else if(NULL != iterator->value[i])
-        //{
-          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;
-}
-
-
-/* Needed by testcase to be extern -- should this be
-   in the header? */
-_MHD_EXTERN 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;
-	unsigned int offset = 0;
-	unsigned int 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;
-}

+ 0 - 1246
src/microspdy/structures.h

@@ -1,1246 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 "io.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 received new data chunk.
- *
- * @param cls client-defined closure
- * @param stream handler
- * @param buf data chunk from the data
- * @param size the size of the data chunk 'buf' in bytes
- * @param more false if this is the last frame received on this stream. 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 stream
- */
-typedef int
-(*SPDYF_NewDataCallback) (void * cls,
-					 struct SPDYF_Stream *stream,
-					 const void * buf,
-					 size_t size,
-					 bool more);
-           
-           
-/**
- * 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.
-	*/
-	unsigned int 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;
-	
-	/**
-	 * Any object to be used by the application layer.
-	 */
-	void *cls;
-  
-	/**
-	 * This stream's ID.
-	 */
-	uint32_t stream_id;
-	
-	/**
-	 * Stream to which this one is associated.
-	 */
-	uint32_t assoc_stream_id;
-	
-	/**
-	 * The window of the data within data frames.
-	 */
-	uint32_t window_size;
-	
-	/**
-	 * 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 IO context for the session. Initialized on each creation
-	 * (actually when the TCP connection is established).
-	 */
-	void *io_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;
-
-	/**
-	 * Function to initialize the IO context for a new session.
-	 */
-	SPDYF_IONewSession fio_new_session;
-
-	/**
-	 * Function to deinitialize the IO context for a session.
-	 */
-	SPDYF_IOCloseSession fio_close_session;
-
-	/**
-	 * Function to read data from socket.
-	 */
-	SPDYF_IORecv fio_recv;
-
-	/**
-	 * Function to write data to socket.
-	 */
-	SPDYF_IOSend fio_send;
-
-	/**
-	 * Function to check for pending data in IO buffers.
-	 */
-	SPDYF_IOIsPending fio_is_pending;
-
-	/**
-	 * Function to call before writing set of frames.
-	 */
-	SPDYF_IOBeforeWrite fio_before_write;
-
-	/**
-	 * Function to call after writing set of frames.
-	 */
-	SPDYF_IOAfterWrite fio_after_write;
-
-	/**
-	 * 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). In milliseconds.
-	 */
-	unsigned long long 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;
-	
-	/**
-	 * Maximum number of frames to be written to the socket at once. The
-   * library tries to send max_num_frames in a single call to SPDY_run
-   * for a single session. This means no requests can be received nor
-   * other sessions can send data as long the current one has enough
-   * frames to send and there is no error on writing.
-	 */
-	uint32_t max_num_frames;
-
-	/**
-	 * 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 IO context for the daemon. Initialized on daemon start.
-	 */
-	void *io_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. To be used by the application layer
-	*/
-	SPDY_NewDataCallback received_data_cb;
-
-	/**
-	* Callback called when DATA frame is received.
-	*/
-	SPDYF_NewDataCallback freceived_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;
-
-	/**
-	 * Function to initialize the IO context for the daemon.
-	 */
-	SPDYF_IOInit fio_init;
-
-	/**
-	 * Function to deinitialize the IO context for the daemon.
-	 */
-	SPDYF_IODeinit fio_deinit;
-
-	/**
-	 * After how many milliseconds of inactivity should
-	 * connections time out? Zero for no timeout.
-	 */
-	unsigned long long session_timeout;
-
-	/**
-	 * Listen socket.
-	 */
-	int socket_fd;
-	
-	/**
-   * This value is inherited by all sessions of the daemon.
-	 * Maximum number of frames to be written to the socket at once. The
-   * library tries to send max_num_frames in a single call to SPDY_run
-   * for a single session. This means no requests can be received nor
-   * other sessions can send data as long the current one has enough
-   * frames to send and there is no error on writing.
-	 */
-	uint32_t max_num_frames;
-
-	/**
-	 * Daemon's options.
-	 */
-	enum SPDY_DAEMON_OPTION options;
-
-	/**
-	 * Daemon's flags.
-	 */
-	enum SPDY_DAEMON_FLAG flags;
-
-	/**
-	 * IO subsystem type used by daemon and all its sessions.
-	 */
-	enum SPDY_IO_SUBSYSTEM io_subsystem;
-
-	/**
-	 * 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);
-
-
-/**
- * Checks if the container is empty, i.e. created but no values were
- * added to it.
- *
- * @param container
- * @return SPDY_YES if empty
- *         SPDY_NO if not
- */
-int
-SPDYF_name_value_is_empty(struct SPDY_NameValue *container);
-
-
-/**
- * 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

+ 0 - 29
src/spdy2http/Makefile.am

@@ -1,29 +0,0 @@
-# This Makefile.am is in the public domain
-SUBDIRS  = .
-
-AM_CFLAGS =
-
-if USE_COVERAGE
-  AM_CFLAGS += -fprofile-arcs -ftest-coverage
-endif
-
-AM_CPPFLAGS = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/src/include \
- -I$(top_srcdir)/src/applicationlayer \
- -DDATA_DIR=\"$(top_srcdir)/src/datadir/\" \
- $(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 \
- -lz \
- $(LIBCURL)

+ 0 - 1411
src/spdy2http/proxy.c

@@ -1,1411 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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.
- * 			No error handling for curl requests.
- *      TODO:
- * - test all options!
- * - don't abort on lack of memory
- * - Correct recapitalizetion of header names before giving the headers
- * to curl.
- * - curl does not close sockets when connection is closed and no
- * new sockets are opened (they stay in CLOSE_WAIT)
- * - add '/' when a user requests http://example.com . Now this is a bad
- * request
- * - curl returns 0 or 1 ms for timeout even when nothing will be done;
- * thus the loop uses CPU for nothing
- * @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>
-#include <getopt.h>
-#include <regex.h>
-
-#define ERROR_RESPONSE "502 Bad Gateway"
-
-
-struct global_options
-{
-  char *http_backend;
-  char *cert;
-  char *cert_key;
-  char *listen_host;
-  unsigned int timeout;
-  uint16_t listen_port;
-  bool verbose;
-  bool curl_verbose;
-  bool transparent;
-  bool http10;
-  bool notls;
-  bool nodelay;
-  bool ipv4;
-  bool ipv6;
-} glob_opt;
-
-
-struct URI
-{
-  char * full_uri;
-  char * scheme;
-  char * host_and_port;
-  //char * host_and_port_for_connecting;
-  char * host;
-  char * path;
-  char * path_and_more;
-  char * query;
-  char * fragment;
-  uint16_t port;
-};
-
-
-#define PRINT_INFO(msg) do{\
-	fprintf(stdout, "%i:%s\n", __LINE__, msg);\
-	fflush(stdout);\
-	}\
-	while(0)
-
-
-#define PRINT_INFO2(fmt, ...) do{\
-	fprintf(stdout, "%i\n", __LINE__);\
-	fprintf(stdout, fmt,##__VA_ARGS__);\
-	fprintf(stdout, "\n");\
-	fflush(stdout);\
-	}\
-	while(0)
-
-
-#define PRINT_VERBOSE(msg) do{\
-  if(glob_opt.verbose){\
-	fprintf(stdout, "%i:%s\n", __LINE__, msg);\
-	fflush(stdout);\
-	}\
-  }\
-	while(0)
-
-
-#define PRINT_VERBOSE2(fmt, ...) do{\
-  if(glob_opt.verbose){\
-	fprintf(stdout, "%i\n", __LINE__);\
-	fprintf(stdout, fmt,##__VA_ARGS__);\
-	fprintf(stdout, "\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)
-
-
-#define DIE(msg) do{\
-	printf("FATAL ERROR (line %i): %s\n", __LINE__, msg);\
-	fflush(stdout);\
-  exit(EXIT_FAILURE);\
-	}\
-	while(0)
-
-
-static int loop = 1;
-
-static CURLM *multi_handle;
-
-static int still_running = 0; /* keep number of running handles */
-
-static regex_t uri_preg;
-
-static bool call_spdy_run;
-static bool call_curl_run;
-
-int debug_num_curls;
-
-
-struct Proxy
-{
-	char *url;
-	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;
-	void *received_body;
-  bool *session_alive;
-	size_t http_body_size;
-	size_t received_body_size;
-	//ssize_t length;
-	int status;
-  //bool done;
-  bool receiving_done;
-  bool is_curl_read_paused;
-  bool is_with_body_data;
-  //bool error;
-  bool curl_done;
-  bool curl_error;
-  bool spdy_done;
-  bool spdy_error;
-};
-
-
-static void
-free_uri(struct URI * uri)
-{
-  if(NULL != uri)
-  {
-    free(uri->full_uri);
-    free(uri->scheme);
-    free(uri->host_and_port);
-    //free(uri->host_and_port_for_connecting);
-    free(uri->host);
-    free(uri->path);
-    free(uri->path_and_more);
-    free(uri->query);
-    free(uri->fragment);
-    uri->port = 0;
-    free(uri);
-  }
-}
-
-
-static int
-init_parse_uri(regex_t * preg)
-{
-  // RFC 2396
-  // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
-      /*
-        scheme    = $2
-      authority = $4
-      path      = $5
-      query     = $7
-      fragment  = $9
-      */
-
-  return regcomp(preg, "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", REG_EXTENDED);
-}
-
-
-static void
-deinit_parse_uri(regex_t * preg)
-{
-  regfree(preg);
-}
-
-
-static int
-parse_uri(regex_t * preg, const char * full_uri, struct URI ** uri)
-{
-  //TODO memeory checks
-  int ret;
-  char *colon;
-  long long port;
-  size_t nmatch = 10;
-  regmatch_t pmatch[10];
-
-  if (0 != (ret = regexec(preg, full_uri, nmatch, pmatch, 0)))
-    return ret;
-
-  *uri = malloc(sizeof(struct URI));
-  if(NULL == *uri)
-    return -200;
-
-  (*uri)->full_uri = strdup(full_uri);
-
-  asprintf(&((*uri)->scheme),
-	   "%.*s",
-	   (int) (pmatch[2].rm_eo - pmatch[2].rm_so),
-	   &full_uri[pmatch[2].rm_so]);
-  asprintf(&((*uri)->host_and_port), "%.*s",
-	   (int) (pmatch[4].rm_eo - pmatch[4].rm_so),
-	   &full_uri[pmatch[4].rm_so]);
-  asprintf(&((*uri)->path),
-	   "%.*s",
-	   (int) (pmatch[5].rm_eo - pmatch[5].rm_so),
-	   &full_uri[pmatch[5].rm_so]);
-  asprintf(&((*uri)->path_and_more),
-	   "%.*s",
-	   (int) (pmatch[9].rm_eo - pmatch[5].rm_so),
-	   &full_uri[pmatch[5].rm_so]);
-  asprintf(&((*uri)->query),
-	   "%.*s",
-	   (int) (pmatch[7].rm_eo - pmatch[7].rm_so),
-	   &full_uri[pmatch[7].rm_so]);
-  asprintf(&((*uri)->fragment),
-	   "%.*s",
-	   (int) (pmatch[9].rm_eo - pmatch[9].rm_so),
-	   &full_uri[pmatch[9].rm_so]);
-
-  colon = strrchr((*uri)->host_and_port, ':');
-  if(NULL == colon)
-  {
-    (*uri)->host = strdup((*uri)->host_and_port);
-    /*if(0 == strcasecmp("http", uri->scheme))
-    {
-      uri->port = 80;
-      asprintf(&(uri->host_and_port_for_connecting), "%s:80", uri->host_and_port);
-    }
-    else if(0 == strcasecmp("https", uri->scheme))
-    {
-      uri->port = 443;
-      asprintf(&(uri->host_and_port_for_connecting), "%s:443", uri->host_and_port);
-    }
-    else
-    {
-      PRINT_INFO("no standard scheme!");
-      */(*uri)->port = 0;
-      /*uri->host_and_port_for_connecting = strdup(uri->host_and_port);
-    }*/
-    return 0;
-  }
-
-  port = atoi(colon  + 1);
-  if(port<1 || port >= 256 * 256)
-  {
-    free_uri(*uri);
-    return -100;
-  }
-  (*uri)->port = port;
-  asprintf(&((*uri)->host), "%.*s", (int)(colon - (*uri)->host_and_port), (*uri)->host_and_port);
-
-  return 0;
-}
-
-
-static bool
-store_in_buffer(const void *src, size_t src_size, void **dst, size_t *dst_size)
-{
-  if(0 == src_size)
-    return true;
-
-  if(NULL == *dst)
-		*dst = malloc(src_size);
-	else
-		*dst = realloc(*dst, src_size + *dst_size);
-	if(NULL == *dst)
-		return false;
-
-	memcpy(*dst + *dst_size, src, src_size);
-	*dst_size += src_size;
-
-  return true;
-}
-
-
-static ssize_t
-get_from_buffer(void **src, size_t *src_size, void *dst, size_t max_size)
-{
-  size_t ret;
-  void *newbody;
-
-	if(max_size >= *src_size)
-	{
-		ret = *src_size;
-		newbody = NULL;
-	}
-	else
-	{
-		ret = max_size;
-		if(NULL == (newbody = malloc(*src_size - max_size)))
-			return -1;
-		memcpy(newbody, *src + ret, *src_size - ret);
-	}
-	memcpy(dst, *src, ret);
-	free(*src);
-	*src = newbody;
-	*src_size -= ret;
-
-  return ret;
-}
-
-
-static void
-catch_signal(int signal)
-{
-  (void)signal;
-
-  loop = 0;
-}
-
-static void
-new_session_cb (void * cls,
-							struct SPDY_Session * session)
-{
-  (void)cls;
-
-  bool *session_alive;
-
-  PRINT_VERBOSE("new session");
-  //TODO clean this memory
-  if(NULL == (session_alive = malloc(sizeof(bool))))
-  {
-			DIE("no memory");
-  }
-  *session_alive = true;
-  SPDY_set_cls_to_session(session,
-						session_alive);
-}
-
-static void
-session_closed_cb (void * cls,
-								struct SPDY_Session * session,
-								int by_client)
-{
-  (void)cls;
-
-  bool *session_alive;
-
-  PRINT_VERBOSE2("session closed; by client: %i", by_client);
-
-  session_alive = SPDY_get_cls_from_session(session);
-  assert(NULL != session_alive);
-
-  *session_alive = false;
-}
-
-
-static int
-spdy_post_data_cb (void * cls,
-					 struct SPDY_Request *request,
-					 const void * buf,
-					 size_t size,
-					 bool more)
-{
-  (void)cls;
-  int ret;
-	struct Proxy *proxy = (struct Proxy *)SPDY_get_cls_from_request(request);
-
-  if(!store_in_buffer(buf, size, &proxy->received_body, &proxy->received_body_size))
-	{
-		PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
-		return 0;
-	}
-
-  proxy->receiving_done = !more;
-
-  PRINT_VERBOSE2("POST bytes from SPDY: %zu", size);
-
-  call_curl_run = true;
-
-  if(proxy->is_curl_read_paused)
-  {
-    if(CURLE_OK != (ret = curl_easy_pause(proxy->curl_handle, CURLPAUSE_CONT)))
-    {
-      PRINT_INFO2("curl_easy_pause returned %i", ret);
-      abort();
-    }
-    PRINT_VERBOSE("curl_read_cb pause resumed");
-  }
-
-  return SPDY_YES;
-}
-
-
-ssize_t
-response_callback (void *cls,
-						void *buffer,
-						size_t max,
-						bool *more)
-{
-	ssize_t ret;
-	struct Proxy *proxy = (struct Proxy *)cls;
-
-  *more = true;
-
-  assert(!proxy->spdy_error);
-
-  if(proxy->curl_error)
-  {
-    PRINT_VERBOSE("tell spdy about the error");
-    return -1;
-  }
-
-	if(!proxy->http_body_size)//nothing to write now
-  {
-    PRINT_VERBOSE("nothing to write now");
-    if(proxy->curl_done || proxy->curl_error) *more = false;
-		return 0;
-  }
-
-  ret = get_from_buffer(&(proxy->http_body), &(proxy->http_body_size), buffer, max);
-  if(ret < 0)
-  {
-    PRINT_INFO("no memory");
-    //TODO error?
-    return -1;
-  }
-
-  if((proxy->curl_done || proxy->curl_error) && 0 == proxy->http_body_size) *more = false;
-
-  PRINT_VERBOSE2("given bytes to microspdy: %zd", ret);
-
-	return ret;
-}
-
-
-static void
-cleanup(struct Proxy *proxy)
-{
-  int ret;
-
-  //fprintf(stderr, "free proxy for %s\n", proxy->url);
-
-	if(CURLM_OK != (ret = curl_multi_remove_handle(multi_handle, proxy->curl_handle)))
-	{
-		PRINT_INFO2("curl_multi_remove_handle failed (%i)", ret);
-    DIE("bug in cleanup");
-	}
-  debug_num_curls--;
-  //TODO bug on ku6.com or amazon.cn
-  // after curl_multi_remove_handle returned CURLM_BAD_EASY_HANDLE
-	curl_slist_free_all(proxy->curl_headers);
-	curl_easy_cleanup(proxy->curl_handle);
-
-	free(proxy->url);
-	free(proxy);
-}
-
-
-static 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;
-
-	if(SPDY_RESPONSE_RESULT_SUCCESS != status)
-	{
-    free(proxy->http_body);
-    proxy->http_body = NULL;
-    proxy->spdy_error = true;
-	}
-	cleanup(proxy);
-	SPDY_destroy_request(request);
-	SPDY_destroy_response(response);
-}
-
-
-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;
-	unsigned int i;
-	unsigned int pos;
-	int ret;
-  int num_values;
-  const char * const * values;
-  bool abort_it;
-
-	//printf("curl_header_cb %s\n", line);
-  if(!*(proxy->session_alive))
-  {
-    PRINT_VERBOSE("headers received, but session is dead");
-    proxy->spdy_error = true;
-    proxy->curl_error = true;
-    return 0;
-  }
-
-  //trailer
-  if(NULL != proxy->response) return 0;
-
-	if('\r' == line[0] || '\n' == 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)))
-							//256)))
-			DIE("no response");
-
-		SPDY_name_value_destroy(proxy->headers);
-    proxy->headers = NULL;
-		free(proxy->status_msg);
-    proxy->status_msg = NULL;
-		free(proxy->version);
-    proxy->version = NULL;
-
-		if(SPDY_YES != SPDY_queue_response(proxy->request,
-							proxy->response,
-							true,
-							false,
-							&response_done_callback,
-							proxy))
-    {
-			//DIE("no queue");
-      //TODO right?
-      proxy->spdy_error = true;
-      proxy->curl_error = true;
-      PRINT_VERBOSE2("no queue in curl_header_cb for %s", proxy->url);
-      SPDY_destroy_response(proxy->response);
-      proxy->response = NULL;
-      return 0;
-    }
-
-    call_spdy_run = true;
-
-		return realsize;
-	}
-
-	pos = 0;
-	if(NULL == proxy->version)
-	{
-		//first line from headers
-		//version
-		for(i=pos; i<realsize && ' '!=line[i]; ++i);
-		if(i == realsize)
-			DIE("error on parsing headers");
-		if(NULL == (proxy->version = strndup(line, i - pos)))
-        DIE("No memory");
-		pos = i+1;
-
-		//status (number)
-		for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i] && '\n'!=line[i]; ++i);
-		if(NULL == (status = strndup(&(line[pos]), i - pos)))
-        DIE("No memory");
-		proxy->status = atoi(status);
-		free(status);
-		if(i<realsize && '\r'!=line[i] && '\n'!=line[i])
-		{
-			//status (message)
-			pos = i+1;
-			for(i=pos; i<realsize && '\r'!=line[i] && '\n'!=line[i]; ++i);
-			if(NULL == (proxy->status_msg = strndup(&(line[pos]), i - pos)))
-        DIE("No memory");
-		}
-    PRINT_VERBOSE2("Header line received '%s' '%i' '%s' ", proxy->version, proxy->status, proxy->status_msg);
-		return realsize;
-	}
-
-	//other lines
-	//header name
-	for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i] && '\n'!=line[i]; ++i)
-		line[i] = tolower(line[i]); //spdy requires lower case
-	if(NULL == (name = strndup(line, i - pos)))
-        DIE("No memory");
-	if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name)
-		|| 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name)
-		|| 0 == strcmp(SPDY_HTTP_HEADER_TRANSFER_ENCODING, name)
-    )
-	{
-		//forbidden in spdy, ignore
-		free(name);
-		return realsize;
-	}
-	if(i == realsize || '\r'==line[i] || '\n'==line[i])
-	{
-		//no value. is it possible?
-		if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, ""))
-			DIE("SPDY_name_value_add failed");
-		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] && '\n'!=line[i]; ++i);
-	if(NULL == (value = strndup(&(line[pos]), i - pos)))
-        DIE("No memory");
-  PRINT_VERBOSE2("Adding header: '%s': '%s'", name, value);
-	if(SPDY_YES != (ret = SPDY_name_value_add(proxy->headers, name, value)))
-	{
-    abort_it=true;
-    if(NULL != (values = SPDY_name_value_lookup(proxy->headers, name, &num_values)))
-      for(i=0; i<(unsigned int)num_values; ++i)
-        if(0 == strcasecmp(value, values[i]))
-        {
-          abort_it=false;
-          PRINT_VERBOSE2("header appears more than once with same value '%s: %s'", name, value);
-          break;
-        }
-
-    if(abort_it)
-    {
-      PRINT_INFO2("SPDY_name_value_add failed (%i) for '%s'", ret, name);
-      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(!*(proxy->session_alive))
-  {
-    PRINT_VERBOSE("data received, but session is dead");
-      proxy->spdy_error = true;
-      proxy->curl_error = true;
-    return 0;
-  }
-
-  if(!store_in_buffer(contents, realsize, &proxy->http_body, &proxy->http_body_size))
-	{
-		PRINT_INFO("not enough memory (malloc/realloc returned NULL)");
-      proxy->curl_error = true;
-		return 0;
-	}
-  /*
-	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;
-  */
-
-  PRINT_VERBOSE2("received bytes from curl: %zu", realsize);
-
-  call_spdy_run = true;
-
-	return realsize;
-}
-
-
-static size_t
-curl_read_cb(void *ptr, size_t size, size_t nmemb, void *userp)
-{
-	ssize_t ret;
-	size_t max = size * nmemb;
-	struct Proxy *proxy = (struct Proxy *)userp;
-	//void *newbody;
-
-
-  if((proxy->receiving_done && !proxy->received_body_size) || !proxy->is_with_body_data || max < 1)
-  {
-    PRINT_VERBOSE("curl_read_cb last call");
-    return 0;
-  }
-
-  if(!*(proxy->session_alive))
-  {
-    PRINT_VERBOSE("POST is still being sent, but session is dead");
-    return CURL_READFUNC_ABORT;
-  }
-
-	if(!proxy->received_body_size)//nothing to write now
-  {
-    PRINT_VERBOSE("curl_read_cb called paused");
-    proxy->is_curl_read_paused = true;
-		return CURL_READFUNC_PAUSE;//TODO curl pause should be used
-  }
-
-  ret = get_from_buffer(&(proxy->received_body), &(proxy->received_body_size), ptr, max);
-  if(ret < 0)
-  {
-    PRINT_INFO("no memory");
-    return CURL_READFUNC_ABORT;
-  }
-
-	/*
-	if(max >= proxy->received_body_size)
-	{
-		ret = proxy->received_body_size;
-		newbody = NULL;
-	}
-	else
-	{
-		ret = max;
-		if(NULL == (newbody = malloc(proxy->received_body_size - max)))
-		{
-			PRINT_INFO("no memory");
-			return CURL_READFUNC_ABORT;
-		}
-		memcpy(newbody, proxy->received_body + max, proxy->received_body_size - max);
-	}
-	memcpy(ptr, proxy->received_body, ret);
-	free(proxy->received_body);
-	proxy->received_body = newbody;
-	proxy->received_body_size -= ret;
-  * */
-
-  PRINT_VERBOSE2("given POST bytes to curl: %zd", ret);
-
-	return ret;
-}
-
-
-static 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 recovery
-    DIE("No memory");
-	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, ", ");
-  PRINT_VERBOSE2("Adding request header: '%s' len %ld", value[i], strlen(value[i]));
-		strcat(line, value[i]);
-	}
-  PRINT_VERBOSE2("Adding request header: '%s'", line);
-  if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line)))
-		DIE("curl_slist_append failed");
-	free(line);
-
-	return SPDY_YES;
-}
-
-
-static 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,
-                        bool more)
-{
-	(void)cls;
-	(void)priority;
-	(void)host;
-	(void)scheme;
-
-	struct Proxy *proxy;
-	int ret;
-  struct URI *uri;
-  struct SPDY_Session *session;
-
-  proxy = SPDY_get_cls_from_request(request);
-  if(NULL != proxy)
-  {
-    //ignore trailers or more headers
-    return;
-  }
-
-	PRINT_VERBOSE2("received request for '%s %s %s'\n", method, path, version);
-
-  //TODO not freed once in a while
-	if(NULL == (proxy = malloc(sizeof(struct Proxy))))
-    DIE("No memory");
-	memset(proxy, 0, sizeof(struct Proxy));
-
-  //fprintf(stderr, "new  proxy for %s\n", path);
-
-  session = SPDY_get_session_for_request(request);
-  assert(NULL != session);
-  proxy->session_alive = SPDY_get_cls_from_session(session);
-  assert(NULL != proxy->session_alive);
-
-  SPDY_set_cls_to_request(request, proxy);
-
-	proxy->request = request;
-	proxy->is_with_body_data = more;
-	if(NULL == (proxy->headers = SPDY_name_value_create()))
-        DIE("No memory");
-
-  if(glob_opt.transparent)
-  {
-    if(NULL != glob_opt.http_backend) //use always same host
-      ret = asprintf(&(proxy->url),"%s://%s%s", scheme, glob_opt.http_backend, path);
-    else //use host header
-      ret = asprintf(&(proxy->url),"%s://%s%s", scheme, host, path);
-    if(-1 == ret)
-        DIE("No memory");
-
-    ret = parse_uri(&uri_preg, proxy->url, &uri);
-    if(ret != 0)
-      DIE("parsing built uri failed");
-  }
-  else
-  {
-    ret = parse_uri(&uri_preg, path, &uri);
-    PRINT_INFO2("path %s '%s' '%s'", path, uri->scheme, uri->host);
-    if(ret != 0 || !strlen(uri->scheme) || !strlen(uri->host))
-      DIE("parsing received uri failed");
-
-    if(NULL != glob_opt.http_backend) //use backend host
-    {
-      ret = asprintf(&(proxy->url),"%s://%s%s", uri->scheme, glob_opt.http_backend, uri->path_and_more);
-      if(-1 == ret)
-        DIE("No memory");
-    }
-    else //use request path
-      if(NULL == (proxy->url = strdup(path)))
-        DIE("No memory");
-  }
-
-  free_uri(uri);
-
-  PRINT_VERBOSE2("curl will request '%s'", proxy->url);
-
-  SPDY_name_value_iterate(headers, &iterate_cb, proxy);
-
-	if(NULL == (proxy->curl_handle = curl_easy_init()))
-    {
-		PRINT_INFO("curl_easy_init failed");
-		abort();
-	}
-
-	if(glob_opt.curl_verbose)
-    CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1);
-
-  if(0 == strcmp(SPDY_HTTP_METHOD_POST,method))
-  {
-    if(NULL == (proxy->curl_headers = curl_slist_append(proxy->curl_headers, "Expect:")))
-      DIE("curl_slist_append failed");
-    CURL_SETOPT(proxy->curl_handle, CURLOPT_POST, 1);
-    CURL_SETOPT(proxy->curl_handle, CURLOPT_READFUNCTION, curl_read_cb);
-    CURL_SETOPT(proxy->curl_handle, CURLOPT_READDATA, proxy);
-  }
-
-  if(glob_opt.timeout)
-    CURL_SETOPT(proxy->curl_handle, CURLOPT_TIMEOUT, glob_opt.timeout);
-	CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, proxy->url);
-	if(glob_opt.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_PRIVATE, proxy);
-	CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTPHEADER, proxy->curl_headers);
-  CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);//TODO
-  CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
-  if(glob_opt.ipv4 && !glob_opt.ipv6)
-    CURL_SETOPT(proxy->curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
-  else if(glob_opt.ipv6 && !glob_opt.ipv4)
-    CURL_SETOPT(proxy->curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
-
-	if(CURLM_OK != (ret = curl_multi_add_handle(multi_handle, proxy->curl_handle)))
-	{
-		PRINT_INFO2("curl_multi_add_handle failed (%i)", ret);
-		abort();
-	}
-  debug_num_curls++;
-
-  //~5ms additional latency for calling this
-	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();
-	}
-
-  call_curl_run = true;
-}
-
-
-static int
-run ()
-{
-  unsigned long long timeoutlong = 0;
-  unsigned long long timeout_spdy = 0;
-  long timeout_curl = -1;
-	struct timeval timeout;
-	int ret;
-	int ret_curl;
-	int ret_spdy;
-	fd_set rs;
-	fd_set ws;
-	fd_set es;
-	int maxfd = -1;
-	int maxfd_curl = -1;
-	struct SPDY_Daemon *daemon;
-  CURLMsg *msg;
-  int msgs_left;
-  struct Proxy *proxy;
-  struct sockaddr_in *addr;
-  struct addrinfo hints;
-  char service[NI_MAXSERV];
-  struct addrinfo *gai;
-  enum SPDY_IO_SUBSYSTEM io = glob_opt.notls ? SPDY_IO_SUBSYSTEM_RAW : SPDY_IO_SUBSYSTEM_OPENSSL;
-  enum SPDY_DAEMON_FLAG flags = SPDY_DAEMON_FLAG_NO;
-  //struct SPDY_Response *error_response;
-  char *curl_private;
-
-	signal(SIGPIPE, SIG_IGN);
-
-  if (signal(SIGINT, catch_signal) == SIG_ERR)
-    PRINT_VERBOSE("signal failed");
-
-  srand(time(NULL));
-  if(init_parse_uri(&uri_preg))
-    DIE("Regexp compilation failed");
-
-	SPDY_init();
-
-  if(glob_opt.nodelay)
-    flags |= SPDY_DAEMON_FLAG_NO_DELAY;
-
-  if(NULL == glob_opt.listen_host)
-	{
-    daemon = SPDY_start_daemon(glob_opt.listen_port,
-								glob_opt.cert,
-								glob_opt.cert_key,
-								&new_session_cb,
-								&session_closed_cb,
-								&standard_request_handler,
-								&spdy_post_data_cb,
-								NULL,
-								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
-								1800,
-                SPDY_DAEMON_OPTION_IO_SUBSYSTEM,
-                io,
-                SPDY_DAEMON_OPTION_FLAGS,
-                flags,
-								SPDY_DAEMON_OPTION_END);
-  }
-  else
-  {
-    snprintf (service, sizeof(service), "%u", glob_opt.listen_port);
-    memset (&hints, 0, sizeof(struct addrinfo));
-    hints.ai_family = AF_INET;
-    hints.ai_socktype = SOCK_STREAM;
-
-    ret = getaddrinfo(glob_opt.listen_host, service, &hints, &gai);
-    if(ret != 0)
-      DIE("problem with specified host");
-
-    addr = (struct sockaddr_in *) gai->ai_addr;
-
-    daemon = SPDY_start_daemon(0,
-								glob_opt.cert,
-								glob_opt.cert_key,
-								&new_session_cb,
-								&session_closed_cb,
-								&standard_request_handler,
-								&spdy_post_data_cb,
-								NULL,
-								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
-								1800,
-                SPDY_DAEMON_OPTION_IO_SUBSYSTEM,
-                io,
-                SPDY_DAEMON_OPTION_FLAGS,
-                flags,
-                SPDY_DAEMON_OPTION_SOCK_ADDR,
-                addr,
-                //SPDY_DAEMON_OPTION_MAX_NUM_FRAMES,
-                //1,
-								SPDY_DAEMON_OPTION_END);
-  }
-
-	if(NULL==daemon){
-		printf("no daemon\n");
-		return 1;
-	}
-
-	multi_handle = curl_multi_init();
-	if(NULL==multi_handle)
-		DIE("no multi_handle");
-
-	timeout.tv_usec = 0;
-
-	do
-	{
-		FD_ZERO(&rs);
-		FD_ZERO(&ws);
-		FD_ZERO(&es);
-
-    PRINT_VERBOSE2("num  curls %i", debug_num_curls);
-
-    ret_spdy = SPDY_get_timeout(daemon, &timeout_spdy);
-    if(SPDY_NO == ret_spdy || timeout_spdy > 5000)
-      timeoutlong = 5000;
-    else
-      timeoutlong = timeout_spdy;
-    PRINT_VERBOSE2("SPDY timeout %lld; %i", timeout_spdy, ret_spdy);
-
-    if(CURLM_OK != (ret_curl = curl_multi_timeout(multi_handle, &timeout_curl)))
-    {
-      PRINT_VERBOSE2("curl_multi_timeout failed (%i)", ret_curl);
-      //curl_timeo = timeoutlong;
-    }
-    else if(timeout_curl >= 0 && timeoutlong > (unsigned long)timeout_curl)
-      timeoutlong = (unsigned long)timeout_curl;
-
-    PRINT_VERBOSE2("curl timeout %ld", timeout_curl);
-
-    timeout.tv_sec = timeoutlong / 1000;
-		timeout.tv_usec = (timeoutlong % 1000) * 1000;
-
-		maxfd = SPDY_get_fdset (daemon,
-								&rs,
-								&ws,
-								&es);
-		assert(-1 != maxfd);
-
-		if(CURLM_OK != (ret = curl_multi_fdset(multi_handle, &rs,
-								&ws,
-								&es, &maxfd_curl)))
-		{
-			PRINT_INFO2("curl_multi_fdset failed (%i)", ret);
-			abort();
-		}
-
-    if(maxfd_curl > maxfd)
-      maxfd = maxfd_curl;
-
-    PRINT_VERBOSE2("timeout before %lld %lld", (unsigned long long)timeout.tv_sec, (unsigned long long)timeout.tv_usec);
-    ret = select(maxfd+1, &rs, &ws, &es, &timeout);
-    PRINT_VERBOSE2("timeout after %lld %lld; ret is %i", (unsigned long long)timeout.tv_sec, (unsigned long long)timeout.tv_usec, ret);
-
-		/*switch(ret) {
-			case -1:
-				PRINT_INFO2("select error: %i", errno);
-				break;
-			case 0:
-				break;
-			default:*/
-
-      //the second part should not happen with current implementation
-      if(ret > 0 || (SPDY_YES == ret_spdy && 0 == timeout_spdy))
-      {
-				PRINT_VERBOSE("run spdy");
-				SPDY_run(daemon);
-        call_spdy_run = false;
-      }
-
-      //if(ret > 0 || (CURLM_OK == ret_curl && 0 == timeout_curl) || call_curl_run)
-      {
-				PRINT_VERBOSE("run curl");
-				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();
-				}
-        call_curl_run = false;
-      }
-			/*break;
-		}*/
-
-    while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
-      if (msg->msg == CURLMSG_DONE) {
-        PRINT_VERBOSE("A curl handler is done");
-        if(CURLE_OK != (ret = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &curl_private)))
-        {
-          PRINT_INFO2("err %i",ret);
-          abort();
-        }
-        assert(NULL != curl_private);
-        proxy = (struct Proxy *)curl_private;
-        if(CURLE_OK == msg->data.result)
-        {
-          proxy->curl_done = true;
-          call_spdy_run = true;
-          //TODO what happens with proxy when the client resets a stream
-          //and response_done is not yet set for the last frame? is it
-          //possible?
-        }
-        else
-        {
-          PRINT_VERBOSE2("bad curl result (%i) for '%s'", msg->data.result, proxy->url);
-          if(proxy->spdy_done || proxy->spdy_error || (NULL == proxy->response && !*(proxy->session_alive)))
-          {
-            PRINT_VERBOSE("cleaning");
-            SPDY_name_value_destroy(proxy->headers);
-            SPDY_destroy_request(proxy->request);
-            SPDY_destroy_response(proxy->response);
-            cleanup(proxy);
-          }
-          else if(NULL == proxy->response && *(proxy->session_alive))
-          {
-            //generate error for the client
-            PRINT_VERBOSE("will send Bad Gateway");
-            SPDY_name_value_destroy(proxy->headers);
-            proxy->headers = NULL;
-            if(NULL == (proxy->response = SPDY_build_response(SPDY_HTTP_BAD_GATEWAY,
-                  NULL,
-                  SPDY_HTTP_VERSION_1_1,
-                  NULL,
-                  ERROR_RESPONSE,
-                  strlen(ERROR_RESPONSE))))
-              DIE("no response");
-            if(SPDY_YES != SPDY_queue_response(proxy->request,
-                      proxy->response,
-                      true,
-                      false,
-                      &response_done_callback,
-                      proxy))
-            {
-              //clean and forget
-              PRINT_VERBOSE("cleaning");
-              SPDY_destroy_request(proxy->request);
-              SPDY_destroy_response(proxy->response);
-              cleanup(proxy);
-            }
-          }
-          else
-          {
-            proxy->curl_error = true;
-          }
-          call_spdy_run = true;
-          //TODO spdy should be notified to send RST_STREAM
-        }
-      }
-      else PRINT_INFO("shouldn't happen");
-    }
-
-    if(call_spdy_run)
-    {
-      PRINT_VERBOSE("second call to SPDY_run");
-      SPDY_run(daemon);
-      call_spdy_run = false;
-    }
-
-    if(glob_opt.verbose)
-    {
-
-#ifdef HAVE_CLOCK_GETTIME
-#ifdef CLOCK_MONOTONIC
-    struct timespec ts;
-
-    if (0 == clock_gettime(CLOCK_MONOTONIC, &ts))
-    PRINT_VERBOSE2 ("time now %lld %lld",
-		    (unsigned long long) ts.tv_sec,
-		    (unsigned long long) ts.tv_nsec);
-#endif
-#endif
-    }
-
-  }
-  while(loop);
-
-	SPDY_stop_daemon(daemon);
-
-	curl_multi_cleanup(multi_handle);
-
-	SPDY_deinit();
-
-  deinit_parse_uri(&uri_preg);
-
-	return 0;
-}
-
-
-static void
-display_usage()
-{
-  printf(
-    "Usage: microspdy2http -p <PORT> [-c <CERTIFICATE>] [-k <CERT-KEY>]\n"
-    "                      [-rvh0DtT] [-b <HTTP-SERVER>] [-l <HOST>]\n\n"
-    "OPTIONS:\n"
-    "    -p, --port            Listening port.\n"
-    "    -l, --host            Listening host. If not set, will listen on [::]\n"
-    "    -c, --certificate     Path to a certificate file. Requiered if\n"
-    "                          --no-tls is not set.\n"
-    "    -k, --certificate-key Path to a key file for the certificate.\n"
-    "                          Requiered if --no-tls is not set.\n"
-    "    -b, --backend-server  If set, the proxy will connect always to it.\n"
-    "                          Otherwise the proxy will connect to the URL\n"
-    "                          which is specified in the path or 'Host:'.\n"
-    "    -v, --verbose         Print debug information.\n"
-    "    -r, --no-tls          Do not use TLS. Client must use SPDY/3.\n"
-    "    -h, --curl-verbose    Print debug information for curl.\n"
-    "    -0, --http10          Prefer HTTP/1.0 connections to the next hop.\n"
-    "    -D, --no-delay        This makes sense only if --no-tls is used.\n"
-    "                          TCP_NODELAY will be used for all sessions' sockets.\n"
-    "    -4, --curl-ipv4       Curl may use IPv4 to connect to the final destination.\n"
-    "    -6, --curl-ipv6       Curl may use IPv6 to connect to the final destination.\n"
-    "                          If neither --curl-ipv4 nor --curl-ipv6 is set,\n"
-    "                          both will be used by default.\n"
-    "    -T, --timeout         Maximum time in seconds for each HTTP transfer.\n"
-    "                          Use 0 for no timeout; this is the default value.\n"
-    "    -t, --transparent     If set, the proxy will fetch an URL which\n"
-    "                          is based on 'Host:' header and requested path.\n"
-    "                          Otherwise, full URL in the requested path is required.\n\n"
-
-  );
-}
-
-
-int
-main (int argc, char *const *argv)
-{
-
-  int getopt_ret;
-  int option_index;
-  struct option long_options[] = {
-    {"port",  required_argument, 0, 'p'},
-    {"certificate",  required_argument, 0, 'c'},
-    {"certificate-key",  required_argument, 0, 'k'},
-    {"backend-server",  required_argument, 0, 'b'},
-    {"no-tls",  no_argument, 0, 'r'},
-    {"verbose",  no_argument, 0, 'v'},
-    {"curl-verbose",  no_argument, 0, 'h'},
-    {"http10",  no_argument, 0, '0'},
-    {"no-delay",  no_argument, 0, 'D'},
-    {"transparent",  no_argument, 0, 't'},
-    {"curl-ipv4",  no_argument, 0, '4'},
-    {"curl-ipv6",  no_argument, 0, '6'},
-    {"timeout",  required_argument, 0, 'T'},
-    {0, 0, 0, 0}
-  };
-
-  while (1)
-  {
-    getopt_ret = getopt_long( argc, argv, "p:l:c:k:b:rv0Dth46T:", long_options, &option_index);
-    if (getopt_ret == -1)
-      break;
-
-    switch(getopt_ret)
-    {
-      case 'p':
-        glob_opt.listen_port = atoi(optarg);
-        break;
-
-      case 'l':
-        glob_opt.listen_host= strdup(optarg);
-        if(NULL == glob_opt.listen_host)
-          return 1;
-        break;
-
-      case 'c':
-        glob_opt.cert = strdup(optarg);
-        break;
-
-      case 'k':
-        glob_opt.cert_key = strdup(optarg);
-        break;
-
-      case 'b':
-        glob_opt.http_backend = strdup(optarg);
-        if(NULL == glob_opt.http_backend)
-          return 1;
-        break;
-
-      case 'r':
-        glob_opt.notls = true;
-        break;
-
-      case 'v':
-        glob_opt.verbose = true;
-        break;
-
-      case 'h':
-        glob_opt.curl_verbose = true;
-        break;
-
-      case '0':
-        glob_opt.http10 = true;
-        break;
-
-      case 'D':
-        glob_opt.nodelay = true;
-        break;
-
-      case 't':
-        glob_opt.transparent = true;
-        break;
-
-      case '4':
-        glob_opt.ipv4 = true;
-        break;
-
-      case '6':
-        glob_opt.ipv6 = true;
-        break;
-
-      case 'T':
-        glob_opt.timeout = atoi(optarg);
-        break;
-
-      case 0:
-        PRINT_INFO("0 from getopt");
-        break;
-
-      case '?':
-        display_usage();
-        return 1;
-
-      default:
-        DIE("default from getopt");
-    }
-  }
-
-  if(
-    0 == glob_opt.listen_port
-    || (!glob_opt.notls && (NULL == glob_opt.cert || NULL == glob_opt.cert_key))
-    //|| !glob_opt.transparent && NULL != glob_opt.http_backend
-    )
-  {
-    display_usage();
-    return 1;
-  }
-
-  return run();
-}
-

+ 0 - 115
src/testspdy/Makefile.am

@@ -1,115 +0,0 @@
-# This Makefile.am is in the public domain
-SUBDIRS  = .
-
-AM_CFLAGS = -DDATA_DIR=\"$(top_srcdir)/src/datadir/\"
-
-if USE_COVERAGE
-  AM_CFLAGS += -fprofile-arcs -ftest-coverage
-endif
-
-AM_CPPFLAGS = \
- -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
-
-if ENABLE_SPDY
-if HAVE_OPENSSL
-check_PROGRAMS = \
-  test_daemon_start_stop \
-  test_daemon_start_stop_many \
-  test_struct_namevalue
-
-if HAVE_SPDYLAY  
-check_PROGRAMS += \
-  test_new_connection  \
-  test_request_response \
-  test_notls \
-  test_request_response_with_callback \
-  test_misc \
-  test_session_timeout
-  #test_requests_with_assets 
-if HAVE_CURL_BINARY
-check_PROGRAMS +=  \
-  test_proxies
-endif 
-endif
-endif 
-endif 
-
-
-TESTS = $(check_PROGRAMS)
-
-
-SPDY_SOURCES= \
- common.h common.c
-
-SPDY_LDADD=  \
- $(top_builddir)/src/microspdy/libmicrospdy.la \
- -lz
-
-test_daemon_start_stop_SOURCES = \
- test_daemon_start_stop.c \
- $(SPDY_SOURCES) 
-test_daemon_start_stop_LDADD =  $(SPDY_LDADD)
-
-test_daemon_start_stop_many_SOURCES = \
- test_daemon_start_stop_many.c  \
- $(SPDY_SOURCES) 
-test_daemon_start_stop_many_LDADD = $(SPDY_LDADD)
-
-test_struct_namevalue_SOURCES = \
- test_struct_namevalue.c  \
- $(SPDY_SOURCES) 
-test_struct_namevalue_LDADD = $(SPDY_LDADD)
-
-if HAVE_SPDYLAY
-test_new_connection_SOURCES = \
- test_new_connection.c  \
- $(SPDY_SOURCES) 
-test_new_connection_LDADD = $(SPDY_LDADD) \
- -lspdylay
-
-test_request_response_SOURCES = \
- test_request_response.c  \
- $(SPDY_SOURCES) 
-test_request_response_LDADD = $(SPDY_LDADD) \
- -lspdylay
-
-test_notls_SOURCES = \
- test_notls.c  \
- $(SPDY_SOURCES) 
-test_notls_LDADD = $(SPDY_LDADD) \
- -lspdylay
-
-test_request_response_with_callback_SOURCES = \
- test_request_response_with_callback.c  \
- $(SPDY_SOURCES) 
-test_request_response_with_callback_LDADD = $(SPDY_LDADD)
-
-#test_requests_with_assets_SOURCES = \
-# test_requests_with_assets.c  \
-# $(SPDY_SOURCES) 
-#test_requests_with_assets_LDADD = $(SPDY_LDADD)
-
-test_misc_SOURCES = \
- test_misc.c  \
- $(SPDY_SOURCES) 
-test_misc_LDADD = $(SPDY_LDADD)
-
-test_session_timeout_SOURCES = \
- test_session_timeout.c  \
- $(SPDY_SOURCES) 
-test_session_timeout_LDADD = $(SPDY_LDADD)
-
-
-test_proxies_SOURCES = \
- test_proxies.c \
- $(SPDY_SOURCES) 
-test_proxies_LDADD = $(SPDY_LDADD)
-
-endif

+ 0 - 59
src/testspdy/common.c

@@ -1,59 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 common.c
- * @brief  Common functions used by the tests.
- * @author Andrey Uzunov
- */
- 
-
-#include "common.h"
-#include <sys/time.h>
-
-#ifdef __GNUC__
-#define FUNC_CONSTRUCTOR(f) static void __attribute__ ((constructor)) f
-#define FUNC_DESTRUCTOR(f) static void __attribute__ ((destructor)) f
-#else  // !__GNUC__
-#define FUNC_CONSTRUCTOR(f) _MHD_EXTERN void f
-#define FUNC_DESTRUCTOR(f) _MHD_EXTERN void f
-#endif  // __GNUC__
-
-FUNC_CONSTRUCTOR (constructor)()
-{
-	printf("\nTEST START -------------------------------------------------------\n");
-}
-
-FUNC_DESTRUCTOR (destructor)()
-{
-	printf("------------------------------------------------------- TEST END\n");
-}
-
-uint16_t
-get_port(uint16_t min)
-{
-	struct timeval tv;
-	gettimeofday(&tv, NULL);
-	if(2 > min) min=2;
-	uint16_t port =  min + (tv.tv_usec+10) % ((1 << 16)  - min);
-	
-	//port = 12345;
-	printf("Port used: %i\n", port);
-	
-	return port;
-}

+ 0 - 38
src/testspdy/common.h

@@ -1,38 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 common.h
- * @brief  Common functions used by the tests.
- * @author Andrey Uzunov
- */
- 
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#define FAIL_TEST(msg) do{\
-	printf("%i:%s\n", __LINE__, msg);\
-	fflush(stdout);\
-	exit(-10);\
-	}\
-	while(0)
-	
-uint16_t
-get_port(uint16_t min);

+ 0 - 49
src/testspdy/test_daemon_start_stop.c

@@ -1,49 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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_start_stop.c
- * @brief  starts and stops a SPDY daemon
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include "common.h"
-
-int
-main()
-{
-	SPDY_init();
-	
-	struct SPDY_Daemon *daemon = SPDY_start_daemon(get_port(16123),
-	 DATA_DIR "cert-and-key.pem",
-	 DATA_DIR "cert-and-key.pem",
-	NULL,NULL,NULL,NULL,NULL,SPDY_DAEMON_OPTION_END);
-	
-	if(NULL==daemon){
-		printf("no daemon\n");
-		return 1;
-	}
-	
-	SPDY_stop_daemon(daemon);
-	
-	SPDY_deinit();
-	
-	return 0;
-}

+ 0 - 66
src/testspdy/test_daemon_start_stop_many.c

@@ -1,66 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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_start_stop_many.c
- * @brief  starts and stops several SPDY daemons, reusing port numbers
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include "common.h"
-
-int
-main()
-{
-	int i;
-	int j;
-	int num_daemons = 3;
-	int num_tries = 5;
-	int port = get_port(15123);
-	struct SPDY_Daemon *daemon[num_daemons];
-	
-	SPDY_init();
-	
-	for(i=0; i<num_tries; ++i)
-	{
-		for(j=0;j<num_daemons;++j)
-		{
-			daemon[j] = SPDY_start_daemon(port + j,
-			DATA_DIR "cert-and-key.pem",
-			DATA_DIR "cert-and-key.pem",
-			NULL,NULL,NULL,NULL,NULL,SPDY_DAEMON_OPTION_END);
-	
-			if(NULL==daemon[j]){
-				printf("no daemon\n");
-				return 1;
-			}
-		}
-		
-		
-		for(j=0;j<num_daemons;++j)
-		{
-			SPDY_stop_daemon(daemon[j]);
-		}
-	}
-	
-	SPDY_deinit();
-	
-	return 0;
-}

+ 0 - 289
src/testspdy/test_misc.c

@@ -1,289 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 misc.c
- * @brief  tests a lot of small calls and callbacks. TODO mention what
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include "stdio.h"
-#include <sys/wait.h>
-#include "common.h"
-
-int port;
-
-#define HTML "<html><head>\
-<link href=\"main.css\" rel=\"stylesheet\" type=\"text/css\" />\
-</head><body>This is libmicrospdy</body></html>"
-
-#define CSS "body{font-size:15px}"
-
-#define SESSION_CLS "1234567890"
-
-#define REQUEST_CLS "1234567890REQ"
-
-pid_t parent;
-pid_t child;
-
-struct SPDY_Session *session1;
-struct SPDY_Session *session2;
-
-void
-killchild()
-{
-	kill(child, SIGKILL);
-	exit(1);
-}
-
-void
-killparent()
-{
-	kill(parent, SIGKILL);
-	_exit(1);
-}
-
-
-void
-create_child()
-{
-	parent = getpid();
-
-	child = fork();
-	if (-1 == child)
-	{
-		fprintf(stderr, "can't fork, error %d\n", errno);
-		exit(EXIT_FAILURE);
-	}
-
-	if (child == 0)
-	{
-		int devnull;
-		char *uri;
-		fflush(stdout);
-		devnull = open("/dev/null", O_WRONLY);
-                if (-1 == devnull)
-                  abort ();
-		if (1 != devnull)
-		{
-			dup2(devnull, 1);
-			close(devnull);
-		}
-		asprintf(&uri,"https://127.0.0.1:%i/",port);
-		execlp("spdycat", "spdycat","-anv",uri,NULL );
-		printf("execlp failed\n");
-		killparent();
-	}
-}
-
-void
-response_done_callback(void *cls,
-								struct SPDY_Response * response,
-								struct SPDY_Request * request,
-								enum SPDY_RESPONSE_RESULT status,
-						bool streamopened)
-{
-  (void)status;
-  (void)streamopened;
-
-	if(strcmp(cls,"/main.css"))
-	{
-		session1 = SPDY_get_session_for_request(request);
-		if(NULL == session1)
-		{
-			printf("SPDY_get_session_for_request failed\n");
-			killchild();
-		}
-
-		char *session_cls = strdup(SESSION_CLS);
-		SPDY_set_cls_to_session(session1,session_cls);
-	}
-	else
-	{
-		session2 = SPDY_get_session_for_request(request);
-		if(session1 != session2)
-		{
-			printf("SPDY_get_session_for_request failed the second time\n");
-			killchild();
-		}
-		printf("SPDY_get_session_for_request tested...\n");
-
-		void *session_cls = SPDY_get_cls_from_session(session2);
-		if(NULL == session_cls || strcmp(session_cls, SESSION_CLS))
-		{
-			printf("SPDY_get_cls_from_session failed\n");
-			killchild();
-		}
-		printf("SPDY_set_cls_to_session tested...\n");
-		printf("SPDY_get_cls_from_session tested...\n");
-
-		void *request_cls = SPDY_get_cls_from_request(request);
-		if(NULL == request_cls || strcmp(request_cls, REQUEST_CLS))
-		{
-			printf("SPDY_get_cls_from_request failed\n");
-			killchild();
-		}
-		printf("SPDY_set_cls_to_request tested...\n");
-		printf("SPDY_get_cls_from_request tested...\n");
-	}
-
-	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,
-            bool more)
-{
-	(void)cls;
-	(void)request;
-	(void)priority;
-	(void)host;
-	(void)scheme;
-	(void)headers;
-	(void)method;
-	(void)version;
-	(void)more;
-
-	struct SPDY_Response *response=NULL;
-	char *cls_path = strdup(path);
-
-	if(strcmp(path,"/main.css")==0)
-	{
-		char *request_cls = strdup(REQUEST_CLS);
-		SPDY_set_cls_to_request(request,request_cls);
-		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,CSS,strlen(CSS));
-	}
-	else
-	{
-		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,HTML,strlen(HTML));
-	}
-
-	if(NULL==response){
-		fprintf(stdout,"no response obj\n");
-		killchild();
-	}
-
-	if(SPDY_queue_response(request,response,true,false,&response_done_callback,cls_path)!=SPDY_YES)
-	{
-		fprintf(stdout,"queue\n");
-		killchild();
-	}
-}
-
-int
-parentproc()
-{
-	int childstatus;
-	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;
-
-	daemon = SPDY_start_daemon(port,
-								DATA_DIR "cert-and-key.pem",
-								DATA_DIR "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;
-	}
-
-	create_child();
-
-	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 > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-
-		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(waitpid(child,&childstatus,WNOHANG) != child);
-
-	SPDY_stop_daemon(daemon);
-
-	return WEXITSTATUS(childstatus);
-}
-
-
-int
-main()
-{
-	port = get_port(13123);
-	SPDY_init();
-
-	int ret = parentproc();
-
-	SPDY_deinit();
-
-	return ret;
-}

+ 0 - 1012
src/testspdy/test_new_connection.c

@@ -1,1012 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 test_new_connection.c
- * @brief  tests new connection callback. spdycli.c
- * 			code is reused here
- * @author Andrey Uzunov
- * @author Tatsuhiro Tsujikawa
- */
-
-//TODO child exits with ret val 1 sometimes
-
-#include "platform.h"
-#include "microspdy.h"
-#include <sys/wait.h>
-#include "common.h"
-
-#define RESPONSE_BODY "<html><body><b>Hi, this is libmicrospdy!</b></body></html>"
-
-#define CLS "anything"
-
-int port;
-int loop = 1;
-
-pid_t parent;
-pid_t child;
-
-int
-spdylay_printf(const char *format, ...)
-{
-  (void)format;
-
-	return 0;
-}
-
-int
-spdylay_fprintf(FILE *stream, const char *format, ...)
-{
-  (void)stream;
-  (void)format;
-
-	return 0;
-}
-
-void
-killchild(int pid, char *message)
-{
-	printf("%s\n",message);
-	kill(pid, SIGKILL);
-	exit(1);
-}
-
-void
-killparent(int pid, char *message)
-{
-	printf("%s\n",message);
-	kill(pid, SIGKILL);
-	_exit(2);
-}
-
-
-/*****
- * start of code needed to utilize spdylay
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include <spdylay/spdylay.h>
-
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-
-enum {
-  IO_NONE,
-  WANT_READ,
-  WANT_WRITE
-};
-
-struct Connection {
-  SSL *ssl;
-  spdylay_session *session;
-  /* WANT_READ if SSL connection needs more input; or WANT_WRITE if it
-     needs more output; or IO_NONE. This is necessary because SSL/TLS
-     re-negotiation is possible at any time. Spdylay API offers
-     similar functions like spdylay_session_want_read() and
-     spdylay_session_want_write() but they do not take into account
-     SSL connection. */
-  int want_io;
-};
-
-struct Request {
-  char *host;
-  uint16_t port;
-  /* In this program, path contains query component as well. */
-  char *path;
-  /* This is the concatenation of host and port with ":" in
-     between. */
-  char *hostport;
-  /* Stream ID for this request. */
-  int32_t stream_id;
-  /* The gzip stream inflater for the compressed response. */
-  spdylay_gzip *inflater;
-};
-
-struct URI {
-  const char *host;
-  size_t hostlen;
-  uint16_t port;
-  /* In this program, path contains query component as well. */
-  const char *path;
-  size_t pathlen;
-  const char *hostport;
-  size_t hostportlen;
-};
-
-/*
- * Returns copy of string |s| with the length |len|. The returned
- * string is NULL-terminated.
- */
-static char* strcopy(const char *s, size_t len)
-{
-  char *dst;
-  dst = malloc(len+1);
-  if (NULL == dst)
-    abort ();
-  memcpy(dst, s, len);
-  dst[len] = '\0';
-  return dst;
-}
-
-/*
- * Prints error message |msg| and exit.
- */
-static void die(const char *msg)
-{
-  fprintf(stderr, "FATAL: %s\n", msg);
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Prints error containing the function name |func| and message |msg|
- * and exit.
- */
-static void dief(const char *func, const char *msg)
-{
-  fprintf(stderr, "FATAL: %s: %s\n", func, msg);
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Prints error containing the function name |func| and error code
- * |error_code| and exit.
- */
-static void diec(const char *func, int error_code)
-{
-  fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
-          spdylay_strerror(error_code));
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Check response is content-encoding: gzip. We need this because SPDY
- * client is required to support gzip.
- */
-static void check_gzip(struct Request *req, char **nv)
-{
-  int gzip = 0;
-  size_t i;
-  for(i = 0; nv[i]; i += 2) {
-    if(strcmp("content-encoding", nv[i]) == 0) {
-      gzip = strcmp("gzip", nv[i+1]) == 0;
-      break;
-    }
-  }
-  if(gzip) {
-    int rv;
-    if(req->inflater) {
-      return;
-    }
-    rv = spdylay_gzip_inflate_new(&req->inflater);
-    if(rv != 0) {
-      die("Can't allocate inflate stream.");
-    }
-  }
-}
-
-/*
- * The implementation of spdylay_send_callback type. Here we write
- * |data| with size |length| to the network and return the number of
- * bytes actually written. See the documentation of
- * spdylay_send_callback for the details.
- */
-static ssize_t send_callback(spdylay_session *session,
-                             const uint8_t *data, size_t length, int flags,
-                             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  struct Connection *connection;
-  ssize_t rv;
-  connection = (struct Connection*)user_data;
-  connection->want_io = IO_NONE;
-  ERR_clear_error();
-  rv = SSL_write(connection->ssl, data, length);
-  if(rv < 0) {
-    int err = SSL_get_error(connection->ssl, rv);
-    if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
-      connection->want_io = (err == SSL_ERROR_WANT_READ ?
-                             WANT_READ : WANT_WRITE);
-      rv = SPDYLAY_ERR_WOULDBLOCK;
-    } else {
-      rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-    }
-  }
-  return rv;
-}
-
-/*
- * The implementation of spdylay_recv_callback type. Here we read data
- * from the network and write them in |buf|. The capacity of |buf| is
- * |length| bytes. Returns the number of bytes stored in |buf|. See
- * the documentation of spdylay_recv_callback for the details.
- */
-static ssize_t recv_callback(spdylay_session *session,
-                             uint8_t *buf, size_t length, int flags,
-                             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  struct Connection *connection;
-  ssize_t rv;
-  connection = (struct Connection*)user_data;
-  connection->want_io = IO_NONE;
-  ERR_clear_error();
-  rv = SSL_read(connection->ssl, buf, length);
-  if(rv < 0) {
-    int err = SSL_get_error(connection->ssl, rv);
-    if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
-      connection->want_io = (err == SSL_ERROR_WANT_READ ?
-                             WANT_READ : WANT_WRITE);
-      rv = SPDYLAY_ERR_WOULDBLOCK;
-    } else {
-      rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-    }
-  } else if(rv == 0) {
-    rv = SPDYLAY_ERR_EOF;
-  }
-  return rv;
-}
-
-/*
- * The implementation of spdylay_before_ctrl_send_callback type.  We
- * use this function to get stream ID of the request. This is because
- * stream ID is not known when we submit the request
- * (spdylay_submit_request).
- */
-static void before_ctrl_send_callback(spdylay_session *session,
-                                      spdylay_frame_type type,
-                                      spdylay_frame *frame,
-                                      void *user_data)
-{
-  (void)user_data;
-
-  if(type == SPDYLAY_SYN_STREAM) {
-    struct Request *req;
-    int stream_id = frame->syn_stream.stream_id;
-    req = spdylay_session_get_stream_user_data(session, stream_id);
-    if(req && req->stream_id == -1) {
-      req->stream_id = stream_id;
-      spdylay_printf("[INFO] Stream ID = %d\n", stream_id);
-    }
-  }
-}
-
-static void on_ctrl_send_callback(spdylay_session *session,
-                                  spdylay_frame_type type,
-                                  spdylay_frame *frame, void *user_data)
-{
-  (void)user_data;
-
-  char **nv;
-  const char *name = NULL;
-  int32_t stream_id;
-  size_t i;
-  switch(type) {
-  case SPDYLAY_SYN_STREAM:
-    nv = frame->syn_stream.nv;
-    name = "SYN_STREAM";
-    stream_id = frame->syn_stream.stream_id;
-    break;
-  default:
-    break;
-  }
-  if(name && spdylay_session_get_stream_user_data(session, stream_id)) {
-    spdylay_printf("[INFO] C ----------------------------> S (%s)\n", name);
-    for(i = 0; nv[i]; i += 2) {
-      spdylay_printf("       %s: %s\n", nv[i], nv[i+1]);
-    }
-  }
-}
-
-static void on_ctrl_recv_callback(spdylay_session *session,
-                                  spdylay_frame_type type,
-                                  spdylay_frame *frame, void *user_data)
-{
-  (void)user_data;
-
-  struct Request *req;
-  char **nv;
-  const char *name = NULL;
-  int32_t stream_id;
-  size_t i;
-  switch(type) {
-  case SPDYLAY_SYN_REPLY:
-    nv = frame->syn_reply.nv;
-    name = "SYN_REPLY";
-    stream_id = frame->syn_reply.stream_id;
-    break;
-  case SPDYLAY_HEADERS:
-    nv = frame->headers.nv;
-    name = "HEADERS";
-    stream_id = frame->headers.stream_id;
-    break;
-  default:
-    break;
-  }
-  if(!name) {
-    return;
-  }
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    check_gzip(req, nv);
-    spdylay_printf("[INFO] C <---------------------------- S (%s)\n", name);
-    for(i = 0; nv[i]; i += 2) {
-      spdylay_printf("       %s: %s\n", nv[i], nv[i+1]);
-    }
-  }
-}
-
-/*
- * The implementation of spdylay_on_stream_close_callback type. We use
- * this function to know the response is fully received. Since we just
- * fetch 1 resource in this program, after reception of the response,
- * we submit GOAWAY and close the session.
- */
-static void on_stream_close_callback(spdylay_session *session,
-                                     int32_t stream_id,
-                                     spdylay_status_code status_code,
-                                     void *user_data)
-{
-  (void)user_data;
-  (void)status_code;
-  struct Request *req;
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    int rv;
-    rv = spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK);
-    if(rv != 0) {
-      diec("spdylay_submit_goaway", rv);
-    }
-  }
-}
-
-#define MAX_OUTLEN 4096
-
-/*
- * The implementation of spdylay_on_data_chunk_recv_callback type. We
- * use this function to print the received response body.
- */
-static void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags,
-                                        int32_t stream_id,
-                                        const uint8_t *data, size_t len,
-                                        void *user_data)
-{
-  (void)user_data;
-  (void)flags;
-
-  struct Request *req;
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    spdylay_printf("[INFO] C <---------------------------- S (DATA)\n");
-    spdylay_printf("       %lu bytes\n", (unsigned long int)len);
-    if(req->inflater) {
-      while(len > 0) {
-        uint8_t out[MAX_OUTLEN];
-        size_t outlen = MAX_OUTLEN;
-        size_t tlen = len;
-        int rv;
-        rv = spdylay_gzip_inflate(req->inflater, out, &outlen, data, &tlen);
-        if(rv == -1) {
-          spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR);
-          break;
-        }
-        fwrite(out, 1, outlen, stdout);
-        data += tlen;
-        len -= tlen;
-      }
-    } else {
-      /* TODO add support gzip */
-      fwrite(data, 1, len, stdout);
-
-      //check if the data is correct
-      if(strcmp(RESPONSE_BODY, (char *)data) != 0)
-		killparent(parent, "\nreceived data is not the same");
-    }
-    spdylay_printf("\n");
-  }
-}
-
-/*
- * Setup callback functions. Spdylay API offers many callback
- * functions, but most of them are optional. The send_callback is
- * always required. Since we use spdylay_session_recv(), the
- * recv_callback is also required.
- */
-static void setup_spdylay_callbacks(spdylay_session_callbacks *callbacks)
-{
-  memset(callbacks, 0, sizeof(spdylay_session_callbacks));
-  callbacks->send_callback = send_callback;
-  callbacks->recv_callback = recv_callback;
-  callbacks->before_ctrl_send_callback = before_ctrl_send_callback;
-  callbacks->on_ctrl_send_callback = on_ctrl_send_callback;
-  callbacks->on_ctrl_recv_callback = on_ctrl_recv_callback;
-  callbacks->on_stream_close_callback = on_stream_close_callback;
-  callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
-}
-
-/*
- * Callback function for SSL/TLS NPN. Since this program only supports
- * SPDY protocol, if server does not offer SPDY protocol the Spdylay
- * library supports, we terminate program.
- */
-static int select_next_proto_cb(SSL* ssl,
-                                unsigned char **out, unsigned char *outlen,
-                                const unsigned char *in, unsigned int inlen,
-                                void *arg)
-{
-  (void)ssl;
-
-  int rv;
-  uint16_t *spdy_proto_version;
-  /* spdylay_select_next_protocol() selects SPDY protocol version the
-     Spdylay library supports. */
-  rv = spdylay_select_next_protocol(out, outlen, in, inlen);
-  if(rv <= 0) {
-    die("Server did not advertise spdy/2 or spdy/3 protocol.");
-  }
-  spdy_proto_version = (uint16_t*)arg;
-  *spdy_proto_version = rv;
-  return SSL_TLSEXT_ERR_OK;
-}
-
-/*
- * Setup SSL context. We pass |spdy_proto_version| to get negotiated
- * SPDY protocol version in NPN callback.
- */
-static void init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version)
-{
-  /* Disable SSLv2 and enable all workarounds for buggy servers */
-  SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
-  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
-  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
-  /* Set NPN callback */
-  SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb,
-                                   spdy_proto_version);
-}
-
-static void ssl_handshake(SSL *ssl, int fd)
-{
-  int rv;
-  if(SSL_set_fd(ssl, fd) == 0) {
-    dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
-  }
-  ERR_clear_error();
-  rv = SSL_connect(ssl);
-  if(rv <= 0) {
-    dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL));
-  }
-}
-
-/*
- * Connects to the host |host| and port |port|.  This function returns
- * the file descriptor of the client socket.
- */
-static int connect_to(const char *host, uint16_t port)
-{
-  struct addrinfo hints;
-  int fd = -1;
-  int rv;
-  char service[NI_MAXSERV];
-  struct addrinfo *res, *rp;
-  snprintf(service, sizeof(service), "%u", port);
-  memset(&hints, 0, sizeof(struct addrinfo));
-  hints.ai_family = AF_UNSPEC;
-  hints.ai_socktype = SOCK_STREAM;
-  rv = getaddrinfo(host, service, &hints, &res);
-  if(rv != 0) {
-    dief("getaddrinfo", gai_strerror(rv));
-  }
-  for(rp = res; rp; rp = rp->ai_next) {
-    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-    if(fd == -1) {
-      continue;
-    }
-    while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
-          errno == EINTR);
-    if(rv == 0) {
-      break;
-    }
-    MHD_socket_close_(fd);
-    fd = -1;
-  }
-  freeaddrinfo(res);
-  return fd;
-}
-
-static void make_non_block(int fd)
-{
-  int flags, rv;
-  while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
-  if(flags == -1) {
-    dief("fcntl", strerror(errno));
-  }
-  while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
-  if(rv == -1) {
-    dief("fcntl", strerror(errno));
-  }
-}
-
-/*
- * Setting TCP_NODELAY is not mandatory for the SPDY protocol.
- */
-static void set_tcp_nodelay(int fd)
-{
-  int val = 1;
-  int rv;
-  rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
-  if(rv == -1) {
-    dief("setsockopt", strerror(errno));
-  }
-}
-
-/*
- * Update |pollfd| based on the state of |connection|.
- */
-static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
-{
-  pollfd->events = 0;
-  if(spdylay_session_want_read(connection->session) ||
-     connection->want_io == WANT_READ) {
-    pollfd->events |= POLLIN;
-  }
-  if(spdylay_session_want_write(connection->session) ||
-     connection->want_io == WANT_WRITE) {
-    pollfd->events |= POLLOUT;
-  }
-}
-
-/*
- * Submits the request |req| to the connection |connection|.  This
- * function does not send packets; just append the request to the
- * internal queue in |connection->session|.
- */
-static void submit_request(struct Connection *connection, struct Request *req)
-{
-  int pri = 0;
-  int rv;
-  const char *nv[15];
-  /* We always use SPDY/3 style header even if the negotiated protocol
-     version is SPDY/2. The library translates the header name as
-     necessary. Make sure that the last item is NULL! */
-  nv[0] = ":method";     nv[1] = "GET";
-  nv[2] = ":path";       nv[3] = req->path;
-  nv[4] = ":version";    nv[5] = "HTTP/1.1";
-  nv[6] = ":scheme";     nv[7] = "https";
-  nv[8] = ":host";       nv[9] = req->hostport;
-  nv[10] = "accept";     nv[11] = "*/*";
-  nv[12] = "user-agent"; nv[13] = "spdylay/"SPDYLAY_VERSION;
-  nv[14] = NULL;
-  rv = spdylay_submit_request(connection->session, pri, nv, NULL, req);
-  if(rv != 0) {
-    diec("spdylay_submit_request", rv);
-  }
-}
-
-/*
- * Performs the network I/O.
- */
-static void exec_io(struct Connection *connection)
-{
-  int rv;
-  rv = spdylay_session_recv(connection->session);
-  if(rv != 0) {
-    diec("spdylay_session_recv", rv);
-  }
-  rv = spdylay_session_send(connection->session);
-  if(rv != 0) {
-    diec("spdylay_session_send", rv);
-  }
-}
-
-static void request_init(struct Request *req, const struct URI *uri)
-{
-  req->host = strcopy(uri->host, uri->hostlen);
-  req->port = uri->port;
-  req->path = strcopy(uri->path, uri->pathlen);
-  req->hostport = strcopy(uri->hostport, uri->hostportlen);
-  req->stream_id = -1;
-  req->inflater = NULL;
-}
-
-static void request_free(struct Request *req)
-{
-  free(req->host);
-  free(req->path);
-  free(req->hostport);
-  spdylay_gzip_inflate_del(req->inflater);
-}
-
-/*
- * Fetches the resource denoted by |uri|.
- */
-static void
-fetch_uri(const struct URI *uri)
-{
-  spdylay_session_callbacks callbacks;
-  int fd;
-  SSL_CTX *ssl_ctx;
-  SSL *ssl;
-  struct Request req;
-  struct Connection connection;
-  int rv;
-  nfds_t npollfds = 1;
-  struct pollfd pollfds[1];
-  uint16_t spdy_proto_version;
-
-  request_init(&req, uri);
-
-  setup_spdylay_callbacks(&callbacks);
-
-  /* Establish connection and setup SSL */
-  fd = connect_to(req.host, req.port);
-  if (-1 == fd)
-    abort ();
-  ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-  if(ssl_ctx == NULL) {
-    dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
-  }
-  init_ssl_ctx(ssl_ctx, &spdy_proto_version);
-  ssl = SSL_new(ssl_ctx);
-  if(ssl == NULL) {
-    dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
-  }
-  /* To simplify the program, we perform SSL/TLS handshake in blocking
-     I/O. */
-  ssl_handshake(ssl, fd);
-
-  connection.ssl = ssl;
-  connection.want_io = IO_NONE;
-
-  /* Here make file descriptor non-block */
-  make_non_block(fd);
-  set_tcp_nodelay(fd);
-
-  spdylay_printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version);
-  rv = spdylay_session_client_new(&connection.session, spdy_proto_version,
-                                  &callbacks, &connection);
-  if(rv != 0) {
-    diec("spdylay_session_client_new", rv);
-  }
-
-  /* Submit the HTTP request to the outbound queue. */
-  submit_request(&connection, &req);
-
-  pollfds[0].fd = fd;
-  ctl_poll(pollfds, &connection);
-
-  /* Event loop */
-  while(spdylay_session_want_read(connection.session) ||
-        spdylay_session_want_write(connection.session)) {
-    int nfds = poll(pollfds, npollfds, -1);
-    if(nfds == -1) {
-      dief("poll", strerror(errno));
-    }
-    if(pollfds[0].revents & (POLLIN | POLLOUT)) {
-      exec_io(&connection);
-    }
-    if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
-      die("Connection error");
-    }
-    ctl_poll(pollfds, &connection);
-  }
-
-  /* Resource cleanup */
-  spdylay_session_del(connection.session);
-  SSL_shutdown(ssl);
-  SSL_free(ssl);
-  SSL_CTX_free(ssl_ctx);
-  shutdown(fd, SHUT_WR);
-  MHD_socket_close_ (fd);
-  request_free(&req);
-}
-
-
-static int
-parse_uri(struct URI *res, const char *uri)
-{
-  /* We only interested in https */
-  size_t len, i, offset;
-  memset(res, 0, sizeof(struct URI));
-  len = strlen(uri);
-  if(len < 9 || memcmp("https://", uri, 8) != 0) {
-    return -1;
-  }
-  offset = 8;
-  res->host = res->hostport = &uri[offset];
-  res->hostlen = 0;
-  if(uri[offset] == '[') {
-    /* IPv6 literal address */
-    ++offset;
-    ++res->host;
-    for(i = offset; i < len; ++i) {
-      if(uri[i] == ']') {
-        res->hostlen = i-offset;
-        offset = i+1;
-        break;
-      }
-    }
-  } else {
-    const char delims[] = ":/?#";
-    for(i = offset; i < len; ++i) {
-      if(strchr(delims, uri[i]) != NULL) {
-        break;
-      }
-    }
-    res->hostlen = i-offset;
-    offset = i;
-  }
-  if(res->hostlen == 0) {
-    return -1;
-  }
-  /* Assuming https */
-  res->port = 443;
-  if(offset < len) {
-    if(uri[offset] == ':') {
-      /* port */
-      const char delims[] = "/?#";
-      int port = 0;
-      ++offset;
-      for(i = offset; i < len; ++i) {
-        if(strchr(delims, uri[i]) != NULL) {
-          break;
-        }
-        if('0' <= uri[i] && uri[i] <= '9') {
-          port *= 10;
-          port += uri[i]-'0';
-          if(port > 65535) {
-            return -1;
-          }
-        } else {
-          return -1;
-        }
-      }
-      if(port == 0) {
-        return -1;
-      }
-      offset = i;
-      res->port = port;
-    }
-  }
-  res->hostportlen = uri+offset-res->host;
-  for(i = offset; i < len; ++i) {
-    if(uri[i] == '#') {
-      break;
-    }
-  }
-  if(i-offset == 0) {
-    res->path = "/";
-    res->pathlen = 1;
-  } else {
-    res->path = &uri[offset];
-    res->pathlen = i-offset;
-  }
-  return 0;
-}
-
-
-/*****
- * end of code needed to utilize spdylay
- */
-
-
-/*****
- * start of code needed to utilize microspdy
- */
-
-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(strcmp(CLS,cls)!=0)
-	{
-		killchild(child,"wrong cls");
-	}
-
-	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)))
-		{
-			killchild(child,"inet_ntop");
-		}
-		printf("New connection from: %s:%i\n", ipstr, ntohs(addr4->sin_port));
-
-		loop = 0;
-	}
-#if HAVE_INET6
-	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)))
-		{
-			killchild(child,"inet_ntop");
-		}
-		printf("New connection from: %s:%i\n", ipstr, ntohs(addr6->sin6_port));
-
-		loop = 0;
-	}
-#endif
-	else
-	{
-		killchild(child,"wrong family");
-	}
-}
-
-/*****
- * end of code needed to utilize microspdy
- */
-
-//child process
-void
-childproc(int parent)
-{
-  struct URI uri;
-  struct sigaction act;
-  int rv;
-  char *uristr;
-
-  memset(&act, 0, sizeof(struct sigaction));
-  act.sa_handler = SIG_IGN;
-  sigaction(SIGPIPE, &act, 0);
-
-	asprintf(&uristr, "https://127.0.0.1:%i/",port);
-
-  SSL_load_error_strings();
-  SSL_library_init();
-
-  rv = parse_uri(&uri, uristr);
-  if(rv != 0) {
-    killparent(parent,"parse_uri failed");
-  }
-  fetch_uri(&uri);
-}
-
-//parent proc
-int
-parentproc(int child)
-{
-	int childstatus = 0;
-	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;
-
-	SPDY_init();
-
-	daemon = SPDY_start_daemon(port,
-								DATA_DIR "cert-and-key.pem",
-								DATA_DIR "cert-and-key.pem",
-								&new_session_callback,NULL,NULL,NULL,CLS,SPDY_DAEMON_OPTION_END);
-
-	if(NULL==daemon){
-		printf("no daemon\n");
-		return 1;
-	}
-
-	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 > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-
-		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);
-				killchild(child, "select error");
-				break;
-			case 0:
-
-				break;
-			default:
-				SPDY_run(daemon);
-
-			break;
-		}
-	}
-	while(loop && waitpid(child,&childstatus,WNOHANG) != child);
-
-	SPDY_stop_daemon(daemon);
-
-	SPDY_deinit();
-
-	if(loop)
-		return WEXITSTATUS(childstatus);
-	if(waitpid(child,&childstatus,WNOHANG) == child)
-		return WEXITSTATUS(childstatus);
-
-	kill(child,SIGKILL);
-
-	waitpid(child,&childstatus,0);
-
-	return 0;
-}
-
-int main()
-{
-	port = get_port(14123);
-	parent = getpid();
-
-   child = fork();
-   if (child == -1)
-   {
-      fprintf(stderr, "can't fork, error %d\n", errno);
-      exit(EXIT_FAILURE);
-   }
-
-   if (child == 0)
-   {
-      childproc(parent);
-      _exit(0);
-   }
-   else
-   {
-	   int ret = parentproc(child);
-      exit(ret);
-   }
-   return 1;
-}

+ 0 - 973
src/testspdy/test_notls.c

@@ -1,973 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 request_response.c
- * @brief  tests receiving request and sending response. spdycli.c (spdylay)
- * 			code is reused here
- * @author Andrey Uzunov
- * @author Tatsuhiro Tsujikawa
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include <sys/wait.h>
-#include "common.h"
-
-#define RESPONSE_BODY "<html><body><b>Hi, this is libmicrospdy!</b></body></html>"
-
-#define CLS "anything"
-
-pid_t parent;
-pid_t child;
-char *rcvbuf;
-int rcvbuf_c = 0;
-
-int session_closed_called = 0;
-
-void
-killchild(int pid, char *message)
-{
-	printf("%s\n",message);
-	kill(pid, SIGKILL);
-	exit(1);
-}
-
-void
-killparent(int pid, char *message)
-{
-	printf("%s\n",message);
-	kill(pid, SIGKILL);
-	_exit(1);
-}
-
-
-/*****
- * start of code needed to utilize spdylay
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include <spdylay/spdylay.h>
-
-enum {
-  IO_NONE,
-  WANT_READ,
-  WANT_WRITE
-};
-
-struct Connection {
-  spdylay_session *session;
-  /* WANT_READ if SSL connection needs more input; or WANT_WRITE if it
-     needs more output; or IO_NONE. This is necessary because SSL/TLS
-     re-negotiation is possible at any time. Spdylay API offers
-     similar functions like spdylay_session_want_read() and
-     spdylay_session_want_write() but they do not take into account
-     SSL connection. */
-  int want_io;
-  int fd;
-};
-
-struct Request {
-  char *host;
-  uint16_t port;
-  /* In this program, path contains query component as well. */
-  char *path;
-  /* This is the concatenation of host and port with ":" in
-     between. */
-  char *hostport;
-  /* Stream ID for this request. */
-  int32_t stream_id;
-  /* The gzip stream inflater for the compressed response. */
-  spdylay_gzip *inflater;
-};
-
-struct URI {
-  const char *host;
-  size_t hostlen;
-  uint16_t port;
-  /* In this program, path contains query component as well. */
-  const char *path;
-  size_t pathlen;
-  const char *hostport;
-  size_t hostportlen;
-};
-
-/*
- * Returns copy of string |s| with the length |len|. The returned
- * string is NULL-terminated.
- */
-static char* strcopy(const char *s, size_t len)
-{
-  char *dst;
-  dst = malloc(len+1);
-  if (NULL == dst)
-    abort ();
-  memcpy(dst, s, len);
-  dst[len] = '\0';
-  return dst;
-}
-
-/*
- * Prints error message |msg| and exit.
- */
-static void die(const char *msg)
-{
-  fprintf(stderr, "FATAL: %s\n", msg);
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Prints error containing the function name |func| and message |msg|
- * and exit.
- */
-static void dief(const char *func, const char *msg)
-{
-  fprintf(stderr, "FATAL: %s: %s\n", func, msg);
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Prints error containing the function name |func| and error code
- * |error_code| and exit.
- */
-static void diec(const char *func, int error_code)
-{
-  fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
-          spdylay_strerror(error_code));
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Check response is content-encoding: gzip. We need this because SPDY
- * client is required to support gzip.
- */
-static void check_gzip(struct Request *req, char **nv)
-{
-  int gzip = 0;
-  size_t i;
-  for(i = 0; nv[i]; i += 2) {
-    if(strcmp("content-encoding", nv[i]) == 0) {
-      gzip = strcmp("gzip", nv[i+1]) == 0;
-      break;
-    }
-  }
-  if(gzip) {
-    int rv;
-    if(req->inflater) {
-      return;
-    }
-    rv = spdylay_gzip_inflate_new(&req->inflater);
-    if(rv != 0) {
-      die("Can't allocate inflate stream.");
-    }
-  }
-}
-
-/*
- * The implementation of spdylay_send_callback type. Here we write
- * |data| with size |length| to the network and return the number of
- * bytes actually written. See the documentation of
- * spdylay_send_callback for the details.
- */
-static ssize_t send_callback(spdylay_session *session,
-                             const uint8_t *data, size_t length, int flags,
-                             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  struct Connection *connection;
-  ssize_t rv;
-  connection = (struct Connection*)user_data;
-  connection->want_io = IO_NONE;
-
-    rv = write(connection->fd,
-            data,
-            length);
-
-    if (rv < 0)
-    {
-      switch(errno)
-      {
-        case EAGAIN:
-  #if EAGAIN != EWOULDBLOCK
-        case EWOULDBLOCK:
-  #endif
-          connection->want_io = WANT_WRITE;
-          rv = SPDYLAY_ERR_WOULDBLOCK;
-          break;
-
-        default:
-          rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-      }
-    }
-  return rv;
-}
-
-/*
- * The implementation of spdylay_recv_callback type. Here we read data
- * from the network and write them in |buf|. The capacity of |buf| is
- * |length| bytes. Returns the number of bytes stored in |buf|. See
- * the documentation of spdylay_recv_callback for the details.
- */
-static ssize_t recv_callback(spdylay_session *session,
-                             uint8_t *buf, size_t length, int flags,
-                             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  struct Connection *connection;
-  ssize_t rv;
-  connection = (struct Connection*)user_data;
-  connection->want_io = IO_NONE;
-
-    rv = read(connection->fd,
-            buf,
-            length);
-
-    if (rv < 0)
-    {
-      switch(errno)
-      {
-        case EAGAIN:
-  #if EAGAIN != EWOULDBLOCK
-        case EWOULDBLOCK:
-  #endif
-          connection->want_io = WANT_READ;
-          rv = SPDYLAY_ERR_WOULDBLOCK;
-          break;
-
-        default:
-          rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-      }
-    }
-    else if(rv == 0)
-      rv = SPDYLAY_ERR_EOF;
-  return rv;
-}
-
-/*
- * The implementation of spdylay_before_ctrl_send_callback type.  We
- * use this function to get stream ID of the request. This is because
- * stream ID is not known when we submit the request
- * (spdylay_submit_request).
- */
-static void before_ctrl_send_callback(spdylay_session *session,
-                                      spdylay_frame_type type,
-                                      spdylay_frame *frame,
-                                      void *user_data)
-{
-  (void)user_data;
-
-  if(type == SPDYLAY_SYN_STREAM) {
-    struct Request *req;
-    int stream_id = frame->syn_stream.stream_id;
-    req = spdylay_session_get_stream_user_data(session, stream_id);
-    if(req && req->stream_id == -1) {
-      req->stream_id = stream_id;
-      printf("[INFO] Stream ID = %d\n", stream_id);
-    }
-  }
-}
-
-static void on_ctrl_send_callback(spdylay_session *session,
-                                  spdylay_frame_type type,
-                                  spdylay_frame *frame, void *user_data)
-{
-  (void)user_data;
-
-  char **nv;
-  const char *name = NULL;
-  int32_t stream_id;
-  size_t i;
-  switch(type) {
-  case SPDYLAY_SYN_STREAM:
-    nv = frame->syn_stream.nv;
-    name = "SYN_STREAM";
-    stream_id = frame->syn_stream.stream_id;
-    break;
-  default:
-    break;
-  }
-  if(name && spdylay_session_get_stream_user_data(session, stream_id)) {
-    printf("[INFO] C ----------------------------> S (%s)\n", name);
-    for(i = 0; nv[i]; i += 2) {
-      printf("       %s: %s\n", nv[i], nv[i+1]);
-    }
-  }
-}
-
-static void on_ctrl_recv_callback(spdylay_session *session,
-                                  spdylay_frame_type type,
-                                  spdylay_frame *frame, void *user_data)
-{
-  (void)user_data;
-
-  struct Request *req;
-  char **nv;
-  const char *name = NULL;
-  int32_t stream_id;
-  size_t i;
-  switch(type) {
-  case SPDYLAY_SYN_REPLY:
-    nv = frame->syn_reply.nv;
-    name = "SYN_REPLY";
-    stream_id = frame->syn_reply.stream_id;
-    break;
-  case SPDYLAY_HEADERS:
-    nv = frame->headers.nv;
-    name = "HEADERS";
-    stream_id = frame->headers.stream_id;
-    break;
-  default:
-    break;
-  }
-  if(!name) {
-    return;
-  }
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    check_gzip(req, nv);
-    printf("[INFO] C <---------------------------- S (%s)\n", name);
-    for(i = 0; nv[i]; i += 2) {
-      printf("       %s: %s\n", nv[i], nv[i+1]);
-    }
-  }
-}
-
-/*
- * The implementation of spdylay_on_stream_close_callback type. We use
- * this function to know the response is fully received. Since we just
- * fetch 1 resource in this program, after reception of the response,
- * we submit GOAWAY and close the session.
- */
-static void on_stream_close_callback(spdylay_session *session,
-                                     int32_t stream_id,
-                                     spdylay_status_code status_code,
-                                     void *user_data)
-{
-  (void)status_code;
-  (void)user_data;
-
-  struct Request *req;
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    int rv;
-    rv = spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK);
-    if(rv != 0) {
-      diec("spdylay_submit_goaway", rv);
-    }
-  }
-}
-
-#define MAX_OUTLEN 4096
-
-/*
- * The implementation of spdylay_on_data_chunk_recv_callback type. We
- * use this function to print the received response body.
- */
-static void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags,
-                                        int32_t stream_id,
-                                        const uint8_t *data, size_t len,
-                                        void *user_data)
-{
-  (void)flags;
-  (void)user_data;
-
-  struct Request *req;
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    printf("[INFO] C <---------------------------- S (DATA)\n");
-    printf("       %lu bytes\n", (unsigned long int)len);
-    if(req->inflater) {
-      while(len > 0) {
-        uint8_t out[MAX_OUTLEN];
-        size_t outlen = MAX_OUTLEN;
-        size_t tlen = len;
-        int rv;
-        rv = spdylay_gzip_inflate(req->inflater, out, &outlen, data, &tlen);
-        if(rv == -1) {
-          spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR);
-          break;
-        }
-        fwrite(out, 1, outlen, stdout);
-        data += tlen;
-        len -= tlen;
-      }
-    } else {
-      /* TODO add support gzip */
-      fwrite(data, 1, len, stdout);
-
-      //check if the data is correct
-      //if(strcmp(RESPONSE_BODY, data) != 0)
-		//killparent(parent, "\nreceived data is not the same");
-      if(len + rcvbuf_c > strlen(RESPONSE_BODY))
-		killparent(parent, "\nreceived data is not the same");
-
-		strcpy(rcvbuf + rcvbuf_c,(char*)data);
-		rcvbuf_c+=len;
-    }
-    printf("\n");
-  }
-}
-
-/*
- * Setup callback functions. Spdylay API offers many callback
- * functions, but most of them are optional. The send_callback is
- * always required. Since we use spdylay_session_recv(), the
- * recv_callback is also required.
- */
-static void setup_spdylay_callbacks(spdylay_session_callbacks *callbacks)
-{
-  memset(callbacks, 0, sizeof(spdylay_session_callbacks));
-  callbacks->send_callback = send_callback;
-  callbacks->recv_callback = recv_callback;
-  callbacks->before_ctrl_send_callback = before_ctrl_send_callback;
-  callbacks->on_ctrl_send_callback = on_ctrl_send_callback;
-  callbacks->on_ctrl_recv_callback = on_ctrl_recv_callback;
-  callbacks->on_stream_close_callback = on_stream_close_callback;
-  callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
-}
-
-
-/*
- * Connects to the host |host| and port |port|.  This function returns
- * the file descriptor of the client socket.
- */
-static int connect_to(const char *host, uint16_t port)
-{
-  struct addrinfo hints;
-  int fd = -1;
-  int rv;
-  char service[NI_MAXSERV];
-  struct addrinfo *res, *rp;
-  snprintf(service, sizeof(service), "%u", port);
-  memset(&hints, 0, sizeof(struct addrinfo));
-  hints.ai_family = AF_UNSPEC;
-  hints.ai_socktype = SOCK_STREAM;
-  rv = getaddrinfo(host, service, &hints, &res);
-  if(rv != 0) {
-    dief("getaddrinfo", gai_strerror(rv));
-  }
-  for(rp = res; rp; rp = rp->ai_next) {
-    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-    if(fd == -1) {
-      continue;
-    }
-    while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
-          errno == EINTR);
-    if(rv == 0) {
-      break;
-    }
-    MHD_socket_close_(fd);
-    fd = -1;
-    dief("connect", strerror(errno));
-  }
-  freeaddrinfo(res);
-  return fd;
-}
-
-static void make_non_block(int fd)
-{
-  int flags, rv;
-  while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
-  if(flags == -1) {
-    dief("fcntl1", strerror(errno));
-  }
-  while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
-  if(rv == -1) {
-    dief("fcntl2", strerror(errno));
-  }
-}
-
-/*
- * Setting TCP_NODELAY is not mandatory for the SPDY protocol.
- */
-static void set_tcp_nodelay(int fd)
-{
-  int val = 1;
-  int rv;
-  rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
-  if(rv == -1) {
-    dief("setsockopt", strerror(errno));
-  }
-}
-
-/*
- * Update |pollfd| based on the state of |connection|.
- */
-static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
-{
-  pollfd->events = 0;
-  if(spdylay_session_want_read(connection->session) ||
-     connection->want_io == WANT_READ) {
-    pollfd->events |= POLLIN;
-  }
-  if(spdylay_session_want_write(connection->session) ||
-     connection->want_io == WANT_WRITE) {
-    pollfd->events |= POLLOUT;
-  }
-}
-
-/*
- * Submits the request |req| to the connection |connection|.  This
- * function does not send packets; just append the request to the
- * internal queue in |connection->session|.
- */
-static void submit_request(struct Connection *connection, struct Request *req)
-{
-  int pri = 0;
-  int rv;
-  const char *nv[15];
-  /* We always use SPDY/3 style header even if the negotiated protocol
-     version is SPDY/2. The library translates the header name as
-     necessary. Make sure that the last item is NULL! */
-  nv[0] = ":method";     nv[1] = "GET";
-  nv[2] = ":path";       nv[3] = req->path;
-  nv[4] = ":version";    nv[5] = "HTTP/1.1";
-  nv[6] = ":scheme";     nv[7] = "https";
-  nv[8] = ":host";       nv[9] = req->hostport;
-  nv[10] = "accept";     nv[11] = "*/*";
-  nv[12] = "user-agent"; nv[13] = "spdylay/"SPDYLAY_VERSION;
-  nv[14] = NULL;
-  rv = spdylay_submit_request(connection->session, pri, nv, NULL, req);
-  if(rv != 0) {
-    diec("spdylay_submit_request", rv);
-  }
-}
-
-/*
- * Performs the network I/O.
- */
-static void exec_io(struct Connection *connection)
-{
-  int rv;
-  rv = spdylay_session_recv(connection->session);
-  if(rv != 0) {
-    diec("spdylay_session_recv", rv);
-  }
-  rv = spdylay_session_send(connection->session);
-  if(rv != 0) {
-    diec("spdylay_session_send", rv);
-  }
-}
-
-static void request_init(struct Request *req, const struct URI *uri)
-{
-  req->host = strcopy(uri->host, uri->hostlen);
-  req->port = uri->port;
-  req->path = strcopy(uri->path, uri->pathlen);
-  req->hostport = strcopy(uri->hostport, uri->hostportlen);
-  req->stream_id = -1;
-  req->inflater = NULL;
-}
-
-static void request_free(struct Request *req)
-{
-  free(req->host);
-  free(req->path);
-  free(req->hostport);
-  spdylay_gzip_inflate_del(req->inflater);
-}
-
-/*
- * Fetches the resource denoted by |uri|.
- */
-static void fetch_uri(const struct URI *uri)
-{
-  spdylay_session_callbacks callbacks;
-  int fd;
-  struct Request req;
-  struct Connection connection;
-  int rv;
-  nfds_t npollfds = 1;
-  struct pollfd pollfds[1];
-  uint16_t spdy_proto_version = 3;
-
-  request_init(&req, uri);
-
-  setup_spdylay_callbacks(&callbacks);
-
-  /* Establish connection and setup SSL */
-  fd = connect_to(req.host, req.port);
-  if (-1 == fd)
-    abort ();
-
-  connection.fd = fd;
-  connection.want_io = IO_NONE;
-
-  /* Here make file descriptor non-block */
-  make_non_block(fd);
-  set_tcp_nodelay(fd);
-
-  printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version);
-  rv = spdylay_session_client_new(&connection.session, spdy_proto_version,
-                                  &callbacks, &connection);
-  if(rv != 0) {
-    diec("spdylay_session_client_new", rv);
-  }
-
-  /* Submit the HTTP request to the outbound queue. */
-  submit_request(&connection, &req);
-
-  pollfds[0].fd = fd;
-  ctl_poll(pollfds, &connection);
-
-  /* Event loop */
-  while(spdylay_session_want_read(connection.session) ||
-        spdylay_session_want_write(connection.session)) {
-    int nfds = poll(pollfds, npollfds, -1);
-    if(nfds == -1) {
-      dief("poll", strerror(errno));
-    }
-    if(pollfds[0].revents & (POLLIN | POLLOUT)) {
-      exec_io(&connection);
-    }
-    if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
-      die("Connection error");
-    }
-    ctl_poll(pollfds, &connection);
-  }
-
-  /* Resource cleanup */
-  spdylay_session_del(connection.session);
-  shutdown(fd, SHUT_WR);
-  MHD_socket_close_(fd);
-  request_free(&req);
-}
-
-static int parse_uri(struct URI *res, const char *uri)
-{
-  /* We only interested in https */
-  size_t len, i, offset;
-  memset(res, 0, sizeof(struct URI));
-  len = strlen(uri);
-  if(len < 9 || memcmp("https://", uri, 8) != 0) {
-    return -1;
-  }
-  offset = 8;
-  res->host = res->hostport = &uri[offset];
-  res->hostlen = 0;
-  if(uri[offset] == '[') {
-    /* IPv6 literal address */
-    ++offset;
-    ++res->host;
-    for(i = offset; i < len; ++i) {
-      if(uri[i] == ']') {
-        res->hostlen = i-offset;
-        offset = i+1;
-        break;
-      }
-    }
-  } else {
-    const char delims[] = ":/?#";
-    for(i = offset; i < len; ++i) {
-      if(strchr(delims, uri[i]) != NULL) {
-        break;
-      }
-    }
-    res->hostlen = i-offset;
-    offset = i;
-  }
-  if(res->hostlen == 0) {
-    return -1;
-  }
-  /* Assuming https */
-  res->port = 443;
-  if(offset < len) {
-    if(uri[offset] == ':') {
-      /* port */
-      const char delims[] = "/?#";
-      int port = 0;
-      ++offset;
-      for(i = offset; i < len; ++i) {
-        if(strchr(delims, uri[i]) != NULL) {
-          break;
-        }
-        if('0' <= uri[i] && uri[i] <= '9') {
-          port *= 10;
-          port += uri[i]-'0';
-          if(port > 65535) {
-            return -1;
-          }
-        } else {
-          return -1;
-        }
-      }
-      if(port == 0) {
-        return -1;
-      }
-      offset = i;
-      res->port = port;
-    }
-  }
-  res->hostportlen = uri+offset-res->host;
-  for(i = offset; i < len; ++i) {
-    if(uri[i] == '#') {
-      break;
-    }
-  }
-  if(i-offset == 0) {
-    res->path = "/";
-    res->pathlen = 1;
-  } else {
-    res->path = &uri[offset];
-    res->pathlen = i-offset;
-  }
-  return 0;
-}
-
-
-/*****
- * end of code needed to utilize spdylay
- */
-
-
-/*****
- * start of code needed to utilize microspdy
- */
-
-
-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,
-            bool more)
-{
-	(void)cls;
-	(void)request;
-	(void)priority;
-	(void)host;
-	(void)scheme;
-	(void)headers;
-	(void)method;
-	(void)version;
-	(void)more;
-
-	struct SPDY_Response *response=NULL;
-
-	if(strcmp(CLS,cls)!=0)
-	{
-		killchild(child,"wrong cls");
-	}
-
-	response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,RESPONSE_BODY,strlen(RESPONSE_BODY));
-
-	if(NULL==response){
-		fprintf(stdout,"no response obj\n");
-		exit(3);
-	}
-
-	if(SPDY_queue_response(request,response,true,false,NULL,(void*)strdup(path))!=SPDY_YES)
-	{
-		fprintf(stdout,"queue\n");
-		exit(4);
-	}
-}
-
-void
-session_closed_handler (void *cls,
-						struct SPDY_Session * session,
-						int by_client)
-{
-	printf("session_closed_handler called\n");
-
-	if(strcmp(CLS,cls)!=0)
-	{
-		killchild(child,"wrong cls");
-	}
-
-	if(SPDY_YES != by_client)
-	{
-		//killchild(child,"wrong by_client");
-		printf("session closed by server\n");
-	}
-	else
-	{
-		printf("session closed by client\n");
-	}
-
-	if(NULL == session)
-	{
-		killchild(child,"session is NULL");
-	}
-
-	session_closed_called = 1;
-}
-
-
-/*****
- * end of code needed to utilize microspdy
- */
-
-//child process
-void
-childproc(int port)
-{
-  struct URI uri;
-  struct sigaction act;
-  int rv;
-  char *uristr;
-
-  memset(&act, 0, sizeof(struct sigaction));
-  act.sa_handler = SIG_IGN;
-  sigaction(SIGPIPE, &act, 0);
-
-	usleep(10000);
-	asprintf(&uristr, "https://127.0.0.1:%i/",port);
-	if(NULL == (rcvbuf = malloc(strlen(RESPONSE_BODY)+1)))
-		killparent(parent,"no memory");
-
-  rv = parse_uri(&uri, uristr);
-  if(rv != 0) {
-    killparent(parent,"parse_uri failed");
-  }
-  fetch_uri(&uri);
-
-  if(strcmp(rcvbuf, RESPONSE_BODY))
-    killparent(parent,"received data is different");
-}
-
-//parent proc
-int
-parentproc( int port)
-{
-	int childstatus;
-	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;
-
-	SPDY_init();
-
-	daemon = SPDY_start_daemon(port,
-								NULL,
-								NULL,
-								NULL,&session_closed_handler,&standard_request_handler,NULL,CLS,
-                SPDY_DAEMON_OPTION_IO_SUBSYSTEM, SPDY_IO_SUBSYSTEM_RAW,
-                SPDY_DAEMON_OPTION_FLAGS, SPDY_DAEMON_FLAG_NO_DELAY,
-                SPDY_DAEMON_OPTION_END);
-
-	if(NULL==daemon){
-		printf("no daemon\n");
-		return 1;
-	}
-
-	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 > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-
-		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);
-				killchild(child, "select error");
-				break;
-			case 0:
-
-				break;
-			default:
-				SPDY_run(daemon);
-
-			break;
-		}
-	}
-	while(waitpid(child,&childstatus,WNOHANG) != child);
-
-	//give chance to the client to close socket and handle this in run
-	usleep(100000);
-	SPDY_run(daemon);
-
-	SPDY_stop_daemon(daemon);
-
-	SPDY_deinit();
-
-	return WEXITSTATUS(childstatus);
-}
-
-int main()
-{
-	int port = get_port(12123);
-	parent = getpid();
-
-   child = fork();
-   if (child == -1)
-   {
-      fprintf(stderr, "can't fork, error %d\n", errno);
-      exit(EXIT_FAILURE);
-   }
-
-   if (child == 0)
-   {
-      childproc(port);
-      _exit(0);
-   }
-   else
-   {
-	   int ret = parentproc(port);
-	   if(1 == session_closed_called && 0 == ret)
-      exit(0);
-      else
-      exit(ret ? ret : 21);
-   }
-   return 1;
-}

+ 0 - 255
src/testspdy/test_proxies.c

@@ -1,255 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 test_proxies.c
- * @brief  test curl > mhd2spdylay > microspdy2http > mhd
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include "common.h"
-#include <sys/wait.h>
-#include <stdio.h>   /* printf, stderr, fprintf */
-#include <sys/types.h> /* pid_t */
-#include <unistd.h>  /* _exit, fork */
-#include <stdlib.h>  /* exit */
-#include <errno.h>   /* errno */
-#include <sys/wait.h> /* pid_t */
-#include "common.h"
-
-#ifdef _WIN32
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN 1
-#endif /* !WIN32_LEAN_AND_MEAN */
-#include <windows.h>
-#endif
-
-#define EXPECTED_BODY "<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>"
-
-
-pid_t parent;
-	pid_t child_mhd;
-	pid_t child_spdy2http;
-	pid_t child_mhd2spdy;
-	pid_t child_curl;
-
-	uint16_t mhd_port;
-	uint16_t spdy2http_port;
-	uint16_t mhd2spdy_port;
-
-void
-killproc(int pid, const char *message)
-{
-	printf("%s\nkilling %i\n",message,pid);
-	kill(pid, SIGKILL);
-}
-
-
-void killchildren()
-{
-    if(0 != child_mhd)
-      killproc(child_mhd,"kill mhd\n");
-    if(0 != child_spdy2http)
-      killproc(child_spdy2http,"kill spdy2http\n");
-    if(0 != child_mhd2spdy)
-      killproc(child_mhd2spdy,"kill mhd2spdy\n");
-    if(0 != child_curl)
-      killproc(child_curl,"kill curl\n");
-}
-
-pid_t au_fork()
-{
-  pid_t child = fork();
-	if (child == -1)
-	{
-    killchildren();
-
-		killproc(parent,"fork failed\n");
-	}
-
-	return child;
-}
-
-
-int main()
-{
-  //pid_t child;
-	int childstatus;
-	pid_t wpid;
-
-	parent = getpid();
-	mhd_port = get_port(4000);
-	spdy2http_port = get_port(4100);
-	mhd2spdy_port = get_port(4200);
-
-	child_mhd = au_fork();
-	if (child_mhd == 0)
-	{
-    //run MHD
-		pid_t devnull;
-    char *port_s;
-
-		close(1);
-		devnull = open("/dev/null", O_WRONLY);
-                if (-1 == devnull)
-                  abort();
-		if (1 != devnull)
-		{
-			dup2(devnull, 1);
-			close(devnull);
-		}
-    asprintf(&port_s, "%i", mhd_port);
-		execlp ("../examples/minimal_example", "minimal_example", port_s, NULL);
-		fprintf(stderr, "executing mhd failed\nFor this test 'make' must be run before 'make check'!\n");
-    //killchildren();
-    _exit(1);
-	}
-
-
-	child_spdy2http = au_fork();
-	if (child_spdy2http == 0)
-	{
-    //run spdy2http
-		pid_t devnull;
-    char *port_s;
-    //char *url;
-
-		close(1);
-		devnull = open("/dev/null", O_WRONLY);
-                if (-1 == devnull)
-                  abort();
-		if (1 != devnull)
-		{
-			dup2(devnull, 1);
-			close(devnull);
-		}
-    //asprintf(&url, "127.0.0.1:%i", mhd_port);
-    asprintf(&port_s, "%i", spdy2http_port);
-    sleep(1);
-		execlp ("../spdy2http/microspdy2http", "microspdy2http", "-v4rtT", "10", "-p", port_s, NULL);
-		fprintf(stderr, "executing microspdy2http failed\n");
-    //killchildren();
-    _exit(1);
-	}
-
-	child_mhd2spdy = au_fork();
-	if (child_mhd2spdy == 0)
-	{
-    //run MHD2sdpy
-		pid_t devnull;
-    char *port_s;
-    char *url;
-
-		close(1);
-		devnull = open("/dev/null", O_WRONLY);
-                if (-1 == devnull)
-                  abort();
-		if (1 != devnull)
-		{
-			dup2(devnull, 1);
-			close(devnull);
-		}
-    asprintf(&url, "http://127.0.0.1:%i", spdy2http_port);
-    asprintf(&port_s, "%i", mhd2spdy_port);
-    sleep(2);
-		execlp ("../examples/mhd2spdy", "mhd2spdy", "-vosb", url, "-p", port_s, NULL);
-		fprintf(stderr, "executing mhd2spdy failed\n");
-    //killchildren();
-    _exit(1);
-	}
-
-	child_curl = au_fork();
-	if (child_curl == 0)
-	{
-    //run curl
-    FILE *p;
-		pid_t devnull;
-		char *cmd;
-    unsigned int i;
-    int retc;
-    char buf[strlen(EXPECTED_BODY) + 1];
-
-		close(1);
-		devnull = open("/dev/null", O_WRONLY);
-                if (-1 == devnull)
-                  abort ();
-		if (1 != devnull)
-		{
-			dup2(devnull, 1);
-			close(devnull);
-		}
-
-		asprintf (&cmd, "curl --proxy http://127.0.0.1:%i http://127.0.0.1:%i/", mhd2spdy_port, mhd_port);
-    sleep(3);
-    p = popen(cmd, "r");
-    if (p != NULL)
-    {
-      for (i = 0; i < strlen(EXPECTED_BODY) && !feof(p); i++)
-      {
-          retc = fgetc (p);
-          if (EOF == retc)
-            abort (); /* what did feof(p) do there!? */
-          buf[i] = (char) retc;
-      }
-
-      pclose(p);
-      buf[i] = 0;
-      _exit(strcmp(EXPECTED_BODY, buf));
-    }
-		fprintf(stderr, "executing curl failed\n");
-    //killchildren();
-    _exit(1);
-	}
-
-  do
-  {
-    wpid = waitpid(child_mhd,&childstatus,WNOHANG);
-    if(wpid == child_mhd)
-    {
-      fprintf(stderr, "mhd died unexpectedly\n");
-      killchildren();
-      return 1;
-    }
-
-    wpid = waitpid(child_spdy2http,&childstatus,WNOHANG);
-    if(wpid == child_spdy2http)
-    {
-      fprintf(stderr, "spdy2http died unexpectedly\n");
-      killchildren();
-      return 1;
-    }
-
-    wpid = waitpid(child_mhd2spdy,&childstatus,WNOHANG);
-    if(wpid == child_mhd2spdy)
-    {
-      fprintf(stderr, "mhd2spdy died unexpectedly\n");
-      killchildren();
-      return 1;
-    }
-
-    if(waitpid(child_curl,&childstatus,WNOHANG) == child_curl)
-    {
-      killchildren();
-      return WEXITSTATUS(childstatus);
-    }
-    sleep(1);
-  }
-	while(true);
-}

+ 0 - 1029
src/testspdy/test_request_response.c

@@ -1,1029 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 test_request_response.c
- * @brief  tests receiving request and sending response. spdycli.c (spdylay)
- * 			code is reused here
- * @author Andrey Uzunov
- * @author Tatsuhiro Tsujikawa
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include <sys/wait.h>
-#include "common.h"
-
-#define RESPONSE_BODY "<html><body><b>Hi, this is libmicrospdy!</b></body></html>"
-
-#define CLS "anything"
-
-pid_t parent;
-pid_t child;
-char *rcvbuf;
-int rcvbuf_c = 0;
-
-int session_closed_called = 0;
-
-void
-killchild(int pid, char *message)
-{
-	printf("%s\n",message);
-	kill(pid, SIGKILL);
-	exit(1);
-}
-
-void
-killparent(int pid, char *message)
-{
-	printf("%s\n",message);
-	kill(pid, SIGKILL);
-	_exit(1);
-}
-
-
-/*****
- * start of code needed to utilize spdylay
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include <spdylay/spdylay.h>
-
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-
-enum {
-  IO_NONE,
-  WANT_READ,
-  WANT_WRITE
-};
-
-struct Connection {
-  SSL *ssl;
-  spdylay_session *session;
-  /* WANT_READ if SSL connection needs more input; or WANT_WRITE if it
-     needs more output; or IO_NONE. This is necessary because SSL/TLS
-     re-negotiation is possible at any time. Spdylay API offers
-     similar functions like spdylay_session_want_read() and
-     spdylay_session_want_write() but they do not take into account
-     SSL connection. */
-  int want_io;
-};
-
-struct Request {
-  char *host;
-  uint16_t port;
-  /* In this program, path contains query component as well. */
-  char *path;
-  /* This is the concatenation of host and port with ":" in
-     between. */
-  char *hostport;
-  /* Stream ID for this request. */
-  int32_t stream_id;
-  /* The gzip stream inflater for the compressed response. */
-  spdylay_gzip *inflater;
-};
-
-struct URI {
-  const char *host;
-  size_t hostlen;
-  uint16_t port;
-  /* In this program, path contains query component as well. */
-  const char *path;
-  size_t pathlen;
-  const char *hostport;
-  size_t hostportlen;
-};
-
-/*
- * Returns copy of string |s| with the length |len|. The returned
- * string is NULL-terminated.
- */
-static char* strcopy(const char *s, size_t len)
-{
-  char *dst;
-  dst = malloc(len+1);
-  if (NULL == dst)
-    abort ();
-  memcpy(dst, s, len);
-  dst[len] = '\0';
-  return dst;
-}
-
-/*
- * Prints error message |msg| and exit.
- */
-static void die(const char *msg)
-{
-  fprintf(stderr, "FATAL: %s\n", msg);
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Prints error containing the function name |func| and message |msg|
- * and exit.
- */
-static void dief(const char *func, const char *msg)
-{
-  fprintf(stderr, "FATAL: %s: %s\n", func, msg);
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Prints error containing the function name |func| and error code
- * |error_code| and exit.
- */
-static void diec(const char *func, int error_code)
-{
-  fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
-          spdylay_strerror(error_code));
-  exit(EXIT_FAILURE);
-}
-
-/*
- * Check response is content-encoding: gzip. We need this because SPDY
- * client is required to support gzip.
- */
-static void check_gzip(struct Request *req, char **nv)
-{
-  int gzip = 0;
-  size_t i;
-  for(i = 0; nv[i]; i += 2) {
-    if(strcmp("content-encoding", nv[i]) == 0) {
-      gzip = strcmp("gzip", nv[i+1]) == 0;
-      break;
-    }
-  }
-  if(gzip) {
-    int rv;
-    if(req->inflater) {
-      return;
-    }
-    rv = spdylay_gzip_inflate_new(&req->inflater);
-    if(rv != 0) {
-      die("Can't allocate inflate stream.");
-    }
-  }
-}
-
-/*
- * The implementation of spdylay_send_callback type. Here we write
- * |data| with size |length| to the network and return the number of
- * bytes actually written. See the documentation of
- * spdylay_send_callback for the details.
- */
-static ssize_t send_callback(spdylay_session *session,
-                             const uint8_t *data, size_t length, int flags,
-                             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  struct Connection *connection;
-  ssize_t rv;
-  connection = (struct Connection*)user_data;
-  connection->want_io = IO_NONE;
-  ERR_clear_error();
-  rv = SSL_write(connection->ssl, data, length);
-  if(rv < 0) {
-    int err = SSL_get_error(connection->ssl, rv);
-    if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
-      connection->want_io = (err == SSL_ERROR_WANT_READ ?
-                             WANT_READ : WANT_WRITE);
-      rv = SPDYLAY_ERR_WOULDBLOCK;
-    } else {
-      rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-    }
-  }
-  return rv;
-}
-
-/*
- * The implementation of spdylay_recv_callback type. Here we read data
- * from the network and write them in |buf|. The capacity of |buf| is
- * |length| bytes. Returns the number of bytes stored in |buf|. See
- * the documentation of spdylay_recv_callback for the details.
- */
-static ssize_t recv_callback(spdylay_session *session,
-                             uint8_t *buf, size_t length, int flags,
-                             void *user_data)
-{
-  (void)session;
-  (void)flags;
-
-  struct Connection *connection;
-  ssize_t rv;
-  connection = (struct Connection*)user_data;
-  connection->want_io = IO_NONE;
-  ERR_clear_error();
-  rv = SSL_read(connection->ssl, buf, length);
-  if(rv < 0) {
-    int err = SSL_get_error(connection->ssl, rv);
-    if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
-      connection->want_io = (err == SSL_ERROR_WANT_READ ?
-                             WANT_READ : WANT_WRITE);
-      rv = SPDYLAY_ERR_WOULDBLOCK;
-    } else {
-      rv = SPDYLAY_ERR_CALLBACK_FAILURE;
-    }
-  } else if(rv == 0) {
-    rv = SPDYLAY_ERR_EOF;
-  }
-  return rv;
-}
-
-/*
- * The implementation of spdylay_before_ctrl_send_callback type.  We
- * use this function to get stream ID of the request. This is because
- * stream ID is not known when we submit the request
- * (spdylay_submit_request).
- */
-static void before_ctrl_send_callback(spdylay_session *session,
-                                      spdylay_frame_type type,
-                                      spdylay_frame *frame,
-                                      void *user_data)
-{
-  (void)user_data;
-
-  if(type == SPDYLAY_SYN_STREAM) {
-    struct Request *req;
-    int stream_id = frame->syn_stream.stream_id;
-    req = spdylay_session_get_stream_user_data(session, stream_id);
-    if(req && req->stream_id == -1) {
-      req->stream_id = stream_id;
-      printf("[INFO] Stream ID = %d\n", stream_id);
-    }
-  }
-}
-
-static void on_ctrl_send_callback(spdylay_session *session,
-                                  spdylay_frame_type type,
-                                  spdylay_frame *frame, void *user_data)
-{
-  (void)user_data;
-
-  char **nv;
-  const char *name = NULL;
-  int32_t stream_id;
-  size_t i;
-  switch(type) {
-  case SPDYLAY_SYN_STREAM:
-    nv = frame->syn_stream.nv;
-    name = "SYN_STREAM";
-    stream_id = frame->syn_stream.stream_id;
-    break;
-  default:
-    break;
-  }
-  if(name && spdylay_session_get_stream_user_data(session, stream_id)) {
-    printf("[INFO] C ----------------------------> S (%s)\n", name);
-    for(i = 0; nv[i]; i += 2) {
-      printf("       %s: %s\n", nv[i], nv[i+1]);
-    }
-  }
-}
-
-static void on_ctrl_recv_callback(spdylay_session *session,
-                                  spdylay_frame_type type,
-                                  spdylay_frame *frame, void *user_data)
-{
-  (void)user_data;
-
-  struct Request *req;
-  char **nv;
-  const char *name = NULL;
-  int32_t stream_id;
-  size_t i;
-  switch(type) {
-  case SPDYLAY_SYN_REPLY:
-    nv = frame->syn_reply.nv;
-    name = "SYN_REPLY";
-    stream_id = frame->syn_reply.stream_id;
-    break;
-  case SPDYLAY_HEADERS:
-    nv = frame->headers.nv;
-    name = "HEADERS";
-    stream_id = frame->headers.stream_id;
-    break;
-  default:
-    break;
-  }
-  if(!name) {
-    return;
-  }
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    check_gzip(req, nv);
-    printf("[INFO] C <---------------------------- S (%s)\n", name);
-    for(i = 0; nv[i]; i += 2) {
-      printf("       %s: %s\n", nv[i], nv[i+1]);
-    }
-  }
-}
-
-/*
- * The implementation of spdylay_on_stream_close_callback type. We use
- * this function to know the response is fully received. Since we just
- * fetch 1 resource in this program, after reception of the response,
- * we submit GOAWAY and close the session.
- */
-static void on_stream_close_callback(spdylay_session *session,
-                                     int32_t stream_id,
-                                     spdylay_status_code status_code,
-                                     void *user_data)
-{
-  (void)user_data;
-  (void)status_code;
-
-  struct Request *req;
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    int rv;
-    rv = spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK);
-    if(rv != 0) {
-      diec("spdylay_submit_goaway", rv);
-    }
-  }
-}
-
-#define MAX_OUTLEN 4096
-
-/*
- * The implementation of spdylay_on_data_chunk_recv_callback type. We
- * use this function to print the received response body.
- */
-static void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags,
-                                        int32_t stream_id,
-                                        const uint8_t *data, size_t len,
-                                        void *user_data)
-{
-  (void)user_data;
-  (void)flags;
-
-  struct Request *req;
-  req = spdylay_session_get_stream_user_data(session, stream_id);
-  if(req) {
-    printf("[INFO] C <---------------------------- S (DATA)\n");
-    printf("       %lu bytes\n", (unsigned long int)len);
-    if(req->inflater) {
-      while(len > 0) {
-        uint8_t out[MAX_OUTLEN];
-        size_t outlen = MAX_OUTLEN;
-        size_t tlen = len;
-        int rv;
-        rv = spdylay_gzip_inflate(req->inflater, out, &outlen, data, &tlen);
-        if(rv == -1) {
-          spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR);
-          break;
-        }
-        fwrite(out, 1, outlen, stdout);
-        data += tlen;
-        len -= tlen;
-      }
-    } else {
-      /* TODO add support gzip */
-      fwrite(data, 1, len, stdout);
-
-      //check if the data is correct
-      //if(strcmp(RESPONSE_BODY, data) != 0)
-		//killparent(parent, "\nreceived data is not the same");
-      if(len + rcvbuf_c > strlen(RESPONSE_BODY))
-		killparent(parent, "\nreceived data is not the same");
-
-		strcpy(rcvbuf + rcvbuf_c,(char*)data);
-		rcvbuf_c+=len;
-    }
-    printf("\n");
-  }
-}
-
-/*
- * Setup callback functions. Spdylay API offers many callback
- * functions, but most of them are optional. The send_callback is
- * always required. Since we use spdylay_session_recv(), the
- * recv_callback is also required.
- */
-static void setup_spdylay_callbacks(spdylay_session_callbacks *callbacks)
-{
-  memset(callbacks, 0, sizeof(spdylay_session_callbacks));
-  callbacks->send_callback = send_callback;
-  callbacks->recv_callback = recv_callback;
-  callbacks->before_ctrl_send_callback = before_ctrl_send_callback;
-  callbacks->on_ctrl_send_callback = on_ctrl_send_callback;
-  callbacks->on_ctrl_recv_callback = on_ctrl_recv_callback;
-  callbacks->on_stream_close_callback = on_stream_close_callback;
-  callbacks->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
-}
-
-/*
- * Callback function for SSL/TLS NPN. Since this program only supports
- * SPDY protocol, if server does not offer SPDY protocol the Spdylay
- * library supports, we terminate program.
- */
-static int select_next_proto_cb(SSL* ssl,
-                                unsigned char **out, unsigned char *outlen,
-                                const unsigned char *in, unsigned int inlen,
-                                void *arg)
-{
-  (void)ssl;
-
-  int rv;
-  uint16_t *spdy_proto_version;
-  /* spdylay_select_next_protocol() selects SPDY protocol version the
-     Spdylay library supports. */
-  rv = spdylay_select_next_protocol(out, outlen, in, inlen);
-  if(rv <= 0) {
-    die("Server did not advertise spdy/2 or spdy/3 protocol.");
-  }
-  spdy_proto_version = (uint16_t*)arg;
-  *spdy_proto_version = rv;
-  return SSL_TLSEXT_ERR_OK;
-}
-
-/*
- * Setup SSL context. We pass |spdy_proto_version| to get negotiated
- * SPDY protocol version in NPN callback.
- */
-static void init_ssl_ctx(SSL_CTX *ssl_ctx, uint16_t *spdy_proto_version)
-{
-  /* Disable SSLv2 and enable all workarounds for buggy servers */
-  SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
-  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
-  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
-  /* Set NPN callback */
-  SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb,
-                                   spdy_proto_version);
-}
-
-static void ssl_handshake(SSL *ssl, int fd)
-{
-  int rv;
-  if(SSL_set_fd(ssl, fd) == 0) {
-    dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
-  }
-  ERR_clear_error();
-  rv = SSL_connect(ssl);
-  if(rv <= 0) {
-    dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL));
-  }
-}
-
-/*
- * Connects to the host |host| and port |port|.  This function returns
- * the file descriptor of the client socket.
- */
-static int connect_to(const char *host, uint16_t port)
-{
-  struct addrinfo hints;
-  int fd = -1;
-  int rv;
-  char service[NI_MAXSERV];
-  struct addrinfo *res, *rp;
-  snprintf(service, sizeof(service), "%u", port);
-  memset(&hints, 0, sizeof(struct addrinfo));
-  hints.ai_family = AF_UNSPEC;
-  hints.ai_socktype = SOCK_STREAM;
-  rv = getaddrinfo(host, service, &hints, &res);
-  if(rv != 0) {
-    dief("getaddrinfo", gai_strerror(rv));
-  }
-  for(rp = res; rp; rp = rp->ai_next) {
-    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-    if(fd == -1) {
-      continue;
-    }
-    while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
-          errno == EINTR);
-    if(rv == 0) {
-      break;
-    }
-    MHD_socket_close_(fd);
-    fd = -1;
-  }
-  freeaddrinfo(res);
-  return fd;
-}
-
-static void make_non_block(int fd)
-{
-  int flags, rv;
-  while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
-  if(flags == -1) {
-    dief("fcntl", strerror(errno));
-  }
-  while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
-  if(rv == -1) {
-    dief("fcntl", strerror(errno));
-  }
-}
-
-/*
- * Setting TCP_NODELAY is not mandatory for the SPDY protocol.
- */
-static void set_tcp_nodelay(int fd)
-{
-  int val = 1;
-  int rv;
-  rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
-  if(rv == -1) {
-    dief("setsockopt", strerror(errno));
-  }
-}
-
-/*
- * Update |pollfd| based on the state of |connection|.
- */
-static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
-{
-  pollfd->events = 0;
-  if(spdylay_session_want_read(connection->session) ||
-     connection->want_io == WANT_READ) {
-    pollfd->events |= POLLIN;
-  }
-  if(spdylay_session_want_write(connection->session) ||
-     connection->want_io == WANT_WRITE) {
-    pollfd->events |= POLLOUT;
-  }
-}
-
-/*
- * Submits the request |req| to the connection |connection|.  This
- * function does not send packets; just append the request to the
- * internal queue in |connection->session|.
- */
-static void submit_request(struct Connection *connection, struct Request *req)
-{
-  int pri = 0;
-  int rv;
-  const char *nv[15];
-  /* We always use SPDY/3 style header even if the negotiated protocol
-     version is SPDY/2. The library translates the header name as
-     necessary. Make sure that the last item is NULL! */
-  nv[0] = ":method";     nv[1] = "GET";
-  nv[2] = ":path";       nv[3] = req->path;
-  nv[4] = ":version";    nv[5] = "HTTP/1.1";
-  nv[6] = ":scheme";     nv[7] = "https";
-  nv[8] = ":host";       nv[9] = req->hostport;
-  nv[10] = "accept";     nv[11] = "*/*";
-  nv[12] = "user-agent"; nv[13] = "spdylay/"SPDYLAY_VERSION;
-  nv[14] = NULL;
-  rv = spdylay_submit_request(connection->session, pri, nv, NULL, req);
-  if(rv != 0) {
-    diec("spdylay_submit_request", rv);
-  }
-}
-
-/*
- * Performs the network I/O.
- */
-static void exec_io(struct Connection *connection)
-{
-  int rv;
-  rv = spdylay_session_recv(connection->session);
-  if(rv != 0) {
-    diec("spdylay_session_recv", rv);
-  }
-  rv = spdylay_session_send(connection->session);
-  if(rv != 0) {
-    diec("spdylay_session_send", rv);
-  }
-}
-
-static void request_init(struct Request *req, const struct URI *uri)
-{
-  req->host = strcopy(uri->host, uri->hostlen);
-  req->port = uri->port;
-  req->path = strcopy(uri->path, uri->pathlen);
-  req->hostport = strcopy(uri->hostport, uri->hostportlen);
-  req->stream_id = -1;
-  req->inflater = NULL;
-}
-
-static void request_free(struct Request *req)
-{
-  free(req->host);
-  free(req->path);
-  free(req->hostport);
-  spdylay_gzip_inflate_del(req->inflater);
-}
-
-/*
- * Fetches the resource denoted by |uri|.
- */
-static void fetch_uri(const struct URI *uri)
-{
-  spdylay_session_callbacks callbacks;
-  int fd;
-  SSL_CTX *ssl_ctx;
-  SSL *ssl;
-  struct Request req;
-  struct Connection connection;
-  int rv;
-  nfds_t npollfds = 1;
-  struct pollfd pollfds[1];
-  uint16_t spdy_proto_version;
-
-  request_init(&req, uri);
-
-  setup_spdylay_callbacks(&callbacks);
-
-  /* Establish connection and setup SSL */
-  fd = connect_to(req.host, req.port);
-  if (-1 == fd)
-    abort ();
-  ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-  if(ssl_ctx == NULL) {
-    dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
-  }
-  init_ssl_ctx(ssl_ctx, &spdy_proto_version);
-  ssl = SSL_new(ssl_ctx);
-  if(ssl == NULL) {
-    dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
-  }
-  /* To simplify the program, we perform SSL/TLS handshake in blocking
-     I/O. */
-  ssl_handshake(ssl, fd);
-
-  connection.ssl = ssl;
-  connection.want_io = IO_NONE;
-
-  /* Here make file descriptor non-block */
-  make_non_block(fd);
-  set_tcp_nodelay(fd);
-
-  printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version);
-  rv = spdylay_session_client_new(&connection.session, spdy_proto_version,
-                                  &callbacks, &connection);
-  if(rv != 0) {
-    diec("spdylay_session_client_new", rv);
-  }
-
-  /* Submit the HTTP request to the outbound queue. */
-  submit_request(&connection, &req);
-
-  pollfds[0].fd = fd;
-  ctl_poll(pollfds, &connection);
-
-  /* Event loop */
-  while(spdylay_session_want_read(connection.session) ||
-        spdylay_session_want_write(connection.session)) {
-    int nfds = poll(pollfds, npollfds, -1);
-    if(nfds == -1) {
-      dief("poll", strerror(errno));
-    }
-    if(pollfds[0].revents & (POLLIN | POLLOUT)) {
-      exec_io(&connection);
-    }
-    if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
-      die("Connection error");
-    }
-    ctl_poll(pollfds, &connection);
-  }
-
-  /* Resource cleanup */
-  spdylay_session_del(connection.session);
-  SSL_shutdown(ssl);
-  SSL_free(ssl);
-  SSL_CTX_free(ssl_ctx);
-  shutdown(fd, SHUT_WR);
-  MHD_socket_close_(fd);
-  request_free(&req);
-}
-
-static int parse_uri(struct URI *res, const char *uri)
-{
-  /* We only interested in https */
-  size_t len, i, offset;
-  memset(res, 0, sizeof(struct URI));
-  len = strlen(uri);
-  if(len < 9 || memcmp("https://", uri, 8) != 0) {
-    return -1;
-  }
-  offset = 8;
-  res->host = res->hostport = &uri[offset];
-  res->hostlen = 0;
-  if(uri[offset] == '[') {
-    /* IPv6 literal address */
-    ++offset;
-    ++res->host;
-    for(i = offset; i < len; ++i) {
-      if(uri[i] == ']') {
-        res->hostlen = i-offset;
-        offset = i+1;
-        break;
-      }
-    }
-  } else {
-    const char delims[] = ":/?#";
-    for(i = offset; i < len; ++i) {
-      if(strchr(delims, uri[i]) != NULL) {
-        break;
-      }
-    }
-    res->hostlen = i-offset;
-    offset = i;
-  }
-  if(res->hostlen == 0) {
-    return -1;
-  }
-  /* Assuming https */
-  res->port = 443;
-  if(offset < len) {
-    if(uri[offset] == ':') {
-      /* port */
-      const char delims[] = "/?#";
-      int port = 0;
-      ++offset;
-      for(i = offset; i < len; ++i) {
-        if(strchr(delims, uri[i]) != NULL) {
-          break;
-        }
-        if('0' <= uri[i] && uri[i] <= '9') {
-          port *= 10;
-          port += uri[i]-'0';
-          if(port > 65535) {
-            return -1;
-          }
-        } else {
-          return -1;
-        }
-      }
-      if(port == 0) {
-        return -1;
-      }
-      offset = i;
-      res->port = port;
-    }
-  }
-  res->hostportlen = uri+offset-res->host;
-  for(i = offset; i < len; ++i) {
-    if(uri[i] == '#') {
-      break;
-    }
-  }
-  if(i-offset == 0) {
-    res->path = "/";
-    res->pathlen = 1;
-  } else {
-    res->path = &uri[offset];
-    res->pathlen = i-offset;
-  }
-  return 0;
-}
-
-
-/*****
- * end of code needed to utilize spdylay
- */
-
-
-/*****
- * start of code needed to utilize microspdy
- */
-
-
-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,
-            bool more)
-{
-	(void)cls;
-	(void)request;
-	(void)priority;
-	(void)host;
-	(void)scheme;
-	(void)headers;
-	(void)method;
-	(void)version;
-
-	struct SPDY_Response *response=NULL;
-
-	if(strcmp(CLS,cls)!=0)
-	{
-		killchild(child,"wrong cls");
-	}
-
-	if(false != more){
-		fprintf(stdout,"more has wrong value\n");
-		exit(5);
-	}
-
-	response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,RESPONSE_BODY,strlen(RESPONSE_BODY));
-
-	if(NULL==response){
-		fprintf(stdout,"no response obj\n");
-		exit(3);
-	}
-
-	if(SPDY_queue_response(request,response,true,false,NULL,(void*)strdup(path))!=SPDY_YES)
-	{
-		fprintf(stdout,"queue\n");
-		exit(4);
-	}
-}
-
-void
-session_closed_handler (void *cls,
-						struct SPDY_Session * session,
-						int by_client)
-{
-	printf("session_closed_handler called\n");
-
-	if(strcmp(CLS,cls)!=0)
-	{
-		killchild(child,"wrong cls");
-	}
-
-	if(SPDY_YES != by_client)
-	{
-		//killchild(child,"wrong by_client");
-		printf("session closed by server\n");
-	}
-	else
-	{
-		printf("session closed by client\n");
-	}
-
-	if(NULL == session)
-	{
-		killchild(child,"session is NULL");
-	}
-
-	session_closed_called = 1;
-}
-
-
-/*****
- * end of code needed to utilize microspdy
- */
-
-//child process
-void
-childproc(int port)
-{
-  struct URI uri;
-  struct sigaction act;
-  int rv;
-  char *uristr;
-
-  memset(&act, 0, sizeof(struct sigaction));
-  act.sa_handler = SIG_IGN;
-  sigaction(SIGPIPE, &act, 0);
-
-	asprintf(&uristr, "https://127.0.0.1:%i/",port);
-	if(NULL == (rcvbuf = malloc(strlen(RESPONSE_BODY)+1)))
-		killparent(parent,"no memory");
-
-  SSL_load_error_strings();
-  SSL_library_init();
-
-  rv = parse_uri(&uri, uristr);
-  if(rv != 0) {
-    killparent(parent,"parse_uri failed");
-  }
-  fetch_uri(&uri);
-
-  if(strcmp(rcvbuf, RESPONSE_BODY))
-    killparent(parent,"received data is different");
-}
-
-//parent proc
-int
-parentproc( int port)
-{
-	int childstatus;
-	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;
-
-	SPDY_init();
-
-	daemon = SPDY_start_daemon(port,
-								DATA_DIR "cert-and-key.pem",
-								DATA_DIR "cert-and-key.pem",
-								NULL,&session_closed_handler,&standard_request_handler,NULL,CLS,SPDY_DAEMON_OPTION_END);
-
-	if(NULL==daemon){
-		printf("no daemon\n");
-		return 1;
-	}
-
-	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 > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-
-		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);
-				killchild(child, "select error");
-				break;
-			case 0:
-
-				break;
-			default:
-				SPDY_run(daemon);
-
-			break;
-		}
-	}
-	while(waitpid(child,&childstatus,WNOHANG) != child);
-
-	//give chance to the client to close socket and handle this in run
-	usleep(100000);
-	SPDY_run(daemon);
-
-	SPDY_stop_daemon(daemon);
-
-	SPDY_deinit();
-
-	return WEXITSTATUS(childstatus);
-}
-
-int main()
-{
-	int port = get_port(12123);
-	parent = getpid();
-
-   child = fork();
-   if (child == -1)
-   {
-      fprintf(stderr, "can't fork, error %d\n", errno);
-      exit(EXIT_FAILURE);
-   }
-
-   if (child == 0)
-   {
-      childproc(port);
-      _exit(0);
-   }
-   else
-   {
-	   int ret = parentproc(port);
-	   if(1 == session_closed_called && 0 == ret)
-      exit(0);
-      else
-      exit(ret ? ret : 21);
-   }
-   return 1;
-}

+ 0 - 320
src/testspdy/test_request_response_with_callback.c

@@ -1,320 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 request_response_with_callback.c
- * @brief  tests responses with callbacks
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include "stdio.h"
-#include <sys/wait.h>
-#include <ctype.h>
-#include "common.h"
-#include <sys/time.h>
-#include <sys/stat.h>
-
-int port;
-
-pid_t parent;
-pid_t child;
-
-int run = 1;
-int chunk_size=1;
-
-void
-killchild()
-{
-	kill(child, SIGKILL);
-	exit(1);
-}
-
-void
-killparent()
-{
-	kill(parent, SIGKILL);
-	_exit(1);
-}
-
-ssize_t
-response_callback (void *cls,
-						void *buffer,
-						size_t max,
-						bool *more)
-{
-	FILE *fd =(FILE*)cls;
-	
-	size_t n;
-	if(chunk_size % 2)
-		n = chunk_size;
-	else
-		n = max - chunk_size;
-	
-	if(n < 1) n = 1;
-	else if (n > max) n=max;
-	chunk_size++;
-	
-	int ret = fread(buffer,1,n,fd);
-	*more = feof(fd) == 0;
-	
-	//printf("more is %i\n",*more);
-	
-	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)status;
-  (void)streamopened;
-  
-	printf("answer for %s was sent\n", (char*)cls);
-	
-	SPDY_destroy_request(request);
-	SPDY_destroy_response(response);
-	free(cls);
-	
-	run = 0;
-}
-
-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,
-            bool more)
-{
-	(void)cls;
-	(void)request;
-	(void)priority;
-	(void)host;
-	(void)scheme;
-	(void)headers;
-	(void)method;
-	(void)version;
-	(void)more;
-  
-	struct SPDY_Response *response=NULL;
-	struct SPDY_NameValue *resp_headers;
-	
-	printf("received request for '%s %s %s'\n", method, path, version);
-	
-		FILE *fd = fopen(DATA_DIR "spdy-draft.txt","r");
-		
-		if(NULL == (resp_headers = SPDY_name_value_create()))
-		{
-			fprintf(stdout,"SPDY_name_value_create failed\n");
-			killchild();
-		}
-		if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,"text/plain"))
-		{
-			fprintf(stdout,"SPDY_name_value_add failed\n");
-			killchild();
-		}
-		
-		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){
-		fprintf(stdout,"no response obj\n");
-			killchild();
-	}
-	
-	void *clspath = strdup(path);
-	
-	if(SPDY_queue_response(request,response,true,false,&response_done_callback,clspath)!=SPDY_YES)
-	{
-		fprintf(stdout,"queue\n");
-			killchild();
-	}
-}
-
-int
-parentproc()
-{	
-	int childstatus;
-	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;
-	
-	SPDY_init();
-	
-	daemon = SPDY_start_daemon(port,
-								DATA_DIR "cert-and-key.pem",
-								DATA_DIR "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;
-	}
-
-	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 > 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-			timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-		
-		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(waitpid(child,&childstatus,WNOHANG) != child);
-
-	SPDY_stop_daemon(daemon);
-	
-	SPDY_deinit();
-	
-	return WEXITSTATUS(childstatus);
-}
-
-#define MD5_LEN 32
-
-int
-md5(char *cmd, char *md5_sum)
-{
-    FILE *p = popen(cmd, "r");
-    if (p == NULL) return 0;
-
-    int i, ch;
-    for (i = 0; i < MD5_LEN && isxdigit(ch = fgetc(p)); i++) {
-        *md5_sum++ = ch;
-    }
-
-    *md5_sum = '\0';
-    pclose(p);
-    return i == MD5_LEN;
-}
-
-int
-childproc()
-{
-	char *cmd1;
-	char *cmd2;
-	char md5_sum1[33];
-	char md5_sum2[33];
-	int ret;
-	struct timeval tv1;
-	struct timeval tv2;
-	struct stat st;
-	//int secs;
-	uint64_t usecs;
-	
-	asprintf(&cmd1, "spdycat https://127.0.0.1:%i/ | md5sum",port);
-	asprintf(&cmd2, "md5sum " DATA_DIR "spdy-draft.txt");
-	
-	gettimeofday(&tv1, NULL);
-	md5(cmd1,md5_sum1);
-	gettimeofday(&tv2, NULL);
-	md5(cmd2,md5_sum2);
-	
-	printf("downloaded file md5: %s\n", md5_sum1);
-	printf("original   file md5: %s\n", md5_sum2);
-	ret = strcmp(md5_sum1, md5_sum2);
-	
-	if(0 == ret && 0 == stat(DATA_DIR "spdy-draft.txt", &st))
-	{
-		usecs = (uint64_t)1000000 * (uint64_t)(tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec;
-		printf("%lld bytes read in %llu usecs\n", (long long)st.st_size, (long long unsigned )usecs);
-	}
-	
-	return ret;
-}
-
-
-int
-main()
-{
-	port = get_port(11123);
-	parent = getpid();
-
-	child = fork();
-	if (-1 == child)
-	{   
-		fprintf(stderr, "can't fork, error %d\n", errno);
-		exit(EXIT_FAILURE);
-	}
-
-	if (child == 0)
-	{
-		int ret = childproc();
-		_exit(ret);
-	}
-	else
-	{ 
-		int ret = parentproc();
-		exit(ret);
-	}
-	return 1;
-}

File diff suppressed because it is too large
+ 0 - 47
src/testspdy/test_requests_with_assets.c


+ 0 - 338
src/testspdy/test_session_timeout.c

@@ -1,338 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 session_timeout.c
- * @brief  tests closing sessions after set timeout. Openssl is used for
- * 			client
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include "stdio.h"
-#include <sys/wait.h>
-#include <ctype.h>
-#include "common.h"
-#include <sys/time.h>
-#include <sys/stat.h>
-#include "../microspdy/internal.h"
-
-#define TIMEOUT 2
-#define SELECT_MS_TIMEOUT 20
-
-int port;
-
-pid_t parent;
-pid_t child;
-
-int run = 1;
-int chunk_size=1;
-int new_session;
-int closed_session;
-int do_sleep;
-
-
-
-static unsigned long long
-monotonic_time (void)
-{
-#ifdef HAVE_CLOCK_GETTIME
-#ifdef CLOCK_MONOTONIC
-  struct timespec ts;
-  if (0 == clock_gettime (CLOCK_MONOTONIC, &ts))
-    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
-#endif
-#endif
-  return time (NULL) * 1000;
-}
-
-
-static void
-killchild(char *msg)
-{
-	printf("%s\n",msg);
-	kill(child, SIGKILL);
-	exit(1);
-}
-
-
-static void
-killparent(char *msg)
-{
-	printf("%s\n",msg);
-	kill(parent, SIGKILL);
-	_exit(1);
-}
-
-
-static void
-new_session_cb (void *cls,
-                struct SPDY_Session * session)
-{
-  (void)cls;
-  (void)session;
-
-	if(!new_session)do_sleep = 1;
-	new_session = 1;
-	printf("new session\n");
-}
-
-
-static void
-closed_session_cb (void *cls,
-                   struct SPDY_Session * session,
-                   int by_client)
-{
-  (void)cls;
-  (void)session;
-
-	printf("closed_session_cb called\n");
-
-	if(SPDY_YES == by_client)
-	{
-		killchild("closed by the client");
-	}
-	if(closed_session)
-	{
-		killchild("closed_session_cb called twice");
-	}
-
-	closed_session = 1;
-}
-
-
-static int
-parentproc()
-{
-	int childstatus;
-	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;
-  unsigned long long  beginning = 0;
-	unsigned long long now;
-
-	SPDY_init();
-
-	daemon = SPDY_start_daemon(port,
-								DATA_DIR "cert-and-key.pem",
-								DATA_DIR "cert-and-key.pem",
-								&new_session_cb,
-								&closed_session_cb,
-								NULL,
-								NULL,
-								NULL,
-								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
-								TIMEOUT,
-								SPDY_DAEMON_OPTION_END);
-
-	if(NULL==daemon){
-		printf("no daemon\n");
-		return 1;
-	}
-
-	do
-	{
-		do_sleep=0;
-		FD_ZERO(&read_fd_set);
-		FD_ZERO(&write_fd_set);
-		FD_ZERO(&except_fd_set);
-
-		ret = SPDY_get_timeout(daemon, &timeoutlong);
-
-		if(new_session && !closed_session)
-		{
-			if(SPDY_NO == ret)
-			{
-				killchild("SPDY_get_timeout returned wrong SPDY_NO");
-			}
-			/*if(timeoutlong)
-			{
-				killchild("SPDY_get_timeout returned wrong timeout");
-			}*/
-			now = monotonic_time ();
-      if(now - beginning > TIMEOUT*1000 + SELECT_MS_TIMEOUT)
-      {
-        printf("Started at: %llums\n",beginning);
-        printf("Now is: %llums\n",now);
-        printf("Timeout is: %i\n",TIMEOUT);
-        printf("Select Timeout is: %ims\n",SELECT_MS_TIMEOUT);
-        printf("SPDY_get_timeout gave: %llums\n",timeoutlong);
-				killchild("Timeout passed but session was not closed");
-      }
-      if(timeoutlong > beginning + TIMEOUT *1000)
-      {
-        printf("Started at: %llums\n",beginning);
-        printf("Now is: %llums\n",now);
-        printf("Timeout is: %i\n",TIMEOUT);
-        printf("Select Timeout is: %ims\n",SELECT_MS_TIMEOUT);
-        printf("SPDY_get_timeout gave: %llums\n",timeoutlong);
-				killchild("SPDY_get_timeout returned wrong timeout");
-      }
-		}
-		else
-		{
-			if(SPDY_YES == ret)
-			{
-				killchild("SPDY_get_timeout returned wrong SPDY_YES");
-			}
-		}
-
-		if(SPDY_NO == ret || timeoutlong >= 1000)
-		{
-			timeout.tv_sec = 1;
-      timeout.tv_usec = 0;
-		}
-		else
-		{
-			timeout.tv_sec = timeoutlong / 1000;
-      timeout.tv_usec = (timeoutlong % 1000) * 1000;
-		}
-
-    //ignore values
-    timeout.tv_sec = 0;
-    timeout.tv_usec = SELECT_MS_TIMEOUT * 1000;
-
-		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:
-				/*if(new_session)
-				{
-					killchild("select returned wrong number");
-				}*/
-				break;
-			default:
-				SPDY_run(daemon);
-        if(0 == beginning)
-        {
-	  beginning = monotonic_time ();
-        }
-				/*if(do_sleep)
-				{
-					sleep(TIMEOUT);
-					do_sleep = 0;
-				}*/
-			break;
-		}
-	}
-	while(waitpid(child,&childstatus,WNOHANG) != child);
-
-	if(!new_session || !closed_session)
-	{
-		killchild("child is dead, callback wasn't called");
-	}
-
-	ret = SPDY_get_timeout(daemon, &timeoutlong);
-
-	if(SPDY_YES == ret)
-	{
-		killchild("SPDY_get_timeout returned wrong SPDY_YES after child died");
-	}
-
-	SPDY_stop_daemon(daemon);
-
-	SPDY_deinit();
-
-	return 0;
-}
-
-
-static int
-childproc()
-{
-	pid_t devnull;
-	int out;
-
-	out=dup(1);
-        if (-1 == out)
-          abort();
-	//close(0);
-	close(1);
-	close(2);
-	/*devnull = open("/dev/null", O_RDONLY);
-	if (0 != devnull)
-	{
-		dup2(devnull, 0);
-		close(devnull);
-	}*/
-	devnull = open("/dev/null", O_WRONLY);
-        if (-1 == devnull)
-          abort ();
-	if (1 != devnull)
-	{
-		dup2(devnull, 1);
-		close(devnull);
-	}
-	devnull = open("/dev/null", O_WRONLY);
-        if (-1 == devnull)
-          abort ();
-	if (2 != devnull)
-	{
-		dup2(devnull, 2);
-		close(devnull);
-	}
-	char *uri;
-	asprintf (&uri, "127.0.0.1:%i", port);
-	execlp ("openssl", "openssl", "s_client", "-connect", uri, NULL);
-	close(1);
-	dup2(out,1);
-	close(out);
-	killparent ("executing openssl failed");
-	return 1;
-}
-
-
-int
-main()
-{
-	port = get_port(11123);
-	parent = getpid();
-
-	child = fork();
-	if (-1 == child)
-	{
-		fprintf(stderr, "can't fork, error %d\n", errno);
-		exit(EXIT_FAILURE);
-	}
-
-	if (child == 0)
-	{
-		int ret = childproc();
-		_exit(ret);
-	}
-	else
-	{
-		int ret = parentproc();
-		exit(ret);
-	}
-	return 1;
-}

+ 0 - 346
src/testspdy/test_struct_namevalue.c

@@ -1,346 +0,0 @@
-/*
-    This file is part of libmicrospdy
-    Copyright 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 struct_namevalue.c
- * @brief  tests all the API functions for handling struct SPDY_NameValue
- * @author Andrey Uzunov
- */
-
-#include "platform.h"
-#include "microspdy.h"
-#include "common.h"
-#include "../microspdy/structures.h"
-#include "../microspdy/alstructures.h"
-
-char *pairs[] = {"one","1","two","2","three","3","four","4","five","5"};
-char *pairs_with_dups[] = {"one","1","two","2","one","11","two","22","three","3","two","222","two","2222","four","","five","5"};//82
-char *pairs_with_empty[] = {"name","","name","value"};
-char *pairs_different[] = {"30","thirty","40","fouthy"};
-int size;
-int size2;
-int brake_at = 3;
-bool flag;
-
-
-int
-iterate_cb (void *cls, const char *name, const char * const * value, int num_values)
-{
-	int *c = (int*)cls;
-
-	if(*c < 0 || *c > size)
-		exit(11);
-
-	if(strcmp(name,pairs[*c]) != 0)
-	{
-		FAIL_TEST("name is wrong\n");
-	}
-
-	if(1 != num_values)
-	{
-		FAIL_TEST("num_values is wrong\n");
-	}
-
-	if(strcmp(value[0],pairs[(*c)+1]) != 0)
-	{
-		FAIL_TEST("value is wrong\n");
-	}
-
-	(*c)+=2;
-
-	return SPDY_YES;
-}
-
-int
-iterate_brake_cb (void *cls, const char *name, const char * const *value, int num_values)
-{
-  (void)name;
-  (void)value;
-  (void)num_values;
-
-	int *c = (int*)cls;
-
-	if(*c < 0 || *c >= brake_at)
-	{
-		FAIL_TEST("iteration was not interrupted\n");
-	}
-
-	(*c)++;
-
-	if(*c == brake_at) return SPDY_NO;
-
-	return SPDY_YES;
-}
-
-int
-main()
-{
-	SPDY_init();
-
-	const char *const*value;
-	const char *const*value2;
-	int i;
-	int j;
-	int cls = 0;
-	int ret;
-	int ret2;
-	void *ob1;
-	void *ob2;
-	void *ob3;
-	void *stream;
-	char data[] = "anything";
-	struct SPDY_NameValue *container;
-	struct SPDY_NameValue *container2;
-	struct SPDY_NameValue *container3;
-	struct SPDY_NameValue *container_arr[2];
-
-	size = sizeof(pairs)/sizeof(pairs[0]);
-
-	if(NULL == (container = SPDY_name_value_create ()))
-	{
-		FAIL_TEST("SPDY_name_value_create failed\n");
-	}
-
-	if(NULL != SPDY_name_value_lookup (container, "anything", &ret))
-	{
-		FAIL_TEST("SPDY_name_value_lookup failed\n");
-	}
-
-	if(SPDY_name_value_iterate (container, NULL, NULL) != 0)
-	{
-		FAIL_TEST("SPDY_name_value_iterate failed\n");
-	}
-
-	for(i=0;i<size; i+=2)
-	{
-		if(SPDY_YES != SPDY_name_value_add(container,pairs[i],pairs[i+1]))
-		{
-			FAIL_TEST("SPDY_name_value_add failed\n");
-		}
-
-		if(SPDY_name_value_iterate (container, NULL, NULL) != ((i / 2) + 1))
-		{
-			FAIL_TEST("SPDY_name_value_iterate failed\n");
-		}
-	}
-
-	if(NULL != SPDY_name_value_lookup (container, "anything", &ret))
-	{
-		FAIL_TEST("SPDY_name_value_lookup failed\n");
-	}
-
-	for(i=size - 2; i >= 0; i-=2)
-	{
-		value = SPDY_name_value_lookup(container,pairs[i], &ret);
-		if(NULL == value || 1 !=ret || strcmp(value[0], pairs[i+1]) != 0)
-		{
-			printf("%p; %i; %i\n", value, ret,
-                               (NULL == value) ? -1 : strcmp(value[0], pairs[i+1]));
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-		}
-	}
-
-	SPDY_name_value_iterate (container, &iterate_cb, &cls);
-
-	cls = 0;
-	if(SPDY_name_value_iterate (container, &iterate_brake_cb, &cls) != brake_at)
-	{
-		FAIL_TEST("SPDY_name_value_iterate with brake failed\n");
-	}
-
-	SPDY_name_value_destroy(container);
-
-	//check everything with NULL values
-	for(i=0; i<7; ++i)
-	{
-		printf("%i ",i);
-		ob1 = (i & 4) ? data : NULL;
-		ob2 = (i & 2) ? data : NULL;
-		ob3 = (i & 1) ? data : NULL;
-		if(SPDY_INPUT_ERROR != SPDY_name_value_add(ob1,ob2,ob3))
-		{
-			FAIL_TEST("SPDY_name_value_add with NULLs failed\n");
-		}
-	}
-	printf("\n");
-	fflush(stdout);
-
-	if(SPDY_INPUT_ERROR != SPDY_name_value_iterate(NULL,NULL,NULL))
-	{
-		FAIL_TEST("SPDY_name_value_iterate with NULLs failed\n");
-	}
-
-	for(i=0; i<7; ++i)
-	{
-		printf("%i ",i);
-		ob1 = (i & 4) ? data : NULL;
-		ob2 = (i & 2) ? data : NULL;
-		ob3 = (i & 1) ? data : NULL;
-		if(NULL != SPDY_name_value_lookup(ob1,ob2,ob3))
-		{
-			FAIL_TEST("SPDY_name_value_lookup with NULLs failed\n");
-		}
-	}
-	printf("\n");
-	SPDY_name_value_destroy(NULL);
-
-	if(NULL == (container = SPDY_name_value_create ()))
-	{
-		FAIL_TEST("SPDY_name_value_create failed\n");
-	}
-
-	size = sizeof(pairs_with_dups)/sizeof(pairs_with_dups[0]);
-
-	for(i=0;i<size; i+=2)
-	{
-		if(SPDY_YES != SPDY_name_value_add(container,pairs_with_dups[i],pairs_with_dups[i+1]))
-		{
-			FAIL_TEST("SPDY_name_value_add failed\n");
-		}
-	}
-	if(SPDY_name_value_iterate (container, NULL, NULL) != atoi(pairs_with_dups[size - 1]))
-	{
-		FAIL_TEST("SPDY_name_value_iterate failed\n");
-	}
-	for(i=size - 2; i >= 0; i-=2)
-	{
-		value = SPDY_name_value_lookup(container,pairs_with_dups[i], &ret);
-		if(NULL == value)
-		{
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-		}
-		flag = false;
-		for(j=0; j<ret; ++j)
-			if(0 == strcmp(pairs_with_dups[i + 1], value[j]))
-			{
-				if(flag)
-					FAIL_TEST("SPDY_name_value_lookup failed\n");
-				flag=true;
-			}
-
-		if(!flag)
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-	}
-	if(SPDY_NO != SPDY_name_value_add(container,pairs_with_dups[0],pairs_with_dups[1]))
-		FAIL_TEST("SPDY_name_value_add failed\n");
-
-	SPDY_name_value_destroy(container);
-
-	if(NULL == (container = SPDY_name_value_create ()))
-	{
-		FAIL_TEST("SPDY_name_value_create failed\n");
-	}
-
-	size = sizeof(pairs_with_empty)/sizeof(pairs_with_empty[0]);
-
-	for(i=0;i<size; i+=2)
-	{
-		if(SPDY_YES != SPDY_name_value_add(container,pairs_with_empty[i],pairs_with_empty[i+1]))
-		{
-			FAIL_TEST("SPDY_name_value_add failed\n");
-		}
-		value = SPDY_name_value_lookup(container,pairs_with_empty[i], &ret);
-		if(NULL == value || 1 != ret)
-		{
-			printf("%p; %i\n", value, ret);
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-		}
-	}
-
-	ret = SPDY_name_value_iterate(container, NULL, NULL);
-	if(SPDY_INPUT_ERROR != SPDY_name_value_add(container, "capitalLeter","anything")
-		|| SPDY_name_value_iterate(container, NULL, NULL) != ret)
-	{
-		FAIL_TEST("SPDY_name_value_add failed\n");
-	}
-
-	SPDY_name_value_destroy(container);
-
-	if(NULL == (container = SPDY_name_value_create ()))
-	{
-		FAIL_TEST("SPDY_name_value_create failed\n");
-	}
-
-	size = sizeof(pairs_with_dups)/sizeof(pairs_with_dups[0]);
-
-	for(i=0;i<size; i+=2)
-	{
-		if(SPDY_YES != SPDY_name_value_add(container,pairs_with_dups[i],pairs_with_dups[i+1]))
-		{
-			FAIL_TEST("SPDY_name_value_add failed\n");
-		}
-	}
-
-	if(NULL == (container2 = SPDY_name_value_create ()))
-	{
-		FAIL_TEST("SPDY_name_value_create failed\n");
-	}
-
-	size2 = sizeof(pairs_different)/sizeof(pairs_different[0]);
-
-	for(i=0;i<size2; i+=2)
-	{
-		if(SPDY_YES != SPDY_name_value_add(container2,pairs_different[i],pairs_different[i+1]))
-		{
-			FAIL_TEST("SPDY_name_value_add failed\n");
-		}
-	}
-
-	container_arr[0] = container;
-	container_arr[1] = container2;
-	if(0 > (ret = SPDYF_name_value_to_stream(container_arr, 2, &stream)) || NULL == stream)
-		FAIL_TEST("SPDYF_name_value_to_stream failed\n");
-	ret = SPDYF_name_value_from_stream(stream, ret, &container3);
-	if(SPDY_YES != ret)
-		FAIL_TEST("SPDYF_name_value_from_stream failed\n");
-
-	if(SPDY_name_value_iterate(container3, NULL, NULL)
-		!= (SPDY_name_value_iterate(container, NULL, NULL) + SPDY_name_value_iterate(container2, NULL, NULL)))
-		FAIL_TEST("SPDYF_name_value_from_stream failed\n");
-
-	for(i=size - 2; i >= 0; i-=2)
-	{
-		value = SPDY_name_value_lookup(container,pairs_with_dups[i], &ret);
-		if(NULL == value)
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-		value2 = SPDY_name_value_lookup(container3,pairs_with_dups[i], &ret2);
-		if(NULL == value2)
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-
-		for(j=0; j<ret; ++j)
-			if(0 != strcmp(value2[j], value[j]))
-				FAIL_TEST("SPDY_name_value_lookup failed\n");
-	}
-	for(i=size2 - 2; i >= 0; i-=2)
-	{
-		value = SPDY_name_value_lookup(container2,pairs_different[i], &ret);
-		if(NULL == value)
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-		value2 = SPDY_name_value_lookup(container3,pairs_different[i], &ret2);
-		if(NULL == value2)
-			FAIL_TEST("SPDY_name_value_lookup failed\n");
-
-		for(j=0; j<ret; ++j)
-			if(0 != strcmp(value2[j], value[j]))
-				FAIL_TEST("SPDY_name_value_lookup failed\n");
-	}
-
-	SPDY_deinit();
-
-	return 0;
-}

Some files were not shown because too many files changed in this diff