C++程序  |  1381行  |  46.98 KB

/*
    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