gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r27025 - in libmicrohttpd: . src src/microhttpd


From: gnunet
Subject: [GNUnet-SVN] r27025 - in libmicrohttpd: . src src/microhttpd
Date: Sun, 5 May 2013 20:07:33 +0200

Author: grothoff
Date: 2013-05-05 20:07:33 +0200 (Sun, 05 May 2013)
New Revision: 27025

Added:
   libmicrohttpd/src/microhttpd/
   libmicrohttpd/src/microhttpd/basicauth.c
   libmicrohttpd/src/microhttpd/connection.c
   libmicrohttpd/src/microhttpd/daemon.c
   libmicrohttpd/src/microhttpd/digestauth.c
   libmicrohttpd/src/microhttpd/internal.c
   libmicrohttpd/src/microhttpd/internal.h
   libmicrohttpd/src/microhttpd/memorypool.c
   libmicrohttpd/src/microhttpd/memorypool.h
   libmicrohttpd/src/microhttpd/postprocessor.c
   libmicrohttpd/src/microhttpd/response.c
   libmicrohttpd/src/microhttpd/test_daemon.c
   libmicrohttpd/src/microhttpd/test_postprocessor.c
   libmicrohttpd/src/microhttpd/test_postprocessor_large.c
Removed:
   libmicrohttpd/src/daemon/
   libmicrohttpd/src/microhttpd/basicauth.c
   libmicrohttpd/src/microhttpd/connection.c
   libmicrohttpd/src/microhttpd/daemon.c
   libmicrohttpd/src/microhttpd/digestauth.c
   libmicrohttpd/src/microhttpd/internal.c
   libmicrohttpd/src/microhttpd/internal.h
   libmicrohttpd/src/microhttpd/memorypool.c
   libmicrohttpd/src/microhttpd/memorypool.h
   libmicrohttpd/src/microhttpd/postprocessor.c
   libmicrohttpd/src/microhttpd/response.c
   libmicrohttpd/src/microhttpd/test_daemon.c
   libmicrohttpd/src/microhttpd/test_postprocessor.c
   libmicrohttpd/src/microhttpd/test_postprocessor_large.c
Modified:
   libmicrohttpd/configure.ac
   libmicrohttpd/src/Makefile.am
Log:
-changing directory name

Modified: libmicrohttpd/configure.ac
===================================================================
--- libmicrohttpd/configure.ac  2013-05-05 18:01:09 UTC (rev 27024)
+++ libmicrohttpd/configure.ac  2013-05-05 18:07:33 UTC (rev 27025)
@@ -449,7 +449,7 @@
 src/Makefile
 src/include/Makefile
 src/include/plibc/Makefile
-src/daemon/Makefile
+src/microhttpd/Makefile
 src/examples/Makefile
 src/testcurl/Makefile
 src/testcurl/https/Makefile

Modified: libmicrohttpd/src/Makefile.am
===================================================================
--- libmicrohttpd/src/Makefile.am       2013-05-05 18:01:09 UTC (rev 27024)
+++ libmicrohttpd/src/Makefile.am       2013-05-05 18:07:33 UTC (rev 27025)
@@ -6,4 +6,4 @@
 endif
 endif
 endif
-SUBDIRS = include daemon examples $(curltests) $(zzuftests) . 
+SUBDIRS = include microhttpd examples $(curltests) $(zzuftests) . 

Deleted: libmicrohttpd/src/microhttpd/basicauth.c
===================================================================
--- libmicrohttpd/src/daemon/basicauth.c        2013-05-05 12:01:06 UTC (rev 
27023)
+++ libmicrohttpd/src/microhttpd/basicauth.c    2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,132 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-*/
-/**
- * @file basicauth.c
- * @brief Implements HTTP basic authentication methods
- * @author Amr Ali
- * @author Matthieu Speder
- */
-#include "platform.h"
-#include <limits.h>
-#include "internal.h"
-#include "base64.h"
-
-/**
- * Beginning string for any valid Basic authentication header.
- */
-#define _BASIC_BASE            "Basic "
-
-
-/**
- * Get the username and password from the basic authorization header sent by 
the client
- *
- * @param connection The MHD connection structure
- * @param password a pointer for the password
- * @return NULL if no username could be found, a pointer
- *                     to the username if found
- */
-char *
-MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
-                                    char** password) 
-{
-  const char *header;
-  char *decode;
-  const char *separator;
-  char *user;
-  
-  if ( (NULL == (header = MHD_lookup_connection_value (connection, 
-                                                      MHD_HEADER_KIND,
-                                                      
MHD_HTTP_HEADER_AUTHORIZATION))) ||
-       (0 != strncmp (header, _BASIC_BASE, strlen(_BASIC_BASE))) )
-    return NULL;
-  header += strlen (_BASIC_BASE);
-  if (NULL == (decode = BASE64Decode (header)))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon,
-               "Error decoding basic authentication\n");
-#endif
-      return NULL;
-    }
-  /* Find user:password pattern */
-  if (NULL == (separator = strchr (decode, ':')))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG(connection->daemon,
-              "Basic authentication doesn't contain ':' separator\n");
-#endif
-      free (decode);
-      return NULL;
-    }
-  if (NULL == (user = strdup (decode)))
-    {
-      free (decode);
-      return NULL;
-    }
-  user[separator - decode] = '\0'; /* cut off at ':' */
-  if (NULL != password) 
-    {
-      *password = strdup (separator + 1);  
-      if (NULL == *password)
-       {
-#if HAVE_MESSAGES
-         MHD_DLOG(connection->daemon,
-                  "Failed to allocate memory for password\n");
-#endif
-         free (decode);
-         free (user);
-         return NULL;
-       }
-    }
-  free (decode);
-  return user;
-}
-
-
-/**
- * Queues a response to request basic authentication from the client
- *
- * @param connection The MHD connection structure
- * @param realm the realm presented to the client
- * @return MHD_YES on success, MHD_NO otherwise
- */
-int 
-MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection,
-                                   const char *realm, 
-                                   struct MHD_Response *response) 
-{
-  int ret;
-  size_t hlen = strlen(realm) + strlen("Basic realm=\"\"") + 1;
-  char header[hlen];
-
-  snprintf (header, 
-           sizeof (header), 
-           "Basic realm=\"%s\"", 
-           realm);
-  ret = MHD_add_response_header (response,
-                                MHD_HTTP_HEADER_WWW_AUTHENTICATE,
-                                header);
-  if (MHD_YES == ret)
-    ret = MHD_queue_response (connection, 
-                             MHD_HTTP_UNAUTHORIZED, 
-                             response);
-  return ret;
-}
-
-/* end of basicauth.c */

Copied: libmicrohttpd/src/microhttpd/basicauth.c (from rev 27024, 
libmicrohttpd/src/daemon/basicauth.c)
===================================================================
--- libmicrohttpd/src/microhttpd/basicauth.c                            (rev 0)
+++ libmicrohttpd/src/microhttpd/basicauth.c    2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,136 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+*/
+/**
+ * @file basicauth.c
+ * @brief Implements HTTP basic authentication methods
+ * @author Amr Ali
+ * @author Matthieu Speder
+ */
+#include "platform.h"
+#include <limits.h>
+#include "internal.h"
+#include "base64.h"
+
+/**
+ * Beginning string for any valid Basic authentication header.
+ */
+#define _BASIC_BASE            "Basic "
+
+
+/**
+ * Get the username and password from the basic authorization header sent by 
the client
+ *
+ * @param connection The MHD connection structure
+ * @param password a pointer for the password
+ * @return NULL if no username could be found, a pointer
+ *                     to the username if found
+ */
+char *
+MHD_basic_auth_get_username_password(struct MHD_Connection *connection,
+                                    char** password) 
+{
+  const char *header;
+  char *decode;
+  const char *separator;
+  char *user;
+  
+  if ( (NULL == (header = MHD_lookup_connection_value (connection, 
+                                                      MHD_HEADER_KIND,
+                                                      
MHD_HTTP_HEADER_AUTHORIZATION))) ||
+       (0 != strncmp (header, _BASIC_BASE, strlen(_BASIC_BASE))) )
+    return NULL;
+  header += strlen (_BASIC_BASE);
+  if (NULL == (decode = BASE64Decode (header)))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon,
+               "Error decoding basic authentication\n");
+#endif
+      return NULL;
+    }
+  /* Find user:password pattern */
+  if (NULL == (separator = strchr (decode, ':')))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG(connection->daemon,
+              "Basic authentication doesn't contain ':' separator\n");
+#endif
+      free (decode);
+      return NULL;
+    }
+  if (NULL == (user = strdup (decode)))
+    {
+      free (decode);
+      return NULL;
+    }
+  user[separator - decode] = '\0'; /* cut off at ':' */
+  if (NULL != password) 
+    {
+      *password = strdup (separator + 1);  
+      if (NULL == *password)
+       {
+#if HAVE_MESSAGES
+         MHD_DLOG(connection->daemon,
+                  "Failed to allocate memory for password\n");
+#endif
+         free (decode);
+         free (user);
+         return NULL;
+       }
+    }
+  free (decode);
+  return user;
+}
+
+
+/**
+ * Queues a response to request basic authentication from the client.
+ * The given response object is expected to include the payload for
+ * the response; the "WWW-Authenticate" header will be added and the
+ * response queued with the 'UNAUTHORIZED' status code.
+ *
+ * @param connection The MHD connection structure
+ * @param realm the realm presented to the client
+ * @param response response object to modify and queue
+ * @return MHD_YES on success, MHD_NO otherwise
+ */
+int 
+MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection,
+                                   const char *realm, 
+                                   struct MHD_Response *response) 
+{
+  int ret;
+  size_t hlen = strlen(realm) + strlen("Basic realm=\"\"") + 1;
+  char header[hlen];
+
+  snprintf (header, 
+           sizeof (header), 
+           "Basic realm=\"%s\"", 
+           realm);
+  ret = MHD_add_response_header (response,
+                                MHD_HTTP_HEADER_WWW_AUTHENTICATE,
+                                header);
+  if (MHD_YES == ret)
+    ret = MHD_queue_response (connection, 
+                             MHD_HTTP_UNAUTHORIZED, 
+                             response);
+  return ret;
+}
+
+/* end of basicauth.c */

Deleted: libmicrohttpd/src/microhttpd/connection.c
===================================================================
--- libmicrohttpd/src/daemon/connection.c       2013-05-05 12:01:06 UTC (rev 
27023)
+++ libmicrohttpd/src/microhttpd/connection.c   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,2578 +0,0 @@
-/*
-    This file is part of libmicrohttpd
-     (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian 
Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-
-*/
-
-/**
- * @file connection.c
- * @brief  Methods for managing connections
- * @author Daniel Pittman
- * @author Christian Grothoff
- */
-
-#include "internal.h"
-#include <limits.h>
-#include "connection.h"
-#include "memorypool.h"
-#include "response.h"
-#include "reason_phrase.h"
-
-#if HAVE_NETINET_TCP_H
-/* for TCP_CORK */
-#include <netinet/tcp.h>
-#endif
-
-/**
- * Minimum size by which MHD tries to increment read/write buffers.
- * We usually begin with half the available pool space for the
- * IO-buffer, but if absolutely needed we additively grow by the
- * number of bytes given here (up to -- theoretically -- the full pool
- * space).
- */
-#define MHD_BUF_INC_SIZE 1024
-
-/**
- * Message to transmit when http 1.1 request is received
- */
-#define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
-
-/**
- * Response text used when the request (http header) is too big to
- * be processed.
- *
- * Intentionally empty here to keep our memory footprint
- * minimal.
- */
-#if HAVE_MESSAGES
-#define REQUEST_TOO_BIG "<html><head><title>Request too 
big</title></head><body>Your HTTP header was too big for the memory constraints 
of this webserver.</body></html>"
-#else
-#define REQUEST_TOO_BIG ""
-#endif
-
-/**
- * Response text used when the request (http header) does not
- * contain a "Host:" header and still claims to be HTTP 1.1.
- *
- * Intentionally empty here to keep our memory footprint
- * minimal.
- */
-#if HAVE_MESSAGES
-#define REQUEST_LACKS_HOST "<html><head><title>&quot;Host:&quot; header 
required</title></head><body>In HTTP 1.1, requests must include a 
&quot;Host:&quot; header, and your HTTP 1.1 request lacked such a 
header.</body></html>"
-#else
-#define REQUEST_LACKS_HOST ""
-#endif
-
-/**
- * Response text used when the request (http header) is
- * malformed.
- *
- * Intentionally empty here to keep our memory footprint
- * minimal.
- */
-#if HAVE_MESSAGES
-#define REQUEST_MALFORMED "<html><head><title>Request 
malformed</title></head><body>Your HTTP request was syntactically 
incorrect.</body></html>"
-#else
-#define REQUEST_MALFORMED ""
-#endif
-
-/**
- * Response text used when there is an internal server error.
- *
- * Intentionally empty here to keep our memory footprint
- * minimal.
- */
-#if HAVE_MESSAGES
-#define INTERNAL_ERROR "<html><head><title>Internal server 
error</title></head><body>Some programmer needs to study the manual more 
carefully.</body></html>"
-#else
-#define INTERNAL_ERROR ""
-#endif
-
-/**
- * Add extra debug messages with reasons for closing connections
- * (non-error reasons).
- */
-#define DEBUG_CLOSE MHD_NO
-
-/**
- * Should all data send be printed to stderr?
- */
-#define DEBUG_SEND_DATA MHD_NO
-
-
-/**
- * Get all of the headers from the request.
- *
- * @param connection connection to get values from
- * @param kind types of values to iterate over
- * @param iterator callback to call on each header;
- *        maybe NULL (then just count headers)
- * @param iterator_cls extra argument to iterator
- * @return number of entries iterated over
- */
-int
-MHD_get_connection_values (struct MHD_Connection *connection,
-                           enum MHD_ValueKind kind,
-                           MHD_KeyValueIterator iterator, void *iterator_cls)
-{
-  int ret;
-  struct MHD_HTTP_Header *pos;
-
-  if (NULL == connection)
-    return -1;
-  ret = 0;
-  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
-    if (0 != (pos->kind & kind))
-      {
-       ret++;
-       if ((NULL != iterator) &&
-           (MHD_YES != iterator (iterator_cls,
-                                 kind, pos->header, pos->value)))
-         return ret;
-      }
-  return ret;
-}
-
-
-/**
- * This function can be used to append an entry to
- * the list of HTTP headers of a connection (so that the
- * MHD_get_connection_values function will return
- * them -- and the MHD PostProcessor will also
- * see them).  This maybe required in certain
- * situations (see Mantis #1399) where (broken)
- * HTTP implementations fail to supply values needed
- * by the post processor (or other parts of the
- * application).
- * <p>
- * This function MUST only be called from within
- * the MHD_AccessHandlerCallback (otherwise, access
- * maybe improperly synchronized).  Furthermore,
- * the client must guarantee that the key and
- * value arguments are 0-terminated strings that
- * are NOT freed until the connection is closed.
- * (The easiest way to do this is by passing only
- * arguments to permanently allocated strings.).
- *
- * @param connection the connection for which a
- *  value should be set
- * @param kind kind of the value
- * @param key key for the value
- * @param value the value itself
- * @return MHD_NO if the operation could not be
- *         performed due to insufficient memory;
- *         MHD_YES on success
- */
-int
-MHD_set_connection_value (struct MHD_Connection *connection,
-                          enum MHD_ValueKind kind,
-                          const char *key, const char *value)
-{
-  struct MHD_HTTP_Header *pos;
-
-  pos = MHD_pool_allocate (connection->pool,
-                           sizeof (struct MHD_HTTP_Header), MHD_NO);
-  if (NULL == pos)
-    return MHD_NO;
-  pos->header = (char *) key;
-  pos->value = (char *) value;
-  pos->kind = kind;
-  pos->next = NULL;
-  /* append 'pos' to the linked list of headers */
-  if (NULL == connection->headers_received_tail)
-  {
-    connection->headers_received = pos;
-    connection->headers_received_tail = pos;
-  }
-  else
-  {
-    connection->headers_received_tail->next = pos;
-    connection->headers_received_tail = pos;
-  }
-  return MHD_YES;
-}
-
-
-/**
- * Get a particular header value.  If multiple
- * values match the kind, return any one of them.
- *
- * @param connection connection to get values from
- * @param kind what kind of value are we looking for
- * @param key the header to look for, NULL to lookup 'trailing' value without 
a key
- * @return NULL if no such item was found
- */
-const char *
-MHD_lookup_connection_value (struct MHD_Connection *connection,
-                             enum MHD_ValueKind kind, const char *key)
-{
-  struct MHD_HTTP_Header *pos;
-
-  if (NULL == connection)
-    return NULL;
-  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
-    if ((0 != (pos->kind & kind)) && 
-       ( (key == pos->header) ||
-         ( (NULL != pos->header) &&
-           (NULL != key) &&
-           (0 == strcasecmp (key, pos->header))) ))
-      return pos->value;    
-  return NULL;
-}
-
-
-/**
- * Queue a response to be transmitted to the client (as soon as
- * possible but after MHD_AccessHandlerCallback returns).
- *
- * @param connection the connection identifying the client
- * @param status_code HTTP status code (i.e. 200 for OK)
- * @param response response to transmit
- * @return MHD_NO on error (i.e. reply already sent),
- *         MHD_YES on success or if message has been queued
- */
-int
-MHD_queue_response (struct MHD_Connection *connection,
-                    unsigned int status_code, struct MHD_Response *response)
-{
-  if ( (NULL == connection) ||
-       (NULL == response) ||
-       (NULL != connection->response) ||
-       ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
-        (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
-    return MHD_NO;
-  MHD_increment_response_rc (response);
-  connection->response = response;
-  connection->responseCode = status_code;
-  if ( (NULL != connection->method) &&
-       (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)) )
-    {
-      /* if this is a "HEAD" request, pretend that we
-         have already sent the full message body */
-      connection->response_write_position = response->total_size;
-    }
-  if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
-    {
-      /* response was queued "early",
-         refuse to read body / footers or further
-         requests! */
-      (void) SHUTDOWN (connection->socket_fd, SHUT_RD);
-      connection->read_closed = MHD_YES;
-      connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Do we (still) need to send a 100 continue
- * message for this connection?
- *
- * @param connection connection to test
- * @return 0 if we don't need 100 CONTINUE, 1 if we do
- */
-static int
-need_100_continue (struct MHD_Connection *connection)
-{
-  const char *expect;
-
-  return ( (NULL == connection->response) &&
-          (NULL != connection->version) &&
-          (0 == strcasecmp (connection->version,
-                            MHD_HTTP_VERSION_1_1)) &&
-          (NULL != (expect = MHD_lookup_connection_value (connection,
-                                                          MHD_HEADER_KIND,
-                                                          
MHD_HTTP_HEADER_EXPECT))) &&
-          (0 == strcasecmp (expect, "100-continue")) &&
-          (connection->continue_message_write_offset <
-           strlen (HTTP_100_CONTINUE)) );
-}
-
-
-/**
- * Close the given connection and give the
- * specified termination code to the user.
- *
- * @param connection connection to close
- * @param termination_code termination reason to give
- */
-void
-MHD_connection_close (struct MHD_Connection *connection,
-                      enum MHD_RequestTerminationCode termination_code)
-{
-  struct MHD_Daemon *daemon;
-
-  daemon = connection->daemon;
-  SHUTDOWN (connection->socket_fd, 
-           (connection->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);
-  connection->state = MHD_CONNECTION_CLOSED;
-  if ( (NULL != daemon->notify_completed) &&
-       (MHD_YES == connection->client_aware) )
-    daemon->notify_completed (daemon->notify_completed_cls, 
-                             connection,
-                             &connection->client_context,
-                             termination_code);
-  connection->client_aware = MHD_NO;
-}
-
-
-/**
- * A serious error occured, close the
- * connection (and notify the application).
- *
- * @param connection connection to close with error
- * @param emsg error message (can be NULL)
- */
-static void
-connection_close_error (struct MHD_Connection *connection,
-                       const char *emsg)
-{
-#if HAVE_MESSAGES
-  if (NULL != emsg)
-    MHD_DLOG (connection->daemon, emsg);
-#endif
-  MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
-}
-
-
-/**
- * Macro to only include error message in call to
- * "connection_close_error" if we have HAVE_MESSAGES.
- */
-#if HAVE_MESSAGES
-#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
-#else
-#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
-#endif
-
-
-/**
- * Prepare the response buffer of this connection for
- * sending.  Assumes that the response mutex is
- * already held.  If the transmission is complete,
- * this function may close the socket (and return
- * MHD_NO).
- *
- * @param connection the connection
- * @return MHD_NO if readying the response failed
- */
-static int
-try_ready_normal_body (struct MHD_Connection *connection)
-{
-  ssize_t ret;
-  struct MHD_Response *response;
-
-  response = connection->response;
-  if (NULL == response->crc)
-    return MHD_YES;
-  if (0 == response->total_size)
-    return MHD_YES; /* 0-byte response is always ready */
-  if ( (response->data_start <=
-       connection->response_write_position) &&
-       (response->data_size + response->data_start >
-       connection->response_write_position) )
-    return MHD_YES; /* response already ready */
-#if LINUX
-  if ( (-1 != response->fd) &&
-       (0 == (connection->daemon->options & MHD_USE_SSL)) )
-    {
-      /* will use sendfile, no need to bother response crc */
-      return MHD_YES; 
-    }
-#endif
-  
-  ret = response->crc (response->crc_cls,
-                       connection->response_write_position,
-                       response->data,
-                       MHD_MIN (response->data_buffer_size,
-                                response->total_size -
-                                connection->response_write_position));
-  if ((0 == ret) &&
-      (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
-    mhd_panic (mhd_panic_cls, __FILE__, __LINE__
-#if HAVE_MESSAGES
-              , "API violation"
-#else
-              , NULL
-#endif
-              );
-  if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
-       (MHD_CONTENT_READER_END_WITH_ERROR == ret) )
-    {
-      /* either error or http 1.0 transfer, close socket! */
-      response->total_size = connection->response_write_position;
-      CONNECTION_CLOSE_ERROR (connection,
-                             (ret == MHD_CONTENT_READER_END_OF_STREAM) 
-                             ? "Closing connection (end of response)\n"
-                             : "Closing connection (stream error)\n");
-      return MHD_NO;
-    }
-  response->data_start = connection->response_write_position;
-  response->data_size = ret;
-  if (0 == ret)
-    {
-      connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
-      return MHD_NO;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Prepare the response buffer of this connection for sending.
- * Assumes that the response mutex is already held.  If the
- * transmission is complete, this function may close the socket (and
- * return MHD_NO).
- *
- * @param connection the connection
- * @return MHD_NO if readying the response failed
- */
-static int
-try_ready_chunked_body (struct MHD_Connection *connection)
-{
-  ssize_t ret;
-  char *buf;
-  struct MHD_Response *response;
-  size_t size;
-  char cbuf[10];                /* 10: max strlen of "%x\r\n" */
-  int cblen;
-
-  response = connection->response;
-  if (0 == connection->write_buffer_size)
-    {
-      size = connection->daemon->pool_size;
-      do
-        {
-          size /= 2;
-          if (size < 128)
-            {
-              /* not enough memory */
-              CONNECTION_CLOSE_ERROR (connection,
-                                     "Closing connection (out of memory)\n");
-              return MHD_NO;
-            }
-          buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
-        }
-      while (NULL == buf);
-      connection->write_buffer_size = size;
-      connection->write_buffer = buf;
-    }
-
-  if ( (response->data_start <=
-       connection->response_write_position) &&
-       (response->data_size + response->data_start >
-       connection->response_write_position) )
-    {
-      /* buffer already ready, use what is there for the chunk */
-      ret = response->data_size + response->data_start - 
connection->response_write_position;
-      if (ret > connection->write_buffer_size - sizeof (cbuf) - 2)
-       ret = connection->write_buffer_size - sizeof (cbuf) - 2;
-      memcpy (&connection->write_buffer[sizeof (cbuf)],
-             &response->data[connection->response_write_position - 
response->data_start],
-             ret);
-    }
-  else
-    {
-      /* buffer not in range, try to fill it */
-      if (0 == response->total_size)
-       ret = 0; /* response must be empty, don't bother calling crc */
-      else
-       ret = response->crc (response->crc_cls,
-                            connection->response_write_position,
-                            &connection->write_buffer[sizeof (cbuf)],
-                            connection->write_buffer_size - sizeof (cbuf) - 2);
-    }
-  if (MHD_CONTENT_READER_END_WITH_ERROR == ret)
-    {
-      /* error, close socket! */
-      response->total_size = connection->response_write_position;
-      CONNECTION_CLOSE_ERROR (connection,
-                             "Closing connection (error generating 
response)\n");
-      return MHD_NO;
-    }
-  if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
-       (0 == response->total_size) )
-    {
-      /* end of message, signal other side! */
-      strcpy (connection->write_buffer, "0\r\n");
-      connection->write_buffer_append_offset = 3;
-      connection->write_buffer_send_offset = 0;
-      response->total_size = connection->response_write_position;
-      return MHD_YES;
-    }
-  if (0 == ret) 
-    {
-      connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
-      return MHD_NO;
-    }
-  if (ret > 0xFFFFFF)
-    ret = 0xFFFFFF;
-  snprintf (cbuf, 
-           sizeof (cbuf),
-           "%X\r\n", (unsigned int) ret);
-  cblen = strlen (cbuf);
-  EXTRA_CHECK (cblen <= sizeof (cbuf));
-  memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
-  memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
-  connection->response_write_position += ret;
-  connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
-  connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
-  return MHD_YES;
-}
-
-
-/**
- * Check if we need to set some additional headers
- * for http-compiliance.
- *
- * @param connection connection to check (and possibly modify)
- */
-static void
-add_extra_headers (struct MHD_Connection *connection)
-{
-  const char *have_close;
-  const char *client_close;
-  const char *have_encoding;
-  char buf[128];
-  int add_close;
-
-  client_close = MHD_lookup_connection_value (connection,
-                                             MHD_HEADER_KIND,
-                                             MHD_HTTP_HEADER_CONNECTION);
-  /* we only care about 'close', everything else is ignored */
-  if ( (NULL != client_close) && (0 != strcasecmp (client_close, "close")) )
-    client_close = NULL;
-  have_close = MHD_get_response_header (connection->response,
-                                       MHD_HTTP_HEADER_CONNECTION);
-  if ( (NULL != have_close) && (0 != strcasecmp (have_close, "close")) )
-    have_close = NULL;
-  connection->have_chunked_upload = MHD_NO;
-  add_close = MHD_NO;
-  if (MHD_SIZE_UNKNOWN == connection->response->total_size)
-    {
-      /* size is unknown, need to either to HTTP 1.1 chunked encoding or
-        close the connection */
-      if (NULL == have_close)
-        {
-         /* 'close' header doesn't exist yet, see if we need to add one;
-            if the client asked for a close, no need to start chunk'ing */
-          if ((NULL == client_close) &&
-             (NULL != connection->version) &&
-              (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) 
-            {
-              connection->have_chunked_upload = MHD_YES;
-              have_encoding = MHD_get_response_header (connection->response,
-                                                      
MHD_HTTP_HEADER_TRANSFER_ENCODING);
-              if (NULL == have_encoding)
-                MHD_add_response_header (connection->response,
-                                         MHD_HTTP_HEADER_TRANSFER_ENCODING,
-                                         "chunked");
-             else if (0 != strcasecmp (have_encoding, "chunked"))
-               add_close = MHD_YES; /* application already set some strange 
encoding, can't do 'chunked' */
-            }
-          else
-            {
-             /* HTTP not 1.1 or client asked for close => set close header */
-             add_close = MHD_YES;
-            }
-        }
-    }
-  else
-    {
-      /* check if we should add a 'close' anyway */
-      if ( (NULL != client_close) &&
-          (NULL == have_close) )
-       add_close = MHD_YES; /* client asked for it, so add it */
-
-      /* if not present, add content length */
-      if (NULL == MHD_get_response_header (connection->response,
-                                          MHD_HTTP_HEADER_CONTENT_LENGTH))
-       {
-         SPRINTF (buf,
-                  MHD_UNSIGNED_LONG_LONG_PRINTF,
-                  (MHD_UNSIGNED_LONG_LONG) connection->response->total_size);
-         MHD_add_response_header (connection->response,
-                                  MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
-       }
-    }
-  if (MHD_YES == add_close)
-    MHD_add_response_header (connection->response,
-                            MHD_HTTP_HEADER_CONNECTION, "close");
-}
-
-
-/**
- * Produce HTTP "Date:" header.
- *
- * @param date where to write the header, with
- *        at least 128 bytes available space.
- */
-static void
-get_date_string (char *date)
-{
-  static const char *const days[] =
-    { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
-  static const char *const mons[] =
-    { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
-    "Nov", "Dec"
-  };
-  struct tm now;
-  time_t t;
-
-  time (&t);
-  gmtime_r (&t, &now);
-  SPRINTF (date,
-           "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
-           days[now.tm_wday % 7],
-           (unsigned int) now.tm_mday,
-           mons[now.tm_mon % 12],
-           (unsigned int) (1900 + now.tm_year),
-          (unsigned int) now.tm_hour, 
-          (unsigned int) now.tm_min, 
-          (unsigned int) now.tm_sec);
-}
-
-
-/**
- * Try growing the read buffer.  We initially claim half the
- * available buffer space for the read buffer (the other half
- * being left for management data structures; the write
- * buffer can in the end take virtually everything as the 
- * read buffer can be reduced to the minimum necessary at that
- * point.
- *
- * @param connection the connection
- * @return MHD_YES on success, MHD_NO on failure
- */
-static int
-try_grow_read_buffer (struct MHD_Connection *connection)
-{
-  void *buf;
-  size_t new_size;
-
-  if (0 == connection->read_buffer_size)
-    new_size = connection->daemon->pool_size / 2;
-  else
-    new_size = connection->read_buffer_size + MHD_BUF_INC_SIZE;
-  buf = MHD_pool_reallocate (connection->pool,
-                             connection->read_buffer,
-                             connection->read_buffer_size,
-                             new_size);
-  if (NULL == buf)
-    return MHD_NO;
-  /* we can actually grow the buffer, do it! */
-  connection->read_buffer = buf;
-  connection->read_buffer_size = new_size;
-  return MHD_YES;
-}
-
-
-/**
- * Allocate the connection's write buffer and fill it with all of the
- * headers (or footers, if we have already sent the body) from the
- * HTTPd's response.
- *
- * @param connection the connection
- */
-static int
-build_header_response (struct MHD_Connection *connection)
-{
-  size_t size;
-  size_t off;
-  struct MHD_HTTP_Header *pos;
-  char code[256];
-  char date[128];
-  char *data;
-  enum MHD_ValueKind kind;
-  const char *reason_phrase;
-  uint32_t rc;
-  int must_add_close;
-
-  EXTRA_CHECK (NULL != connection->version);
-  if (0 == strlen(connection->version))
-    {
-      data = MHD_pool_allocate (connection->pool, 0, MHD_YES);
-      connection->write_buffer = data;
-      connection->write_buffer_append_offset = 0;
-      connection->write_buffer_send_offset = 0;
-      connection->write_buffer_size = 0;
-      return MHD_YES;
-    }
-  if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
-    {
-      add_extra_headers (connection);
-      rc = connection->responseCode & (~MHD_ICY_FLAG);
-      reason_phrase = MHD_get_reason_phrase_for (rc);
-      SPRINTF (code,
-               "%s %u %s\r\n",
-              (0 != (connection->responseCode & MHD_ICY_FLAG))
-              ? "ICY" 
-              : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0,
-                                    connection->version)) 
-                  ? MHD_HTTP_VERSION_1_0 
-                  : MHD_HTTP_VERSION_1_1),
-              rc, 
-              reason_phrase);
-      off = strlen (code);
-      /* estimate size */
-      size = off + 2;           /* extra \r\n at the end */
-      kind = MHD_HEADER_KIND;
-      if ( (0 == (connection->daemon->options & MHD_SUPPRESS_DATE_NO_CLOCK)) 
&& 
-          (NULL == MHD_get_response_header (connection->response,
-                                            MHD_HTTP_HEADER_DATE)) )
-        get_date_string (date);
-      else
-        date[0] = '\0';
-      size += strlen (date);
-    }
-  else
-    {
-      size = 2;
-      kind = MHD_FOOTER_KIND;
-      off = 0;
-    }
-  must_add_close = ( (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) &&
-                    (connection->read_closed == MHD_YES) &&
-                    (0 == strcasecmp (connection->version,
-                                      MHD_HTTP_VERSION_1_1)) &&
-                    (NULL == MHD_get_response_header (connection->response,
-                                                      
MHD_HTTP_HEADER_CONNECTION)) );
-  if (must_add_close)
-    size += strlen ("Connection: close\r\n");
-  for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
-    if (pos->kind == kind)
-      size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, 
linefeeds */
-  /* produce data */
-  data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
-  if (NULL == data)
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
-#endif
-      return MHD_NO;
-    }
-  if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
-    {
-      memcpy (data, code, off);
-    }
-  if (must_add_close)
-    {
-      /* we must add the 'close' header because circumstances forced us to
-        stop reading from the socket; however, we are not adding the header
-        to the response as the response may be used in a different context
-        as well */
-      memcpy (&data[off], "Connection: close\r\n",
-             strlen ("Connection: close\r\n"));
-      off += strlen ("Connection: close\r\n");
-    }
-  for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
-    if (pos->kind == kind)
-      off += SPRINTF (&data[off], 
-                     "%s: %s\r\n",
-                     pos->header, 
-                     pos->value);
-  if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
-    {
-      strcpy (&data[off], date);
-      off += strlen (date);
-    }
-  memcpy (&data[off], "\r\n", 2);
-  off += 2;
-
-  if (off != size)
-    mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
-  connection->write_buffer = data;
-  connection->write_buffer_append_offset = size;
-  connection->write_buffer_send_offset = 0;
-  connection->write_buffer_size = size + 1;
-  return MHD_YES;
-}
-
-
-/**
- * We encountered an error processing the request.
- * Handle it properly by stopping to read data
- * and sending the indicated response code and message.
- *
- * @param connection the connection
- * @param status_code the response code to send (400, 413 or 414)
- * @param message the error message to send
- */
-static void
-transmit_error_response (struct MHD_Connection *connection,
-                         unsigned int status_code, 
-                        const char *message)
-{
-  struct MHD_Response *response;
-
-  if (NULL == connection->version)
-    {
-      /* we were unable to process the full header line, so we don't
-        really know what version the client speaks; assume 1.0 */
-      connection->version = MHD_HTTP_VERSION_1_0;
-    }
-  connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-  connection->read_closed = MHD_YES;
-#if HAVE_MESSAGES
-  MHD_DLOG (connection->daemon,
-            "Error %u (`%s') processing request, closing connection.\n",
-            status_code, message);
-#endif
-  EXTRA_CHECK (connection->response == NULL);
-  response = MHD_create_response_from_buffer (strlen (message),
-                                             (void *) message, 
-                                             MHD_RESPMEM_PERSISTENT);
-  MHD_queue_response (connection, status_code, response);
-  EXTRA_CHECK (connection->response != NULL);
-  MHD_destroy_response (response);
-  if (MHD_NO == build_header_response (connection))
-    {
-      /* oops - close! */
-      CONNECTION_CLOSE_ERROR (connection,
-                             "Closing connection (failed to create response 
header)\n");
-    }
-  else
-    {
-      connection->state = MHD_CONNECTION_HEADERS_SENDING;
-    }
-}
-
-
-/**
- * Add "fd" to the "fd_set".  If "fd" is
- * greater than "*max", set "*max" to fd.
- *
- * @param fd file descriptor to add to the set
- * @param set set to modify
- * @param max_fd maximum value to potentially update
- */
-static void
-add_to_fd_set (int fd, 
-              fd_set *set, 
-              int *max_fd)
-{
-  FD_SET (fd, set);
-  if ( (NULL != max_fd) &&
-       (fd > *max_fd) )
-    *max_fd = fd;
-}
-
-
-/**
- * Obtain the select sets for this connection.  The given
- * sets (and the maximum) are updated and must have 
- * already been initialized.
- *
- * @param connection connetion to get select sets for
- * @param read_fd_set read set to initialize
- * @param write_fd_set write set to initialize
- * @param except_fd_set except set to initialize (never changed)
- * @param max_fd where to store largest FD put into any set
- * @return MHD_YES on success
- */
-int
-MHD_connection_get_fdset (struct MHD_Connection *connection,
-                          fd_set *read_fd_set,
-                          fd_set *write_fd_set,
-                          fd_set *except_fd_set, 
-                         int *max_fd)
-{
-  int ret;
-  struct MHD_Pollfd p;
-
-  /* we use the 'poll fd' as a convenient way to re-use code 
-     when determining the select sets */
-  memset (&p, 0, sizeof(struct MHD_Pollfd));
-  ret = MHD_connection_get_pollfd (connection, &p);
-  if ( (MHD_YES == ret) && (p.fd >= 0) ) {
-    if (0 != (p.events & MHD_POLL_ACTION_IN)) 
-      add_to_fd_set(p.fd, read_fd_set, max_fd);    
-    if (0 != (p.events & MHD_POLL_ACTION_OUT)) 
-      add_to_fd_set(p.fd, write_fd_set, max_fd);    
-  }
-  return ret;
-}
-
-
-/**
- * Obtain the pollfd for this connection
- *
- * @param connection connetion to get poll set for 
- * @param p where to store the polling information
- * @return MHD_YES on success. If return MHD_YES and p->fd < 0, this 
- *                 connection is not waiting for any read or write events
- */
-int
-MHD_connection_get_pollfd (struct MHD_Connection *connection, 
-                          struct MHD_Pollfd *p)
-{
-  int fd;
-
-  if (NULL == connection->pool)
-    connection->pool = MHD_pool_create (connection->daemon->pool_size);
-  if (NULL == connection->pool)
-    {
-      CONNECTION_CLOSE_ERROR (connection,
-                             "Failed to create memory pool!\n");
-      return MHD_YES;
-    }
-  fd = connection->socket_fd;
-  p->fd = fd;
-  if (-1 == fd)
-    return MHD_YES;
-  while (1)
-    {
-#if DEBUG_STATES
-      MHD_DLOG (connection->daemon, "%s: state: %s\n",
-                __FUNCTION__, MHD_state_to_string (connection->state));
-#endif
-      switch (connection->state)
-        {
-#if HTTPS_SUPPORT     
-       case MHD_TLS_CONNECTION_INIT:
-         if (0 == gnutls_record_get_direction (connection->tls_session))
-            p->events |= MHD_POLL_ACTION_IN;
-         else
-           p->events |= MHD_POLL_ACTION_OUT;
-         break;
-#endif
-        case MHD_CONNECTION_INIT:
-        case MHD_CONNECTION_URL_RECEIVED:
-        case MHD_CONNECTION_HEADER_PART_RECEIVED:
-          /* while reading headers, we always grow the
-             read buffer if needed, no size-check required */
-          if ((connection->read_closed) &&
-              (0 == connection->read_buffer_offset))
-            {
-             CONNECTION_CLOSE_ERROR (connection, 
-                                     "Connection buffer to small for 
request\n");
-              continue;
-            }
-          if ((connection->read_buffer_offset == connection->read_buffer_size)
-              && (MHD_NO == try_grow_read_buffer (connection)))
-            {
-              transmit_error_response (connection,
-                                       (connection->url != NULL)
-                                       ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
-                                       : MHD_HTTP_REQUEST_URI_TOO_LONG,
-                                       REQUEST_TOO_BIG);
-              continue;
-            }
-          if (MHD_NO == connection->read_closed)
-            p->events |= MHD_POLL_ACTION_IN;
-          break;
-        case MHD_CONNECTION_HEADERS_RECEIVED:
-          /* we should never get here */
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_HEADERS_PROCESSED:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_CONTINUE_SENDING:
-          p->events |= MHD_POLL_ACTION_OUT;
-          break;
-        case MHD_CONNECTION_CONTINUE_SENT:
-          if (connection->read_buffer_offset == connection->read_buffer_size)
-            {
-              if ((MHD_YES != try_grow_read_buffer (connection)) &&
-                  (0 != (connection->daemon->options &
-                         (MHD_USE_SELECT_INTERNALLY |
-                          MHD_USE_THREAD_PER_CONNECTION))))
-                {
-                  /* failed to grow the read buffer, and the
-                     client which is supposed to handle the
-                     received data in a *blocking* fashion
-                     (in this mode) did not handle the data as
-                     it was supposed to!
-                     => we would either have to do busy-waiting
-                     (on the client, which would likely fail),
-                     or if we do nothing, we would just timeout
-                     on the connection (if a timeout is even
-                     set!).
-                     Solution: we kill the connection with an error */
-                  transmit_error_response (connection,
-                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                           INTERNAL_ERROR);
-                  continue;
-                }
-            }
-          if ((connection->read_buffer_offset < connection->read_buffer_size)
-              && (MHD_NO == connection->read_closed))
-            p->events |= MHD_POLL_ACTION_IN;
-          break;
-        case MHD_CONNECTION_BODY_RECEIVED:
-        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-          /* while reading footers, we always grow the
-             read buffer if needed, no size-check required */
-          if (MHD_YES == connection->read_closed)
-            {
-             CONNECTION_CLOSE_ERROR (connection, 
-                                     NULL);
-              continue;
-            }
-          p->events |= MHD_POLL_ACTION_IN;
-          /* transition to FOOTERS_RECEIVED
-             happens in read handler */
-          break;
-        case MHD_CONNECTION_FOOTERS_RECEIVED:
-          /* no socket action, wait for client
-             to provide response */
-          break;
-        case MHD_CONNECTION_HEADERS_SENDING:
-          /* headers in buffer, keep writing */
-          p->events |= MHD_POLL_ACTION_OUT;
-          break;
-        case MHD_CONNECTION_HEADERS_SENT:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_NORMAL_BODY_READY:
-          p->events |= MHD_POLL_ACTION_OUT;
-          break;
-        case MHD_CONNECTION_NORMAL_BODY_UNREADY:
-          /* not ready, no socket action */
-          break;
-        case MHD_CONNECTION_CHUNKED_BODY_READY:
-          p->events |= MHD_POLL_ACTION_OUT;
-          break;
-        case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
-          /* not ready, no socket action */
-          break;
-        case MHD_CONNECTION_BODY_SENT:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_FOOTERS_SENDING:
-          p->events |= MHD_POLL_ACTION_OUT;
-          break;
-        case MHD_CONNECTION_FOOTERS_SENT:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_CLOSED:
-          return MHD_YES;       /* do nothing, not even reading */
-        default:
-          EXTRA_CHECK (0);
-        }
-      break;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Parse a single line of the HTTP header.  Advance
- * read_buffer (!) appropriately.  If the current line does not
- * fit, consider growing the buffer.  If the line is
- * far too long, close the connection.  If no line is
- * found (incomplete, buffer too small, line too long),
- * return NULL.  Otherwise return a pointer to the line.
- */
-static char *
-get_next_header_line (struct MHD_Connection *connection)
-{
-  char *rbuf;
-  size_t pos;
-
-  if (0 == connection->read_buffer_offset)
-    return NULL;
-  pos = 0;
-  rbuf = connection->read_buffer;
-  while ((pos < connection->read_buffer_offset - 1) &&
-         ('\r' != rbuf[pos]) && ('\n' != rbuf[pos]))
-    pos++;
-  if (pos == connection->read_buffer_offset - 1)
-    {
-      /* not found, consider growing... */
-      if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
-          (MHD_NO == 
-           try_grow_read_buffer (connection)) )
-       {
-         transmit_error_response (connection,
-                                  (NULL != connection->url)
-                                  ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
-                                  : MHD_HTTP_REQUEST_URI_TOO_LONG,
-                                  REQUEST_TOO_BIG);
-       }        
-      return NULL;
-    }
-  /* found, check if we have proper CRLF */
-  if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1]))
-    rbuf[pos++] = '\0';         /* skip both r and n */
-  rbuf[pos++] = '\0';
-  connection->read_buffer += pos;
-  connection->read_buffer_size -= pos;
-  connection->read_buffer_offset -= pos;
-  return rbuf;
-}
-
-
-/**
- * Add an entry to the HTTP headers of a connection.  If this fails,
- * transmit an error response (request too big).
- *
- * @param connection the connection for which a
- *  value should be set
- * @param kind kind of the value
- * @param key key for the value
- * @param value the value itself
- * @return MHD_NO on failure (out of memory), MHD_YES for success
- */
-static int
-connection_add_header (struct MHD_Connection *connection,
-                       char *key, char *value, enum MHD_ValueKind kind)
-{
-  if (MHD_NO == MHD_set_connection_value (connection,
-                                         kind,
-                                         key, value))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon,
-                "Not enough memory to allocate header record!\n");
-#endif
-      transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
-                               REQUEST_TOO_BIG);
-      return MHD_NO;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Parse and unescape the arguments given by the client as part
- * of the HTTP request URI.
- *
- * @param kind header kind to use for adding to the connection
- * @param connection connection to add headers to
- * @param args argument URI string (after "?" in URI)
- * @return MHD_NO on failure (out of memory), MHD_YES for success
- */
-static int
-parse_arguments (enum MHD_ValueKind kind,
-                 struct MHD_Connection *connection, 
-                char *args)
-{
-  char *equals;
-  char *amper;
-
-  while (NULL != args)
-    {
-      equals = strchr (args, '=');
-      amper = strchr (args, '&');
-      if (NULL == amper)
-       {
-         /* last argument */
-         if (NULL == equals)
-           {
-             /* got 'foo', add key 'foo' with NULL for value */
-             connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                                    connection,
-                                                    args);
-             return connection_add_header (connection,
-                                           args,
-                                           NULL,
-                                           kind);            
-           }
-         /* got 'foo=bar' */
-         equals[0] = '\0';
-         equals++;
-         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                                connection,
-                                                args);
-         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                                connection,
-                                                equals);
-         return connection_add_header (connection, args, equals, kind);
-       }
-      /* amper is non-NULL here */
-      amper[0] = '\0';
-      amper++;
-      if ( (NULL == equals) ||
-          (equals >= amper) )
-       {
-         /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value 
*/
-         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                                connection,
-                                                args);
-         if (MHD_NO ==
-             connection_add_header (connection,
-                                    args,
-                                    NULL,
-                                    kind))
-           return MHD_NO;
-         /* continue with 'bar' */
-         args = amper;
-         continue;
-
-       }
-      /* equals and amper are non-NULL here, and equals < amper,
-        so we got regular 'foo=value&bar...'-kind of argument */
-      equals[0] = '\0';
-      equals++;
-      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                            connection,
-                                            args);
-      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                            connection,
-                                            equals);
-      if (MHD_NO == connection_add_header (connection, args, equals, kind))
-        return MHD_NO;
-      args = amper;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Parse the cookie header (see RFC 2109).
- *
- * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory)
- */
-static int
-parse_cookie_header (struct MHD_Connection *connection)
-{
-  const char *hdr;
-  char *cpy;
-  char *pos;
-  char *sce;
-  char *semicolon;
-  char *equals;
-  char *ekill;
-  char old;
-  int quotes;
-
-  hdr = MHD_lookup_connection_value (connection,
-                                    MHD_HEADER_KIND,
-                                    MHD_HTTP_HEADER_COOKIE);
-  if (hdr == NULL)
-    return MHD_YES;
-  cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
-  if (cpy == NULL)
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
-#endif
-      transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
-                               REQUEST_TOO_BIG);
-      return MHD_NO;
-    }
-  memcpy (cpy, hdr, strlen (hdr) + 1);
-  pos = cpy;
-  while (pos != NULL)
-    {
-      while (*pos == ' ')
-        pos++;                  /* skip spaces */
-
-      sce = pos;
-      while (((*sce) != '\0') &&
-             ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
-        sce++;
-      /* remove tailing whitespace (if any) from key */
-      ekill = sce - 1;
-      while ((*ekill == ' ') && (ekill >= pos))
-        *(ekill--) = '\0';
-      old = *sce;
-      *sce = '\0';
-      if (old != '=')
-        {
-          /* value part omitted, use empty string... */
-          if (MHD_NO ==
-              connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
-            return MHD_NO;
-          if (old == '\0')
-            break;
-          pos = sce + 1;
-          continue;
-        }
-      equals = sce + 1;
-      quotes = 0;
-      semicolon = equals;
-      while ((semicolon[0] != '\0') &&
-             ((quotes != 0) ||
-              ((semicolon[0] != ';') && (semicolon[0] != ','))))
-        {
-          if (semicolon[0] == '"')
-            quotes = (quotes + 1) & 1;
-          semicolon++;
-        }
-      if (semicolon[0] == '\0')
-        semicolon = NULL;
-      if (semicolon != NULL)
-        {
-          semicolon[0] = '\0';
-          semicolon++;
-        }
-      /* remove quotes */
-      if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
-        {
-          equals[strlen (equals) - 1] = '\0';
-          equals++;
-        }
-      if (MHD_NO == connection_add_header (connection,
-                                           pos, equals, MHD_COOKIE_KIND))
-        return MHD_NO;
-      pos = semicolon;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Parse the first line of the HTTP HEADER.
- *
- * @param connection the connection (updated)
- * @param line the first line
- * @return MHD_YES if the line is ok, MHD_NO if it is malformed
- */
-static int
-parse_initial_message_line (struct MHD_Connection *connection, char *line)
-{
-  char *uri;
-  char *httpVersion;
-  char *args;
-
-  if (NULL == (uri = strchr (line, ' ')))
-    return MHD_NO;              /* serious error */
-  uri[0] = '\0';
-  connection->method = line;
-  uri++;
-  while (uri[0] == ' ')
-    uri++;
-  httpVersion = strchr (uri, ' ');
-  if (httpVersion != NULL)
-    {
-      httpVersion[0] = '\0';
-      httpVersion++;
-    }
-  if (connection->daemon->uri_log_callback != NULL)
-    connection->client_context
-      =
-      connection->daemon->uri_log_callback (connection->daemon->
-                                            uri_log_callback_cls, uri);
-  args = strchr (uri, '?');
-  if (NULL != args)
-    {
-      args[0] = '\0';
-      args++;
-      parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
-    }
-  connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                        connection,
-                                        uri);
-  connection->url = uri;
-  if (NULL == httpVersion)
-    connection->version = "";
-  else
-    connection->version = httpVersion;
-  return MHD_YES;
-}
-
-
-/**
- * Call the handler of the application for this
- * connection.  Handles chunking of the upload
- * as well as normal uploads.
- */
-static void
-call_connection_handler (struct MHD_Connection *connection)
-{
-  size_t processed;
-
-  if (NULL != connection->response)
-    return;                     /* already queued a response */  
-  processed = 0;
-  connection->client_aware = MHD_YES;
-  if (MHD_NO ==
-      connection->daemon->default_handler (connection->daemon->
-                                          default_handler_cls,
-                                          connection, connection->url,
-                                          connection->method,
-                                          connection->version,
-                                          NULL, &processed,
-                                          &connection->client_context))
-    {
-      /* serious internal error, close connection */
-      CONNECTION_CLOSE_ERROR (connection, 
-                             "Internal application error, closing 
connection.\n");
-      return;
-    }
-}
-
-
-
-/**
- * Call the handler of the application for this
- * connection.  Handles chunking of the upload
- * as well as normal uploads.
- */
-static void
-process_request_body (struct MHD_Connection *connection)
-{
-  size_t processed;
-  size_t available;
-  size_t used;
-  size_t i;
-  int instant_retry;
-  int malformed;
-  char *buffer_head;
-  char *end;
-
-  if (NULL != connection->response)
-    return;                     /* already queued a response */
-
-  buffer_head = connection->read_buffer;
-  available = connection->read_buffer_offset;
-  do
-    {
-      instant_retry = MHD_NO;
-      if ((connection->have_chunked_upload == MHD_YES) &&
-          (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
-        {
-          if ((connection->current_chunk_offset ==
-               connection->current_chunk_size)
-              && (connection->current_chunk_offset != 0) && (available >= 2))
-            {
-              /* skip new line at the *end* of a chunk */
-              i = 0;
-              if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
-                i++;            /* skip 1st part of line feed */
-              if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
-                i++;            /* skip 2nd part of line feed */
-              if (i == 0)
-                {
-                  /* malformed encoding */
-                  CONNECTION_CLOSE_ERROR (connection,
-                                         "Received malformed HTTP request (bad 
chunked encoding), closing connection.\n");
-                  return;
-                }
-              available -= i;
-              buffer_head += i;
-              connection->current_chunk_offset = 0;
-              connection->current_chunk_size = 0;
-            }
-          if (connection->current_chunk_offset <
-              connection->current_chunk_size)
-            {
-              /* we are in the middle of a chunk, give
-                 as much as possible to the client (without
-                 crossing chunk boundaries) */
-              processed =
-                connection->current_chunk_size -
-                connection->current_chunk_offset;
-              if (processed > available)
-                processed = available;
-              if (available > processed)
-                instant_retry = MHD_YES;
-            }
-          else
-            {
-              /* we need to read chunk boundaries */
-              i = 0;
-              while (i < available)
-                {
-                  if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
-                    break;
-                  i++;
-                  if (i >= 6)
-                    break;
-                }
-              /* take '\n' into account; if '\n'
-                 is the unavailable character, we
-                 will need to wait until we have it
-                 before going further */
-              if ((i + 1 >= available) &&
-                  !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
-                break;          /* need more data... */
-              malformed = (i >= 6);
-              if (!malformed)
-                {
-                  buffer_head[i] = '\0';
-                 connection->current_chunk_size = strtoul (buffer_head, &end, 
16);
-                  malformed = ('\0' != *end);
-                }
-              if (malformed)
-                {
-                  /* malformed encoding */
-                  CONNECTION_CLOSE_ERROR (connection,
-                                         "Received malformed HTTP request (bad 
chunked encoding), closing connection.\n");
-                  return;
-                }
-              i++;
-              if ((i < available) &&
-                  ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
-                i++;            /* skip 2nd part of line feed */
-
-              buffer_head += i;
-              available -= i;
-              connection->current_chunk_offset = 0;
-
-              if (available > 0)
-                instant_retry = MHD_YES;
-              if (connection->current_chunk_size == 0)
-                {
-                  connection->remaining_upload_size = 0;
-                  break;
-                }
-              continue;
-            }
-        }
-      else
-        {
-          /* no chunked encoding, give all to the client */
-          if ( (0 != connection->remaining_upload_size) && 
-              (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
-              (connection->remaining_upload_size < available) )
-           {
-              processed = connection->remaining_upload_size;
-           }
-          else
-           {
-              /**
-               * 1. no chunked encoding, give all to the client
-               * 2. client may send large chunked data, but only a smaller 
part is available at one time.
-               */
-              processed = available;
-           }
-        }
-      used = processed;
-      connection->client_aware = MHD_YES;
-      if (MHD_NO ==
-          connection->daemon->default_handler (connection->daemon->
-                                               default_handler_cls,
-                                               connection, connection->url,
-                                               connection->method,
-                                               connection->version,
-                                               buffer_head, &processed,
-                                               &connection->client_context))
-        {
-          /* serious internal error, close connection */
-         CONNECTION_CLOSE_ERROR (connection,
-                                 "Internal application error, closing 
connection.\n");
-          return;
-        }
-      if (processed > used)
-        mhd_panic (mhd_panic_cls, __FILE__, __LINE__
-#if HAVE_MESSAGES
-                  , "API violation"
-#else
-                  , NULL
-#endif
-                  );
-      if (processed != 0)
-        instant_retry = MHD_NO; /* client did not process everything */
-      used -= processed;
-      if (connection->have_chunked_upload == MHD_YES)
-        connection->current_chunk_offset += used;
-      /* dh left "processed" bytes in buffer for next time... */
-      buffer_head += used;
-      available -= used;
-      if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
-        connection->remaining_upload_size -= used;
-    }
-  while (MHD_YES == instant_retry);
-  if (available > 0)
-    memmove (connection->read_buffer, buffer_head, available);
-  connection->read_buffer_offset = available;
-}
-
-
-/**
- * Try reading data from the socket into the
- * read buffer of the connection.
- *
- * @return MHD_YES if something changed,
- *         MHD_NO if we were interrupted or if
- *                no space was available
- */
-static int
-do_read (struct MHD_Connection *connection)
-{
-  int bytes_read;
-
-  if (connection->read_buffer_size == connection->read_buffer_offset)
-    return MHD_NO;
-
-  bytes_read = connection->recv_cls (connection,
-                                     &connection->read_buffer
-                                     [connection->read_buffer_offset],
-                                     connection->read_buffer_size -
-                                     connection->read_buffer_offset);
-  if (bytes_read < 0)
-    {
-      if ((EINTR == errno) || (EAGAIN == errno))
-        return MHD_NO;
-#if HAVE_MESSAGES
-#if HTTPS_SUPPORT
-      if (0 != (connection->daemon->options & MHD_USE_SSL))
-       MHD_DLOG (connection->daemon,
-                 "Failed to receive data: %s\n",
-                 gnutls_strerror (bytes_read));
-      else
-#endif      
-       MHD_DLOG (connection->daemon,
-                 "Failed to receive data: %s\n", STRERROR (errno));
-#endif
-      CONNECTION_CLOSE_ERROR (connection, NULL);
-      return MHD_YES;
-    }
-  if (0 == bytes_read)
-    {
-      /* other side closed connection */
-      connection->read_closed = MHD_YES;
-      SHUTDOWN (connection->socket_fd, SHUT_RD);
-      return MHD_YES;
-    }
-  connection->read_buffer_offset += bytes_read;
-  return MHD_YES;
-}
-
-/**
- * Try writing data to the socket from the
- * write buffer of the connection.
- *
- * @return MHD_YES if something changed,
- *         MHD_NO if we were interrupted
- */
-static int
-do_write (struct MHD_Connection *connection)
-{
-  int ret;
-
-  ret = connection->send_cls (connection,
-                              &connection->write_buffer
-                              [connection->write_buffer_send_offset],
-                              connection->write_buffer_append_offset
-                              - connection->write_buffer_send_offset);
-
-  if (ret < 0)
-    {
-      if ((EINTR == errno) || (EAGAIN == errno))
-        return MHD_NO;
-#if HAVE_MESSAGES
-#if HTTPS_SUPPORT
-      if (0 != (connection->daemon->options & MHD_USE_SSL))
-       MHD_DLOG (connection->daemon,
-                 "Failed to send data: %s\n",
-                 gnutls_strerror (ret));
-      else
-#endif      
-       MHD_DLOG (connection->daemon,
-                 "Failed to send data: %s\n", STRERROR (errno));
-#endif
-      CONNECTION_CLOSE_ERROR (connection, NULL);
-      return MHD_YES;
-    }
-#if DEBUG_SEND_DATA
-  FPRINTF (stderr,
-           "Sent response: `%.*s'\n",
-           ret,
-           &connection->write_buffer[connection->write_buffer_send_offset]);
-#endif
-  connection->write_buffer_send_offset += ret;
-  return MHD_YES;
-}
-
-
-/**
- * Check if we are done sending the write-buffer.
- * If so, transition into "next_state".
- *
- * @param connection connection to check write status for
- * @param next_state the next state to transition to
- * @return MHY_NO if we are not done, MHD_YES if we are
- */
-static int
-check_write_done (struct MHD_Connection *connection,
-                  enum MHD_CONNECTION_STATE next_state)
-{
-  if (connection->write_buffer_append_offset !=
-      connection->write_buffer_send_offset)
-    return MHD_NO;
-  connection->write_buffer_append_offset = 0;
-  connection->write_buffer_send_offset = 0;
-  connection->state = next_state;
-  MHD_pool_reallocate (connection->pool, connection->write_buffer,
-                       connection->write_buffer_size, 0);
-  connection->write_buffer = NULL;
-  connection->write_buffer_size = 0;
-  return MHD_YES;
-}
-
-
-/**
- * We have received (possibly the beginning of) a line in the
- * header (or footer).  Validate (check for ":") and prepare
- * to process.
- */
-static int
-process_header_line (struct MHD_Connection *connection, char *line)
-{
-  char *colon;
-
-  /* line should be normal header line, find colon */
-  colon = strchr (line, ':');
-  if (colon == NULL)
-    {
-      /* error in header line, die hard */
-      CONNECTION_CLOSE_ERROR (connection, 
-                             "Received malformed line (no colon), closing 
connection.\n");
-      return MHD_NO;
-    }
-  /* zero-terminate header */
-  colon[0] = '\0';
-  colon++;                      /* advance to value */
-  while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
-    colon++;
-  /* we do the actual adding of the connection
-     header at the beginning of the while
-     loop since we need to be able to inspect
-     the *next* header line (in case it starts
-     with a space...) */
-  connection->last = line;
-  connection->colon = colon;
-  return MHD_YES;
-}
-
-
-/**
- * Process a header value that spans multiple lines.
- * The previous line(s) are in connection->last.
- *
- * @param connection connection we're processing
- * @param line the current input line
- * @param kind if the line is complete, add a header
- *        of the given kind
- * @return MHD_YES if the line was processed successfully
- */
-static int
-process_broken_line (struct MHD_Connection *connection,
-                     char *line, enum MHD_ValueKind kind)
-{
-  char *last;
-  char *tmp;
-  size_t last_len;
-  size_t tmp_len;
-
-  last = connection->last;
-  if ((line[0] == ' ') || (line[0] == '\t'))
-    {
-      /* value was continued on the next line, see
-         http://www.jmarshall.com/easy/http/ */
-      last_len = strlen (last);
-      /* skip whitespace at start of 2nd line */
-      tmp = line;
-      while ((tmp[0] == ' ') || (tmp[0] == '\t'))
-        tmp++;                  
-      tmp_len = strlen (tmp);
-      last = MHD_pool_reallocate (connection->pool,
-                                  last,
-                                  last_len + 1,
-                                  last_len + tmp_len + 1);
-      if (last == NULL)
-        {
-          transmit_error_response (connection,
-                                   MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
-                                   REQUEST_TOO_BIG);
-          return MHD_NO;
-        }
-      memcpy (&last[last_len], tmp, tmp_len + 1);
-      connection->last = last;
-      return MHD_YES;           /* possibly more than 2 lines... */
-    }
-  EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
-  if ((MHD_NO == connection_add_header (connection,
-                                        last, connection->colon, kind)))
-    {
-      transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
-                               REQUEST_TOO_BIG);
-      return MHD_NO;
-    }
-  /* we still have the current line to deal with... */
-  if (strlen (line) != 0)
-    {
-      if (MHD_NO == process_header_line (connection, line))
-        {
-          transmit_error_response (connection,
-                                   MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
-          return MHD_NO;
-        }
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Parse the various headers; figure out the size
- * of the upload and make sure the headers follow
- * the protocol.  Advance to the appropriate state.
- */
-static void
-parse_connection_headers (struct MHD_Connection *connection)
-{
-  const char *clen;
-  MHD_UNSIGNED_LONG_LONG cval;
-  struct MHD_Response *response;
-  const char *enc;
-  char *end;
-
-  parse_cookie_header (connection);
-  if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
-      && (NULL != connection->version)
-      && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
-      && (NULL ==
-          MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
-                                       MHD_HTTP_HEADER_HOST)))
-    {
-      /* die, http 1.1 request without host and we are pedantic */
-      connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-      connection->read_closed = MHD_YES;
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon,
-                "Received `%s' request without `%s' header.\n",
-                MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
-#endif
-      EXTRA_CHECK (connection->response == NULL);
-      response =
-        MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST),
-                                        REQUEST_LACKS_HOST,
-                                        MHD_RESPMEM_PERSISTENT);
-      MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
-      MHD_destroy_response (response);
-      return;
-    }
-
-  connection->remaining_upload_size = 0;
-  enc = MHD_lookup_connection_value (connection,
-                                    MHD_HEADER_KIND,
-                                    MHD_HTTP_HEADER_TRANSFER_ENCODING);
-  if (enc != NULL)
-    {
-      connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
-      if (0 == strcasecmp (enc, "chunked"))
-        connection->have_chunked_upload = MHD_YES;
-    }
-  else
-    {
-      clen = MHD_lookup_connection_value (connection,
-                                         MHD_HEADER_KIND,
-                                         MHD_HTTP_HEADER_CONTENT_LENGTH);
-      if (clen != NULL)
-        {
-          cval = strtoul (clen, &end, 10);
-          if ( ('\0' != *end) ||
-            ( (LONG_MAX == cval) && (errno == ERANGE) ) )
-            {
-#if HAVE_MESSAGES
-              MHD_DLOG (connection->daemon,
-                    "Failed to parse `%s' header `%s', closing connection.\n",
-                    MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
-#endif
-             CONNECTION_CLOSE_ERROR (connection, NULL);
-              return;
-            }
-          connection->remaining_upload_size = cval;
-        }
-    }
-}
-
-
-/**
- * This function handles a particular connection when it has been
- * determined that there is data to be read off a socket. All
- * implementations (multithreaded, external select, internal select)
- * call this function to handle reads.
- *
- * @param connection connection to handle
- * @return always MHD_YES (we should continue to process the
- *         connection)
- */
-int
-MHD_connection_handle_read (struct MHD_Connection *connection)
-{
-  connection->last_activity = MHD_monotonic_time();
-  if (connection->state == MHD_CONNECTION_CLOSED)
-    return MHD_YES;
-  /* make sure "read" has a reasonable number of bytes
-     in buffer to use per system call (if possible) */
-  if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
-      connection->read_buffer_size)
-    try_grow_read_buffer (connection);
-  if (MHD_NO == do_read (connection))
-    return MHD_YES;
-  while (1)
-    {
-#if DEBUG_STATES
-      MHD_DLOG (connection->daemon, "%s: state: %s\n",
-                __FUNCTION__, MHD_state_to_string (connection->state));
-#endif
-      switch (connection->state)
-        {
-        case MHD_CONNECTION_INIT:
-        case MHD_CONNECTION_URL_RECEIVED:
-        case MHD_CONNECTION_HEADER_PART_RECEIVED:
-        case MHD_CONNECTION_HEADERS_RECEIVED:
-        case MHD_CONNECTION_HEADERS_PROCESSED:
-        case MHD_CONNECTION_CONTINUE_SENDING:
-        case MHD_CONNECTION_CONTINUE_SENT:
-        case MHD_CONNECTION_BODY_RECEIVED:
-        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-          /* nothing to do but default action */
-          if (MHD_YES == connection->read_closed)
-            {
-             MHD_connection_close (connection,
-                                   MHD_REQUEST_TERMINATED_READ_ERROR);
-              continue;
-            }
-          break;
-        case MHD_CONNECTION_CLOSED:
-          return MHD_YES;
-        default:
-          /* shrink read buffer to how much is actually used */
-          MHD_pool_reallocate (connection->pool,
-                               connection->read_buffer,
-                               connection->read_buffer_size + 1,
-                               connection->read_buffer_offset);
-          break;
-        }
-      break;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * This function was created to handle writes to sockets when it has
- * been determined that the socket can be written to. All
- * implementations (multithreaded, external select, internal select)
- * call this function
- *
- * @param connection connection to handle
- * @return always MHD_YES (we should continue to process the
- *         connection)
- */
-int
-MHD_connection_handle_write (struct MHD_Connection *connection)
-{
-  struct MHD_Response *response;
-  int ret;
-  connection->last_activity = MHD_monotonic_time();
-  while (1)
-    {
-#if DEBUG_STATES
-      MHD_DLOG (connection->daemon, "%s: state: %s\n",
-                __FUNCTION__, MHD_state_to_string (connection->state));
-#endif
-      switch (connection->state)
-        {
-        case MHD_CONNECTION_INIT:
-        case MHD_CONNECTION_URL_RECEIVED:
-        case MHD_CONNECTION_HEADER_PART_RECEIVED:
-        case MHD_CONNECTION_HEADERS_RECEIVED:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_HEADERS_PROCESSED:
-          break;
-        case MHD_CONNECTION_CONTINUE_SENDING:
-          ret = connection->send_cls (connection,
-                                      &HTTP_100_CONTINUE
-                                      
[connection->continue_message_write_offset],
-                                      strlen (HTTP_100_CONTINUE) -
-                                      
connection->continue_message_write_offset);
-          if (ret < 0)
-            {
-              if ((errno == EINTR) || (errno == EAGAIN))
-                break;
-#if HAVE_MESSAGES
-              MHD_DLOG (connection->daemon,
-                        "Failed to send data: %s\n", STRERROR (errno));
-#endif
-             CONNECTION_CLOSE_ERROR (connection, NULL);
-              return MHD_YES;
-            }
-#if DEBUG_SEND_DATA
-          FPRINTF (stderr,
-                   "Sent 100 continue response: `%.*s'\n",
-                   ret,
-                   &HTTP_100_CONTINUE
-                   [connection->continue_message_write_offset]);
-#endif
-          connection->continue_message_write_offset += ret;
-          break;
-        case MHD_CONNECTION_CONTINUE_SENT:
-        case MHD_CONNECTION_BODY_RECEIVED:
-        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-        case MHD_CONNECTION_FOOTERS_RECEIVED:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_HEADERS_SENDING:
-          do_write (connection);
-         if (connection->state != MHD_CONNECTION_HEADERS_SENDING)
-            break;
-          check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
-          break;
-        case MHD_CONNECTION_HEADERS_SENT:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_NORMAL_BODY_READY:
-          response = connection->response;
-          if (response->crc != NULL)
-            pthread_mutex_lock (&response->mutex);
-          if (MHD_YES != try_ready_normal_body (connection))
-            {
-              if (response->crc != NULL)
-                pthread_mutex_unlock (&response->mutex);
-              break;
-            }
-         ret = connection->send_cls (connection,
-                                     &response->data
-                                     [connection->response_write_position
-                                      - response->data_start],
-                                     response->data_size -
-                                     (connection->response_write_position
-                                      - response->data_start));
-#if DEBUG_SEND_DATA
-          if (ret > 0)
-            FPRINTF (stderr,
-                     "Sent DATA response: `%.*s'\n",
-                     ret,
-                     &response->data[connection->response_write_position -
-                                     response->data_start]);
-#endif
-          if (response->crc != NULL)
-            pthread_mutex_unlock (&response->mutex);
-          if (ret < 0)
-            {
-              if ((errno == EINTR) || (errno == EAGAIN))
-                return MHD_YES;
-#if HAVE_MESSAGES
-              MHD_DLOG (connection->daemon,
-                        "Failed to send data: %s\n", STRERROR (errno));
-#endif
-             CONNECTION_CLOSE_ERROR (connection, NULL);
-              return MHD_YES;
-            }
-          connection->response_write_position += ret;
-          if (connection->response_write_position ==
-              connection->response->total_size)
-            connection->state = MHD_CONNECTION_FOOTERS_SENT;    /* have no 
footers... */
-          break;
-        case MHD_CONNECTION_NORMAL_BODY_UNREADY:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_CHUNKED_BODY_READY:
-          do_write (connection);
-         if (connection->state !=  MHD_CONNECTION_CHUNKED_BODY_READY)
-            break;
-          check_write_done (connection,
-                            (connection->response->total_size ==
-                             connection->response_write_position) ?
-                            MHD_CONNECTION_BODY_SENT :
-                            MHD_CONNECTION_CHUNKED_BODY_UNREADY);
-          break;
-        case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
-        case MHD_CONNECTION_BODY_SENT:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_FOOTERS_SENDING:
-          do_write (connection);
-         if (connection->state != MHD_CONNECTION_FOOTERS_SENDING)
-           break;
-          check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
-          break;
-        case MHD_CONNECTION_FOOTERS_SENT:
-          EXTRA_CHECK (0);
-          break;
-        case MHD_CONNECTION_CLOSED:
-          return MHD_YES;
-        case MHD_TLS_CONNECTION_INIT:
-          EXTRA_CHECK (0);
-          break;
-        default:
-          EXTRA_CHECK (0);
-         CONNECTION_CLOSE_ERROR (connection, "Internal error\n");
-          return MHD_YES;
-        }
-      break;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * This function was created to handle per-connection processing that
- * has to happen even if the socket cannot be read or written to.  All
- * implementations (multithreaded, external select, internal select)
- * call this function.
- *
- * @param connection connection to handle
- * @return MHD_YES if we should continue to process the
- *         connection (not dead yet), MHD_NO if it died
- */
-int
-MHD_connection_handle_idle (struct MHD_Connection *connection)
-{
-  struct MHD_Daemon *daemon;
-  unsigned int timeout;
-  const char *end;
-  int rend;
-  char *line;
-
-  while (1)
-    {
-#if DEBUG_STATES
-      MHD_DLOG (connection->daemon, "%s: state: %s\n",
-                __FUNCTION__, MHD_state_to_string (connection->state));
-#endif
-      switch (connection->state)
-        {
-        case MHD_CONNECTION_INIT:
-          line = get_next_header_line (connection);
-          if (line == NULL)
-            {
-              if (connection->state != MHD_CONNECTION_INIT)
-                continue;
-              if (connection->read_closed)
-                {
-                 CONNECTION_CLOSE_ERROR (connection, 
-                                         NULL);
-                  continue;
-                }
-              break;
-            }
-          if (MHD_NO == parse_initial_message_line (connection, line))
-            CONNECTION_CLOSE_ERROR (connection, NULL);
-          else
-            connection->state = MHD_CONNECTION_URL_RECEIVED;
-          continue;
-        case MHD_CONNECTION_URL_RECEIVED:
-          line = get_next_header_line (connection);
-          if (line == NULL)
-            {
-              if (connection->state != MHD_CONNECTION_URL_RECEIVED)
-                continue;
-              if (connection->read_closed)
-                {
-                 CONNECTION_CLOSE_ERROR (connection, 
-                                         NULL);
-                  continue;
-                }
-              break;
-            }
-          if (strlen (line) == 0)
-            {
-              connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
-              continue;
-            }
-          if (MHD_NO == process_header_line (connection, line))
-            {
-              transmit_error_response (connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       REQUEST_MALFORMED);
-              break;
-            }
-          connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
-          continue;
-        case MHD_CONNECTION_HEADER_PART_RECEIVED:
-          line = get_next_header_line (connection);
-          if (line == NULL)
-            {
-              if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
-                continue;
-              if (connection->read_closed)
-                {
-                 CONNECTION_CLOSE_ERROR (connection, 
-                                         NULL);
-                  continue;
-                }
-              break;
-            }
-          if (MHD_NO ==
-              process_broken_line (connection, line, MHD_HEADER_KIND))
-            continue;
-          if (strlen (line) == 0)
-            {
-              connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
-              continue;
-            }
-          continue;
-        case MHD_CONNECTION_HEADERS_RECEIVED:
-          parse_connection_headers (connection);
-          if (connection->state == MHD_CONNECTION_CLOSED)
-            continue;
-          connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
-          continue;
-        case MHD_CONNECTION_HEADERS_PROCESSED:
-          call_connection_handler (connection); /* first call */
-          if (connection->state == MHD_CONNECTION_CLOSED)
-            continue;
-          if (need_100_continue (connection))
-            {
-              connection->state = MHD_CONNECTION_CONTINUE_SENDING;
-              break;
-            }
-          if (connection->response != NULL)
-            {
-              /* we refused (no upload allowed!) */
-              connection->remaining_upload_size = 0;
-              /* force close, in case client still tries to upload... */
-              connection->read_closed = MHD_YES;
-            }
-          connection->state = (connection->remaining_upload_size == 0)
-            ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
-          continue;
-        case MHD_CONNECTION_CONTINUE_SENDING:
-          if (connection->continue_message_write_offset ==
-              strlen (HTTP_100_CONTINUE))
-            {
-              connection->state = MHD_CONNECTION_CONTINUE_SENT;
-              continue;
-            }
-          break;
-        case MHD_CONNECTION_CONTINUE_SENT:
-          if (connection->read_buffer_offset != 0)
-            {
-              process_request_body (connection);     /* loop call */
-              if (connection->state == MHD_CONNECTION_CLOSED)
-                continue;
-            }
-          if ((connection->remaining_upload_size == 0) ||
-              ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
-               (connection->read_buffer_offset == 0) &&
-               (MHD_YES == connection->read_closed)))
-            {
-              if ((MHD_YES == connection->have_chunked_upload) &&
-                  (MHD_NO == connection->read_closed))
-                connection->state = MHD_CONNECTION_BODY_RECEIVED;
-              else
-                connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-              continue;
-            }
-          break;
-        case MHD_CONNECTION_BODY_RECEIVED:
-          line = get_next_header_line (connection);
-          if (line == NULL)
-            {
-              if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
-                continue;
-              if (connection->read_closed)
-                {
-                 CONNECTION_CLOSE_ERROR (connection, 
-                                         NULL);
-                  continue;
-                }
-              break;
-            }
-          if (strlen (line) == 0)
-            {
-              connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-              continue;
-            }
-          if (MHD_NO == process_header_line (connection, line))
-            {
-              transmit_error_response (connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       REQUEST_MALFORMED);
-              break;
-            }
-          connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
-          continue;
-        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-          line = get_next_header_line (connection);
-          if (line == NULL)
-            {
-              if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
-                continue;
-              if (connection->read_closed)
-                {
-                 CONNECTION_CLOSE_ERROR (connection, 
-                                         NULL);
-                  continue;
-                }
-              break;
-            }
-          if (MHD_NO ==
-              process_broken_line (connection, line, MHD_FOOTER_KIND))
-            continue;
-          if (strlen (line) == 0)
-            {
-              connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
-              continue;
-            }
-          continue;
-        case MHD_CONNECTION_FOOTERS_RECEIVED:
-          call_connection_handler (connection); /* "final" call */
-          if (connection->state == MHD_CONNECTION_CLOSED)
-            continue;
-          if (connection->response == NULL)
-            break;              /* try again next time */
-          if (MHD_NO == build_header_response (connection))
-            {
-              /* oops - close! */
-             CONNECTION_CLOSE_ERROR (connection, 
-                                     "Closing connection (failed to create 
response header)\n");
-              continue;
-            }
-          connection->state = MHD_CONNECTION_HEADERS_SENDING;
-
-#if HAVE_DECL_TCP_CORK
-          /* starting header send, set TCP cork */
-          {
-            const int val = 1;
-            setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
-                        sizeof (val));
-          }
-#endif
-          break;
-        case MHD_CONNECTION_HEADERS_SENDING:
-          /* no default action */
-          break;
-        case MHD_CONNECTION_HEADERS_SENT:
-          if (connection->have_chunked_upload)
-            connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
-          else
-            connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
-          continue;
-        case MHD_CONNECTION_NORMAL_BODY_READY:
-          /* nothing to do here */
-          break;
-        case MHD_CONNECTION_NORMAL_BODY_UNREADY:
-          if (connection->response->crc != NULL)
-            pthread_mutex_lock (&connection->response->mutex);
-          if (MHD_YES == try_ready_normal_body (connection))
-            {
-              if (connection->response->crc != NULL)
-                pthread_mutex_unlock (&connection->response->mutex);
-              connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
-              break;
-            }
-          if (connection->response->crc != NULL)
-            pthread_mutex_unlock (&connection->response->mutex);
-          /* not ready, no socket action */
-          break;
-        case MHD_CONNECTION_CHUNKED_BODY_READY:
-          /* nothing to do here */
-          break;
-        case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
-          if (connection->response->crc != NULL)
-            pthread_mutex_lock (&connection->response->mutex);
-          if (MHD_YES == try_ready_chunked_body (connection))
-            {
-              if (connection->response->crc != NULL)
-                pthread_mutex_unlock (&connection->response->mutex);
-              connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
-              continue;
-            }
-          if (connection->response->crc != NULL)
-            pthread_mutex_unlock (&connection->response->mutex);
-          break;
-        case MHD_CONNECTION_BODY_SENT:
-          build_header_response (connection);
-          if (connection->write_buffer_send_offset ==
-              connection->write_buffer_append_offset)
-            connection->state = MHD_CONNECTION_FOOTERS_SENT;
-          else
-            connection->state = MHD_CONNECTION_FOOTERS_SENDING;
-          continue;
-        case MHD_CONNECTION_FOOTERS_SENDING:
-          /* no default action */
-          break;
-        case MHD_CONNECTION_FOOTERS_SENT:
-#if HAVE_DECL_TCP_CORK
-          /* done sending, uncork */
-          {
-            const int val = 0;
-            setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
-                        sizeof (val));
-          }
-#endif
-          end =
-            MHD_get_response_header (connection->response, 
-                                    MHD_HTTP_HEADER_CONNECTION);
-         rend = ( (end != NULL) && (0 == strcasecmp (end, "close")) );
-          MHD_destroy_response (connection->response);
-          connection->response = NULL;
-          if (connection->daemon->notify_completed != NULL)
-           connection->daemon->notify_completed (connection->daemon->
-                                                 notify_completed_cls,
-                                                 connection,
-                                                 &connection->client_context,
-                                                 
MHD_REQUEST_TERMINATED_COMPLETED_OK);     
-         connection->client_aware = MHD_NO;
-          end =
-            MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
-                                         MHD_HTTP_HEADER_CONNECTION);
-          connection->client_context = NULL;
-          connection->continue_message_write_offset = 0;
-          connection->responseCode = 0;
-          connection->headers_received = NULL;
-         connection->headers_received_tail = NULL;
-          connection->response_write_position = 0;
-          connection->have_chunked_upload = MHD_NO;
-          connection->method = NULL;
-          connection->url = NULL;
-          connection->write_buffer = NULL;
-          connection->write_buffer_size = 0;
-          connection->write_buffer_send_offset = 0;
-          connection->write_buffer_append_offset = 0;
-          if ( (rend) || ((end != NULL) && (0 == strcasecmp (end, "close"))) )
-            {
-              connection->read_closed = MHD_YES;
-              connection->read_buffer_offset = 0;
-            }
-          if (((MHD_YES == connection->read_closed) &&
-               (0 == connection->read_buffer_offset)) ||
-              (connection->version == NULL) ||
-              (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
-            {
-              /* http 1.0, version-less requests cannot be pipelined */
-              MHD_connection_close (connection, 
MHD_REQUEST_TERMINATED_COMPLETED_OK);
-              MHD_pool_destroy (connection->pool);
-              connection->pool = NULL;
-              connection->read_buffer = NULL;
-              connection->read_buffer_size = 0;
-              connection->read_buffer_offset = 0;
-            }
-          else
-            {
-              connection->version = NULL;
-              connection->state = MHD_CONNECTION_INIT;
-              connection->read_buffer
-                = MHD_pool_reset (connection->pool,
-                                  connection->read_buffer,
-                                  connection->read_buffer_size);
-            }
-          continue;
-        case MHD_CONNECTION_CLOSED:
-         if (connection->response != NULL)
-           {
-             MHD_destroy_response (connection->response);
-             connection->response = NULL;
-           }
-         daemon = connection->daemon;
-         if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to acquire cleanup mutex\n");
-           }
-         DLL_remove (daemon->connections_head,
-                     daemon->connections_tail,
-                     connection);
-         DLL_insert (daemon->cleanup_head,
-                     daemon->cleanup_tail,
-                     connection);
-         if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to release cleanup mutex\n");
-           }
-         return MHD_NO;
-        default:
-          EXTRA_CHECK (0);
-          break;
-        }
-      break;
-    }
-  timeout = connection->connection_timeout;
-  if ( (timeout != 0) &&
-       (timeout <= (MHD_monotonic_time() - connection->last_activity)) )
-    {
-      MHD_connection_close (connection, 
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
-      return MHD_YES;
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Set callbacks for this connection to those for HTTP.
- *
- * @param connection connection to initialize
- */
-void
-MHD_set_http_callbacks_ (struct MHD_Connection *connection)
-{
-  connection->read_handler = &MHD_connection_handle_read;
-  connection->write_handler = &MHD_connection_handle_write;
-  connection->idle_handler = &MHD_connection_handle_idle;
-}
-
-
-/**
- * Obtain information about the given connection.
- *
- * @param connection what connection to get information about
- * @param infoType what information is desired?
- * @param ... depends on infoType
- * @return NULL if this information is not available
- *         (or if the infoType is unknown)
- */
-const union MHD_ConnectionInfo *
-MHD_get_connection_info (struct MHD_Connection *connection,
-                         enum MHD_ConnectionInfoType infoType, ...)
-{
-  switch (infoType)
-    {
-#if HTTPS_SUPPORT
-    case MHD_CONNECTION_INFO_CIPHER_ALGO:
-      if (connection->tls_session == NULL)
-       return NULL;
-      connection->cipher = gnutls_cipher_get (connection->tls_session);
-      return (const union MHD_ConnectionInfo *) &connection->cipher;
-    case MHD_CONNECTION_INFO_PROTOCOL:
-      if (connection->tls_session == NULL)
-       return NULL;
-      connection->protocol = gnutls_protocol_get_version 
(connection->tls_session);
-      return (const union MHD_ConnectionInfo *) &connection->protocol;
-    case MHD_CONNECTION_INFO_GNUTLS_SESSION:
-      if (connection->tls_session == NULL)
-       return NULL;
-      return (const union MHD_ConnectionInfo *) &connection->tls_session;
-#endif
-    case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
-      return (const union MHD_ConnectionInfo *) &connection->addr;
-    case MHD_CONNECTION_INFO_DAEMON:
-      return (const union MHD_ConnectionInfo *) &connection->daemon;
-    default:
-      return NULL;
-    };
-}
-
-
-/**
- * Set a custom option for the given connection, overriding defaults.
- *
- * @param connection connection to modify
- * @param option option to set
- * @param ... arguments to the option, depending on the option type
- * @return MHD_YES on success, MHD_NO if setting the option failed
- */
-int 
-MHD_set_connection_option (struct MHD_Connection *connection,
-                          enum MHD_CONNECTION_OPTION option,
-                          ...)
-{
-  va_list ap;
-
-  switch (option)
-    {
-    case MHD_CONNECTION_OPTION_TIMEOUT:
-      va_start (ap, option);
-      connection->connection_timeout = va_arg (ap, unsigned int);
-      va_end (ap);
-      return MHD_YES;
-    default:
-      return MHD_NO;
-    }
-}
-
-
-/* end of connection.c */

Copied: libmicrohttpd/src/microhttpd/connection.c (from rev 27024, 
libmicrohttpd/src/daemon/connection.c)
===================================================================
--- libmicrohttpd/src/microhttpd/connection.c                           (rev 0)
+++ libmicrohttpd/src/microhttpd/connection.c   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,2578 @@
+/*
+    This file is part of libmicrohttpd
+     (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian 
Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+
+*/
+
+/**
+ * @file connection.c
+ * @brief  Methods for managing connections
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ */
+
+#include "internal.h"
+#include <limits.h>
+#include "connection.h"
+#include "memorypool.h"
+#include "response.h"
+#include "reason_phrase.h"
+
+#if HAVE_NETINET_TCP_H
+/* for TCP_CORK */
+#include <netinet/tcp.h>
+#endif
+
+/**
+ * Minimum size by which MHD tries to increment read/write buffers.
+ * We usually begin with half the available pool space for the
+ * IO-buffer, but if absolutely needed we additively grow by the
+ * number of bytes given here (up to -- theoretically -- the full pool
+ * space).
+ */
+#define MHD_BUF_INC_SIZE 1024
+
+/**
+ * Message to transmit when http 1.1 request is received
+ */
+#define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
+
+/**
+ * Response text used when the request (http header) is too big to
+ * be processed.
+ *
+ * Intentionally empty here to keep our memory footprint
+ * minimal.
+ */
+#if HAVE_MESSAGES
+#define REQUEST_TOO_BIG "<html><head><title>Request too 
big</title></head><body>Your HTTP header was too big for the memory constraints 
of this webserver.</body></html>"
+#else
+#define REQUEST_TOO_BIG ""
+#endif
+
+/**
+ * Response text used when the request (http header) does not
+ * contain a "Host:" header and still claims to be HTTP 1.1.
+ *
+ * Intentionally empty here to keep our memory footprint
+ * minimal.
+ */
+#if HAVE_MESSAGES
+#define REQUEST_LACKS_HOST "<html><head><title>&quot;Host:&quot; header 
required</title></head><body>In HTTP 1.1, requests must include a 
&quot;Host:&quot; header, and your HTTP 1.1 request lacked such a 
header.</body></html>"
+#else
+#define REQUEST_LACKS_HOST ""
+#endif
+
+/**
+ * Response text used when the request (http header) is
+ * malformed.
+ *
+ * Intentionally empty here to keep our memory footprint
+ * minimal.
+ */
+#if HAVE_MESSAGES
+#define REQUEST_MALFORMED "<html><head><title>Request 
malformed</title></head><body>Your HTTP request was syntactically 
incorrect.</body></html>"
+#else
+#define REQUEST_MALFORMED ""
+#endif
+
+/**
+ * Response text used when there is an internal server error.
+ *
+ * Intentionally empty here to keep our memory footprint
+ * minimal.
+ */
+#if HAVE_MESSAGES
+#define INTERNAL_ERROR "<html><head><title>Internal server 
error</title></head><body>Some programmer needs to study the manual more 
carefully.</body></html>"
+#else
+#define INTERNAL_ERROR ""
+#endif
+
+/**
+ * Add extra debug messages with reasons for closing connections
+ * (non-error reasons).
+ */
+#define DEBUG_CLOSE MHD_NO
+
+/**
+ * Should all data send be printed to stderr?
+ */
+#define DEBUG_SEND_DATA MHD_NO
+
+
+/**
+ * Get all of the headers from the request.
+ *
+ * @param connection connection to get values from
+ * @param kind types of values to iterate over
+ * @param iterator callback to call on each header;
+ *        maybe NULL (then just count headers)
+ * @param iterator_cls extra argument to iterator
+ * @return number of entries iterated over
+ */
+int
+MHD_get_connection_values (struct MHD_Connection *connection,
+                           enum MHD_ValueKind kind,
+                           MHD_KeyValueIterator iterator, void *iterator_cls)
+{
+  int ret;
+  struct MHD_HTTP_Header *pos;
+
+  if (NULL == connection)
+    return -1;
+  ret = 0;
+  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
+    if (0 != (pos->kind & kind))
+      {
+       ret++;
+       if ((NULL != iterator) &&
+           (MHD_YES != iterator (iterator_cls,
+                                 kind, pos->header, pos->value)))
+         return ret;
+      }
+  return ret;
+}
+
+
+/**
+ * This function can be used to append an entry to
+ * the list of HTTP headers of a connection (so that the
+ * MHD_get_connection_values function will return
+ * them -- and the MHD PostProcessor will also
+ * see them).  This maybe required in certain
+ * situations (see Mantis #1399) where (broken)
+ * HTTP implementations fail to supply values needed
+ * by the post processor (or other parts of the
+ * application).
+ * <p>
+ * This function MUST only be called from within
+ * the MHD_AccessHandlerCallback (otherwise, access
+ * maybe improperly synchronized).  Furthermore,
+ * the client must guarantee that the key and
+ * value arguments are 0-terminated strings that
+ * are NOT freed until the connection is closed.
+ * (The easiest way to do this is by passing only
+ * arguments to permanently allocated strings.).
+ *
+ * @param connection the connection for which a
+ *  value should be set
+ * @param kind kind of the value
+ * @param key key for the value
+ * @param value the value itself
+ * @return MHD_NO if the operation could not be
+ *         performed due to insufficient memory;
+ *         MHD_YES on success
+ */
+int
+MHD_set_connection_value (struct MHD_Connection *connection,
+                          enum MHD_ValueKind kind,
+                          const char *key, const char *value)
+{
+  struct MHD_HTTP_Header *pos;
+
+  pos = MHD_pool_allocate (connection->pool,
+                           sizeof (struct MHD_HTTP_Header), MHD_NO);
+  if (NULL == pos)
+    return MHD_NO;
+  pos->header = (char *) key;
+  pos->value = (char *) value;
+  pos->kind = kind;
+  pos->next = NULL;
+  /* append 'pos' to the linked list of headers */
+  if (NULL == connection->headers_received_tail)
+  {
+    connection->headers_received = pos;
+    connection->headers_received_tail = pos;
+  }
+  else
+  {
+    connection->headers_received_tail->next = pos;
+    connection->headers_received_tail = pos;
+  }
+  return MHD_YES;
+}
+
+
+/**
+ * Get a particular header value.  If multiple
+ * values match the kind, return any one of them.
+ *
+ * @param connection connection to get values from
+ * @param kind what kind of value are we looking for
+ * @param key the header to look for, NULL to lookup 'trailing' value without 
a key
+ * @return NULL if no such item was found
+ */
+const char *
+MHD_lookup_connection_value (struct MHD_Connection *connection,
+                             enum MHD_ValueKind kind, const char *key)
+{
+  struct MHD_HTTP_Header *pos;
+
+  if (NULL == connection)
+    return NULL;
+  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
+    if ((0 != (pos->kind & kind)) && 
+       ( (key == pos->header) ||
+         ( (NULL != pos->header) &&
+           (NULL != key) &&
+           (0 == strcasecmp (key, pos->header))) ))
+      return pos->value;    
+  return NULL;
+}
+
+
+/**
+ * Queue a response to be transmitted to the client (as soon as
+ * possible but after MHD_AccessHandlerCallback returns).
+ *
+ * @param connection the connection identifying the client
+ * @param status_code HTTP status code (i.e. 200 for OK)
+ * @param response response to transmit
+ * @return MHD_NO on error (i.e. reply already sent),
+ *         MHD_YES on success or if message has been queued
+ */
+int
+MHD_queue_response (struct MHD_Connection *connection,
+                    unsigned int status_code, struct MHD_Response *response)
+{
+  if ( (NULL == connection) ||
+       (NULL == response) ||
+       (NULL != connection->response) ||
+       ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
+        (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
+    return MHD_NO;
+  MHD_increment_response_rc (response);
+  connection->response = response;
+  connection->responseCode = status_code;
+  if ( (NULL != connection->method) &&
+       (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)) )
+    {
+      /* if this is a "HEAD" request, pretend that we
+         have already sent the full message body */
+      connection->response_write_position = response->total_size;
+    }
+  if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
+    {
+      /* response was queued "early",
+         refuse to read body / footers or further
+         requests! */
+      (void) SHUTDOWN (connection->socket_fd, SHUT_RD);
+      connection->read_closed = MHD_YES;
+      connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Do we (still) need to send a 100 continue
+ * message for this connection?
+ *
+ * @param connection connection to test
+ * @return 0 if we don't need 100 CONTINUE, 1 if we do
+ */
+static int
+need_100_continue (struct MHD_Connection *connection)
+{
+  const char *expect;
+
+  return ( (NULL == connection->response) &&
+          (NULL != connection->version) &&
+          (0 == strcasecmp (connection->version,
+                            MHD_HTTP_VERSION_1_1)) &&
+          (NULL != (expect = MHD_lookup_connection_value (connection,
+                                                          MHD_HEADER_KIND,
+                                                          
MHD_HTTP_HEADER_EXPECT))) &&
+          (0 == strcasecmp (expect, "100-continue")) &&
+          (connection->continue_message_write_offset <
+           strlen (HTTP_100_CONTINUE)) );
+}
+
+
+/**
+ * Close the given connection and give the
+ * specified termination code to the user.
+ *
+ * @param connection connection to close
+ * @param termination_code termination reason to give
+ */
+void
+MHD_connection_close (struct MHD_Connection *connection,
+                      enum MHD_RequestTerminationCode termination_code)
+{
+  struct MHD_Daemon *daemon;
+
+  daemon = connection->daemon;
+  SHUTDOWN (connection->socket_fd, 
+           (connection->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);
+  connection->state = MHD_CONNECTION_CLOSED;
+  if ( (NULL != daemon->notify_completed) &&
+       (MHD_YES == connection->client_aware) )
+    daemon->notify_completed (daemon->notify_completed_cls, 
+                             connection,
+                             &connection->client_context,
+                             termination_code);
+  connection->client_aware = MHD_NO;
+}
+
+
+/**
+ * A serious error occured, close the
+ * connection (and notify the application).
+ *
+ * @param connection connection to close with error
+ * @param emsg error message (can be NULL)
+ */
+static void
+connection_close_error (struct MHD_Connection *connection,
+                       const char *emsg)
+{
+#if HAVE_MESSAGES
+  if (NULL != emsg)
+    MHD_DLOG (connection->daemon, emsg);
+#endif
+  MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
+}
+
+
+/**
+ * Macro to only include error message in call to
+ * "connection_close_error" if we have HAVE_MESSAGES.
+ */
+#if HAVE_MESSAGES
+#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
+#else
+#define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
+#endif
+
+
+/**
+ * Prepare the response buffer of this connection for
+ * sending.  Assumes that the response mutex is
+ * already held.  If the transmission is complete,
+ * this function may close the socket (and return
+ * MHD_NO).
+ *
+ * @param connection the connection
+ * @return MHD_NO if readying the response failed
+ */
+static int
+try_ready_normal_body (struct MHD_Connection *connection)
+{
+  ssize_t ret;
+  struct MHD_Response *response;
+
+  response = connection->response;
+  if (NULL == response->crc)
+    return MHD_YES;
+  if (0 == response->total_size)
+    return MHD_YES; /* 0-byte response is always ready */
+  if ( (response->data_start <=
+       connection->response_write_position) &&
+       (response->data_size + response->data_start >
+       connection->response_write_position) )
+    return MHD_YES; /* response already ready */
+#if LINUX
+  if ( (-1 != response->fd) &&
+       (0 == (connection->daemon->options & MHD_USE_SSL)) )
+    {
+      /* will use sendfile, no need to bother response crc */
+      return MHD_YES; 
+    }
+#endif
+  
+  ret = response->crc (response->crc_cls,
+                       connection->response_write_position,
+                       response->data,
+                       MHD_MIN (response->data_buffer_size,
+                                response->total_size -
+                                connection->response_write_position));
+  if ((0 == ret) &&
+      (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
+    mhd_panic (mhd_panic_cls, __FILE__, __LINE__
+#if HAVE_MESSAGES
+              , "API violation"
+#else
+              , NULL
+#endif
+              );
+  if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
+       (MHD_CONTENT_READER_END_WITH_ERROR == ret) )
+    {
+      /* either error or http 1.0 transfer, close socket! */
+      response->total_size = connection->response_write_position;
+      CONNECTION_CLOSE_ERROR (connection,
+                             (ret == MHD_CONTENT_READER_END_OF_STREAM) 
+                             ? "Closing connection (end of response)\n"
+                             : "Closing connection (stream error)\n");
+      return MHD_NO;
+    }
+  response->data_start = connection->response_write_position;
+  response->data_size = ret;
+  if (0 == ret)
+    {
+      connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
+      return MHD_NO;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Prepare the response buffer of this connection for sending.
+ * Assumes that the response mutex is already held.  If the
+ * transmission is complete, this function may close the socket (and
+ * return MHD_NO).
+ *
+ * @param connection the connection
+ * @return MHD_NO if readying the response failed
+ */
+static int
+try_ready_chunked_body (struct MHD_Connection *connection)
+{
+  ssize_t ret;
+  char *buf;
+  struct MHD_Response *response;
+  size_t size;
+  char cbuf[10];                /* 10: max strlen of "%x\r\n" */
+  int cblen;
+
+  response = connection->response;
+  if (0 == connection->write_buffer_size)
+    {
+      size = connection->daemon->pool_size;
+      do
+        {
+          size /= 2;
+          if (size < 128)
+            {
+              /* not enough memory */
+              CONNECTION_CLOSE_ERROR (connection,
+                                     "Closing connection (out of memory)\n");
+              return MHD_NO;
+            }
+          buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
+        }
+      while (NULL == buf);
+      connection->write_buffer_size = size;
+      connection->write_buffer = buf;
+    }
+
+  if ( (response->data_start <=
+       connection->response_write_position) &&
+       (response->data_size + response->data_start >
+       connection->response_write_position) )
+    {
+      /* buffer already ready, use what is there for the chunk */
+      ret = response->data_size + response->data_start - 
connection->response_write_position;
+      if (ret > connection->write_buffer_size - sizeof (cbuf) - 2)
+       ret = connection->write_buffer_size - sizeof (cbuf) - 2;
+      memcpy (&connection->write_buffer[sizeof (cbuf)],
+             &response->data[connection->response_write_position - 
response->data_start],
+             ret);
+    }
+  else
+    {
+      /* buffer not in range, try to fill it */
+      if (0 == response->total_size)
+       ret = 0; /* response must be empty, don't bother calling crc */
+      else
+       ret = response->crc (response->crc_cls,
+                            connection->response_write_position,
+                            &connection->write_buffer[sizeof (cbuf)],
+                            connection->write_buffer_size - sizeof (cbuf) - 2);
+    }
+  if (MHD_CONTENT_READER_END_WITH_ERROR == ret)
+    {
+      /* error, close socket! */
+      response->total_size = connection->response_write_position;
+      CONNECTION_CLOSE_ERROR (connection,
+                             "Closing connection (error generating 
response)\n");
+      return MHD_NO;
+    }
+  if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
+       (0 == response->total_size) )
+    {
+      /* end of message, signal other side! */
+      strcpy (connection->write_buffer, "0\r\n");
+      connection->write_buffer_append_offset = 3;
+      connection->write_buffer_send_offset = 0;
+      response->total_size = connection->response_write_position;
+      return MHD_YES;
+    }
+  if (0 == ret) 
+    {
+      connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
+      return MHD_NO;
+    }
+  if (ret > 0xFFFFFF)
+    ret = 0xFFFFFF;
+  snprintf (cbuf, 
+           sizeof (cbuf),
+           "%X\r\n", (unsigned int) ret);
+  cblen = strlen (cbuf);
+  EXTRA_CHECK (cblen <= sizeof (cbuf));
+  memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
+  memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
+  connection->response_write_position += ret;
+  connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
+  connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
+  return MHD_YES;
+}
+
+
+/**
+ * Check if we need to set some additional headers
+ * for http-compiliance.
+ *
+ * @param connection connection to check (and possibly modify)
+ */
+static void
+add_extra_headers (struct MHD_Connection *connection)
+{
+  const char *have_close;
+  const char *client_close;
+  const char *have_encoding;
+  char buf[128];
+  int add_close;
+
+  client_close = MHD_lookup_connection_value (connection,
+                                             MHD_HEADER_KIND,
+                                             MHD_HTTP_HEADER_CONNECTION);
+  /* we only care about 'close', everything else is ignored */
+  if ( (NULL != client_close) && (0 != strcasecmp (client_close, "close")) )
+    client_close = NULL;
+  have_close = MHD_get_response_header (connection->response,
+                                       MHD_HTTP_HEADER_CONNECTION);
+  if ( (NULL != have_close) && (0 != strcasecmp (have_close, "close")) )
+    have_close = NULL;
+  connection->have_chunked_upload = MHD_NO;
+  add_close = MHD_NO;
+  if (MHD_SIZE_UNKNOWN == connection->response->total_size)
+    {
+      /* size is unknown, need to either to HTTP 1.1 chunked encoding or
+        close the connection */
+      if (NULL == have_close)
+        {
+         /* 'close' header doesn't exist yet, see if we need to add one;
+            if the client asked for a close, no need to start chunk'ing */
+          if ((NULL == client_close) &&
+             (NULL != connection->version) &&
+              (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) 
+            {
+              connection->have_chunked_upload = MHD_YES;
+              have_encoding = MHD_get_response_header (connection->response,
+                                                      
MHD_HTTP_HEADER_TRANSFER_ENCODING);
+              if (NULL == have_encoding)
+                MHD_add_response_header (connection->response,
+                                         MHD_HTTP_HEADER_TRANSFER_ENCODING,
+                                         "chunked");
+             else if (0 != strcasecmp (have_encoding, "chunked"))
+               add_close = MHD_YES; /* application already set some strange 
encoding, can't do 'chunked' */
+            }
+          else
+            {
+             /* HTTP not 1.1 or client asked for close => set close header */
+             add_close = MHD_YES;
+            }
+        }
+    }
+  else
+    {
+      /* check if we should add a 'close' anyway */
+      if ( (NULL != client_close) &&
+          (NULL == have_close) )
+       add_close = MHD_YES; /* client asked for it, so add it */
+
+      /* if not present, add content length */
+      if (NULL == MHD_get_response_header (connection->response,
+                                          MHD_HTTP_HEADER_CONTENT_LENGTH))
+       {
+         SPRINTF (buf,
+                  MHD_UNSIGNED_LONG_LONG_PRINTF,
+                  (MHD_UNSIGNED_LONG_LONG) connection->response->total_size);
+         MHD_add_response_header (connection->response,
+                                  MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
+       }
+    }
+  if (MHD_YES == add_close)
+    MHD_add_response_header (connection->response,
+                            MHD_HTTP_HEADER_CONNECTION, "close");
+}
+
+
+/**
+ * Produce HTTP "Date:" header.
+ *
+ * @param date where to write the header, with
+ *        at least 128 bytes available space.
+ */
+static void
+get_date_string (char *date)
+{
+  static const char *const days[] =
+    { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+  static const char *const mons[] =
+    { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
+    "Nov", "Dec"
+  };
+  struct tm now;
+  time_t t;
+
+  time (&t);
+  gmtime_r (&t, &now);
+  SPRINTF (date,
+           "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
+           days[now.tm_wday % 7],
+           (unsigned int) now.tm_mday,
+           mons[now.tm_mon % 12],
+           (unsigned int) (1900 + now.tm_year),
+          (unsigned int) now.tm_hour, 
+          (unsigned int) now.tm_min, 
+          (unsigned int) now.tm_sec);
+}
+
+
+/**
+ * Try growing the read buffer.  We initially claim half the
+ * available buffer space for the read buffer (the other half
+ * being left for management data structures; the write
+ * buffer can in the end take virtually everything as the 
+ * read buffer can be reduced to the minimum necessary at that
+ * point.
+ *
+ * @param connection the connection
+ * @return MHD_YES on success, MHD_NO on failure
+ */
+static int
+try_grow_read_buffer (struct MHD_Connection *connection)
+{
+  void *buf;
+  size_t new_size;
+
+  if (0 == connection->read_buffer_size)
+    new_size = connection->daemon->pool_size / 2;
+  else
+    new_size = connection->read_buffer_size + MHD_BUF_INC_SIZE;
+  buf = MHD_pool_reallocate (connection->pool,
+                             connection->read_buffer,
+                             connection->read_buffer_size,
+                             new_size);
+  if (NULL == buf)
+    return MHD_NO;
+  /* we can actually grow the buffer, do it! */
+  connection->read_buffer = buf;
+  connection->read_buffer_size = new_size;
+  return MHD_YES;
+}
+
+
+/**
+ * Allocate the connection's write buffer and fill it with all of the
+ * headers (or footers, if we have already sent the body) from the
+ * HTTPd's response.
+ *
+ * @param connection the connection
+ */
+static int
+build_header_response (struct MHD_Connection *connection)
+{
+  size_t size;
+  size_t off;
+  struct MHD_HTTP_Header *pos;
+  char code[256];
+  char date[128];
+  char *data;
+  enum MHD_ValueKind kind;
+  const char *reason_phrase;
+  uint32_t rc;
+  int must_add_close;
+
+  EXTRA_CHECK (NULL != connection->version);
+  if (0 == strlen(connection->version))
+    {
+      data = MHD_pool_allocate (connection->pool, 0, MHD_YES);
+      connection->write_buffer = data;
+      connection->write_buffer_append_offset = 0;
+      connection->write_buffer_send_offset = 0;
+      connection->write_buffer_size = 0;
+      return MHD_YES;
+    }
+  if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
+    {
+      add_extra_headers (connection);
+      rc = connection->responseCode & (~MHD_ICY_FLAG);
+      reason_phrase = MHD_get_reason_phrase_for (rc);
+      SPRINTF (code,
+               "%s %u %s\r\n",
+              (0 != (connection->responseCode & MHD_ICY_FLAG))
+              ? "ICY" 
+              : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0,
+                                    connection->version)) 
+                  ? MHD_HTTP_VERSION_1_0 
+                  : MHD_HTTP_VERSION_1_1),
+              rc, 
+              reason_phrase);
+      off = strlen (code);
+      /* estimate size */
+      size = off + 2;           /* extra \r\n at the end */
+      kind = MHD_HEADER_KIND;
+      if ( (0 == (connection->daemon->options & MHD_SUPPRESS_DATE_NO_CLOCK)) 
&& 
+          (NULL == MHD_get_response_header (connection->response,
+                                            MHD_HTTP_HEADER_DATE)) )
+        get_date_string (date);
+      else
+        date[0] = '\0';
+      size += strlen (date);
+    }
+  else
+    {
+      size = 2;
+      kind = MHD_FOOTER_KIND;
+      off = 0;
+    }
+  must_add_close = ( (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) &&
+                    (connection->read_closed == MHD_YES) &&
+                    (0 == strcasecmp (connection->version,
+                                      MHD_HTTP_VERSION_1_1)) &&
+                    (NULL == MHD_get_response_header (connection->response,
+                                                      
MHD_HTTP_HEADER_CONNECTION)) );
+  if (must_add_close)
+    size += strlen ("Connection: close\r\n");
+  for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
+    if (pos->kind == kind)
+      size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, 
linefeeds */
+  /* produce data */
+  data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
+  if (NULL == data)
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
+#endif
+      return MHD_NO;
+    }
+  if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
+    {
+      memcpy (data, code, off);
+    }
+  if (must_add_close)
+    {
+      /* we must add the 'close' header because circumstances forced us to
+        stop reading from the socket; however, we are not adding the header
+        to the response as the response may be used in a different context
+        as well */
+      memcpy (&data[off], "Connection: close\r\n",
+             strlen ("Connection: close\r\n"));
+      off += strlen ("Connection: close\r\n");
+    }
+  for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
+    if (pos->kind == kind)
+      off += SPRINTF (&data[off], 
+                     "%s: %s\r\n",
+                     pos->header, 
+                     pos->value);
+  if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
+    {
+      strcpy (&data[off], date);
+      off += strlen (date);
+    }
+  memcpy (&data[off], "\r\n", 2);
+  off += 2;
+
+  if (off != size)
+    mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
+  connection->write_buffer = data;
+  connection->write_buffer_append_offset = size;
+  connection->write_buffer_send_offset = 0;
+  connection->write_buffer_size = size + 1;
+  return MHD_YES;
+}
+
+
+/**
+ * We encountered an error processing the request.
+ * Handle it properly by stopping to read data
+ * and sending the indicated response code and message.
+ *
+ * @param connection the connection
+ * @param status_code the response code to send (400, 413 or 414)
+ * @param message the error message to send
+ */
+static void
+transmit_error_response (struct MHD_Connection *connection,
+                         unsigned int status_code, 
+                        const char *message)
+{
+  struct MHD_Response *response;
+
+  if (NULL == connection->version)
+    {
+      /* we were unable to process the full header line, so we don't
+        really know what version the client speaks; assume 1.0 */
+      connection->version = MHD_HTTP_VERSION_1_0;
+    }
+  connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+  connection->read_closed = MHD_YES;
+#if HAVE_MESSAGES
+  MHD_DLOG (connection->daemon,
+            "Error %u (`%s') processing request, closing connection.\n",
+            status_code, message);
+#endif
+  EXTRA_CHECK (connection->response == NULL);
+  response = MHD_create_response_from_buffer (strlen (message),
+                                             (void *) message, 
+                                             MHD_RESPMEM_PERSISTENT);
+  MHD_queue_response (connection, status_code, response);
+  EXTRA_CHECK (connection->response != NULL);
+  MHD_destroy_response (response);
+  if (MHD_NO == build_header_response (connection))
+    {
+      /* oops - close! */
+      CONNECTION_CLOSE_ERROR (connection,
+                             "Closing connection (failed to create response 
header)\n");
+    }
+  else
+    {
+      connection->state = MHD_CONNECTION_HEADERS_SENDING;
+    }
+}
+
+
+/**
+ * Add "fd" to the "fd_set".  If "fd" is
+ * greater than "*max", set "*max" to fd.
+ *
+ * @param fd file descriptor to add to the set
+ * @param set set to modify
+ * @param max_fd maximum value to potentially update
+ */
+static void
+add_to_fd_set (int fd, 
+              fd_set *set, 
+              int *max_fd)
+{
+  FD_SET (fd, set);
+  if ( (NULL != max_fd) &&
+       (fd > *max_fd) )
+    *max_fd = fd;
+}
+
+
+/**
+ * Obtain the select sets for this connection.  The given
+ * sets (and the maximum) are updated and must have 
+ * already been initialized.
+ *
+ * @param connection connetion to get select sets for
+ * @param read_fd_set read set to initialize
+ * @param write_fd_set write set to initialize
+ * @param except_fd_set except set to initialize (never changed)
+ * @param max_fd where to store largest FD put into any set
+ * @return MHD_YES on success
+ */
+int
+MHD_connection_get_fdset (struct MHD_Connection *connection,
+                          fd_set *read_fd_set,
+                          fd_set *write_fd_set,
+                          fd_set *except_fd_set, 
+                         int *max_fd)
+{
+  int ret;
+  struct MHD_Pollfd p;
+
+  /* we use the 'poll fd' as a convenient way to re-use code 
+     when determining the select sets */
+  memset (&p, 0, sizeof(struct MHD_Pollfd));
+  ret = MHD_connection_get_pollfd (connection, &p);
+  if ( (MHD_YES == ret) && (p.fd >= 0) ) {
+    if (0 != (p.events & MHD_POLL_ACTION_IN)) 
+      add_to_fd_set(p.fd, read_fd_set, max_fd);    
+    if (0 != (p.events & MHD_POLL_ACTION_OUT)) 
+      add_to_fd_set(p.fd, write_fd_set, max_fd);    
+  }
+  return ret;
+}
+
+
+/**
+ * Obtain the pollfd for this connection
+ *
+ * @param connection connetion to get poll set for 
+ * @param p where to store the polling information
+ * @return MHD_YES on success. If return MHD_YES and p->fd < 0, this 
+ *                 connection is not waiting for any read or write events
+ */
+int
+MHD_connection_get_pollfd (struct MHD_Connection *connection, 
+                          struct MHD_Pollfd *p)
+{
+  int fd;
+
+  if (NULL == connection->pool)
+    connection->pool = MHD_pool_create (connection->daemon->pool_size);
+  if (NULL == connection->pool)
+    {
+      CONNECTION_CLOSE_ERROR (connection,
+                             "Failed to create memory pool!\n");
+      return MHD_YES;
+    }
+  fd = connection->socket_fd;
+  p->fd = fd;
+  if (-1 == fd)
+    return MHD_YES;
+  while (1)
+    {
+#if DEBUG_STATES
+      MHD_DLOG (connection->daemon, "%s: state: %s\n",
+                __FUNCTION__, MHD_state_to_string (connection->state));
+#endif
+      switch (connection->state)
+        {
+#if HTTPS_SUPPORT     
+       case MHD_TLS_CONNECTION_INIT:
+         if (0 == gnutls_record_get_direction (connection->tls_session))
+            p->events |= MHD_POLL_ACTION_IN;
+         else
+           p->events |= MHD_POLL_ACTION_OUT;
+         break;
+#endif
+        case MHD_CONNECTION_INIT:
+        case MHD_CONNECTION_URL_RECEIVED:
+        case MHD_CONNECTION_HEADER_PART_RECEIVED:
+          /* while reading headers, we always grow the
+             read buffer if needed, no size-check required */
+          if ((connection->read_closed) &&
+              (0 == connection->read_buffer_offset))
+            {
+             CONNECTION_CLOSE_ERROR (connection, 
+                                     "Connection buffer to small for 
request\n");
+              continue;
+            }
+          if ((connection->read_buffer_offset == connection->read_buffer_size)
+              && (MHD_NO == try_grow_read_buffer (connection)))
+            {
+              transmit_error_response (connection,
+                                       (connection->url != NULL)
+                                       ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
+                                       : MHD_HTTP_REQUEST_URI_TOO_LONG,
+                                       REQUEST_TOO_BIG);
+              continue;
+            }
+          if (MHD_NO == connection->read_closed)
+            p->events |= MHD_POLL_ACTION_IN;
+          break;
+        case MHD_CONNECTION_HEADERS_RECEIVED:
+          /* we should never get here */
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_HEADERS_PROCESSED:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_CONTINUE_SENDING:
+          p->events |= MHD_POLL_ACTION_OUT;
+          break;
+        case MHD_CONNECTION_CONTINUE_SENT:
+          if (connection->read_buffer_offset == connection->read_buffer_size)
+            {
+              if ((MHD_YES != try_grow_read_buffer (connection)) &&
+                  (0 != (connection->daemon->options &
+                         (MHD_USE_SELECT_INTERNALLY |
+                          MHD_USE_THREAD_PER_CONNECTION))))
+                {
+                  /* failed to grow the read buffer, and the
+                     client which is supposed to handle the
+                     received data in a *blocking* fashion
+                     (in this mode) did not handle the data as
+                     it was supposed to!
+                     => we would either have to do busy-waiting
+                     (on the client, which would likely fail),
+                     or if we do nothing, we would just timeout
+                     on the connection (if a timeout is even
+                     set!).
+                     Solution: we kill the connection with an error */
+                  transmit_error_response (connection,
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           INTERNAL_ERROR);
+                  continue;
+                }
+            }
+          if ((connection->read_buffer_offset < connection->read_buffer_size)
+              && (MHD_NO == connection->read_closed))
+            p->events |= MHD_POLL_ACTION_IN;
+          break;
+        case MHD_CONNECTION_BODY_RECEIVED:
+        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+          /* while reading footers, we always grow the
+             read buffer if needed, no size-check required */
+          if (MHD_YES == connection->read_closed)
+            {
+             CONNECTION_CLOSE_ERROR (connection, 
+                                     NULL);
+              continue;
+            }
+          p->events |= MHD_POLL_ACTION_IN;
+          /* transition to FOOTERS_RECEIVED
+             happens in read handler */
+          break;
+        case MHD_CONNECTION_FOOTERS_RECEIVED:
+          /* no socket action, wait for client
+             to provide response */
+          break;
+        case MHD_CONNECTION_HEADERS_SENDING:
+          /* headers in buffer, keep writing */
+          p->events |= MHD_POLL_ACTION_OUT;
+          break;
+        case MHD_CONNECTION_HEADERS_SENT:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_NORMAL_BODY_READY:
+          p->events |= MHD_POLL_ACTION_OUT;
+          break;
+        case MHD_CONNECTION_NORMAL_BODY_UNREADY:
+          /* not ready, no socket action */
+          break;
+        case MHD_CONNECTION_CHUNKED_BODY_READY:
+          p->events |= MHD_POLL_ACTION_OUT;
+          break;
+        case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
+          /* not ready, no socket action */
+          break;
+        case MHD_CONNECTION_BODY_SENT:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_FOOTERS_SENDING:
+          p->events |= MHD_POLL_ACTION_OUT;
+          break;
+        case MHD_CONNECTION_FOOTERS_SENT:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_CLOSED:
+          return MHD_YES;       /* do nothing, not even reading */
+        default:
+          EXTRA_CHECK (0);
+        }
+      break;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Parse a single line of the HTTP header.  Advance
+ * read_buffer (!) appropriately.  If the current line does not
+ * fit, consider growing the buffer.  If the line is
+ * far too long, close the connection.  If no line is
+ * found (incomplete, buffer too small, line too long),
+ * return NULL.  Otherwise return a pointer to the line.
+ */
+static char *
+get_next_header_line (struct MHD_Connection *connection)
+{
+  char *rbuf;
+  size_t pos;
+
+  if (0 == connection->read_buffer_offset)
+    return NULL;
+  pos = 0;
+  rbuf = connection->read_buffer;
+  while ((pos < connection->read_buffer_offset - 1) &&
+         ('\r' != rbuf[pos]) && ('\n' != rbuf[pos]))
+    pos++;
+  if (pos == connection->read_buffer_offset - 1)
+    {
+      /* not found, consider growing... */
+      if ( (connection->read_buffer_offset == connection->read_buffer_size) &&
+          (MHD_NO == 
+           try_grow_read_buffer (connection)) )
+       {
+         transmit_error_response (connection,
+                                  (NULL != connection->url)
+                                  ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
+                                  : MHD_HTTP_REQUEST_URI_TOO_LONG,
+                                  REQUEST_TOO_BIG);
+       }        
+      return NULL;
+    }
+  /* found, check if we have proper LFCR */
+  if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1]))
+    rbuf[pos++] = '\0';         /* skip both r and n */
+  rbuf[pos++] = '\0';
+  connection->read_buffer += pos;
+  connection->read_buffer_size -= pos;
+  connection->read_buffer_offset -= pos;
+  return rbuf;
+}
+
+
+/**
+ * Add an entry to the HTTP headers of a connection.  If this fails,
+ * transmit an error response (request too big).
+ *
+ * @param connection the connection for which a
+ *  value should be set
+ * @param kind kind of the value
+ * @param key key for the value
+ * @param value the value itself
+ * @return MHD_NO on failure (out of memory), MHD_YES for success
+ */
+static int
+connection_add_header (struct MHD_Connection *connection,
+                       char *key, char *value, enum MHD_ValueKind kind)
+{
+  if (MHD_NO == MHD_set_connection_value (connection,
+                                         kind,
+                                         key, value))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon,
+                "Not enough memory to allocate header record!\n");
+#endif
+      transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
+                               REQUEST_TOO_BIG);
+      return MHD_NO;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Parse and unescape the arguments given by the client as part
+ * of the HTTP request URI.
+ *
+ * @param kind header kind to use for adding to the connection
+ * @param connection connection to add headers to
+ * @param args argument URI string (after "?" in URI)
+ * @return MHD_NO on failure (out of memory), MHD_YES for success
+ */
+static int
+parse_arguments (enum MHD_ValueKind kind,
+                 struct MHD_Connection *connection, 
+                char *args)
+{
+  char *equals;
+  char *amper;
+
+  while (NULL != args)
+    {
+      equals = strchr (args, '=');
+      amper = strchr (args, '&');
+      if (NULL == amper)
+       {
+         /* last argument */
+         if (NULL == equals)
+           {
+             /* got 'foo', add key 'foo' with NULL for value */
+             connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                                    connection,
+                                                    args);
+             return connection_add_header (connection,
+                                           args,
+                                           NULL,
+                                           kind);            
+           }
+         /* got 'foo=bar' */
+         equals[0] = '\0';
+         equals++;
+         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                                connection,
+                                                args);
+         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                                connection,
+                                                equals);
+         return connection_add_header (connection, args, equals, kind);
+       }
+      /* amper is non-NULL here */
+      amper[0] = '\0';
+      amper++;
+      if ( (NULL == equals) ||
+          (equals >= amper) )
+       {
+         /* got 'foo&bar' or 'foo&bar=val', add key 'foo' with NULL for value 
*/
+         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                                connection,
+                                                args);
+         if (MHD_NO ==
+             connection_add_header (connection,
+                                    args,
+                                    NULL,
+                                    kind))
+           return MHD_NO;
+         /* continue with 'bar' */
+         args = amper;
+         continue;
+
+       }
+      /* equals and amper are non-NULL here, and equals < amper,
+        so we got regular 'foo=value&bar...'-kind of argument */
+      equals[0] = '\0';
+      equals++;
+      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                            connection,
+                                            args);
+      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                            connection,
+                                            equals);
+      if (MHD_NO == connection_add_header (connection, args, equals, kind))
+        return MHD_NO;
+      args = amper;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Parse the cookie header (see RFC 2109).
+ *
+ * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory)
+ */
+static int
+parse_cookie_header (struct MHD_Connection *connection)
+{
+  const char *hdr;
+  char *cpy;
+  char *pos;
+  char *sce;
+  char *semicolon;
+  char *equals;
+  char *ekill;
+  char old;
+  int quotes;
+
+  hdr = MHD_lookup_connection_value (connection,
+                                    MHD_HEADER_KIND,
+                                    MHD_HTTP_HEADER_COOKIE);
+  if (hdr == NULL)
+    return MHD_YES;
+  cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
+  if (cpy == NULL)
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
+#endif
+      transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
+                               REQUEST_TOO_BIG);
+      return MHD_NO;
+    }
+  memcpy (cpy, hdr, strlen (hdr) + 1);
+  pos = cpy;
+  while (pos != NULL)
+    {
+      while (*pos == ' ')
+        pos++;                  /* skip spaces */
+
+      sce = pos;
+      while (((*sce) != '\0') &&
+             ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
+        sce++;
+      /* remove tailing whitespace (if any) from key */
+      ekill = sce - 1;
+      while ((*ekill == ' ') && (ekill >= pos))
+        *(ekill--) = '\0';
+      old = *sce;
+      *sce = '\0';
+      if (old != '=')
+        {
+          /* value part omitted, use empty string... */
+          if (MHD_NO ==
+              connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
+            return MHD_NO;
+          if (old == '\0')
+            break;
+          pos = sce + 1;
+          continue;
+        }
+      equals = sce + 1;
+      quotes = 0;
+      semicolon = equals;
+      while ((semicolon[0] != '\0') &&
+             ((quotes != 0) ||
+              ((semicolon[0] != ';') && (semicolon[0] != ','))))
+        {
+          if (semicolon[0] == '"')
+            quotes = (quotes + 1) & 1;
+          semicolon++;
+        }
+      if (semicolon[0] == '\0')
+        semicolon = NULL;
+      if (semicolon != NULL)
+        {
+          semicolon[0] = '\0';
+          semicolon++;
+        }
+      /* remove quotes */
+      if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
+        {
+          equals[strlen (equals) - 1] = '\0';
+          equals++;
+        }
+      if (MHD_NO == connection_add_header (connection,
+                                           pos, equals, MHD_COOKIE_KIND))
+        return MHD_NO;
+      pos = semicolon;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Parse the first line of the HTTP HEADER.
+ *
+ * @param connection the connection (updated)
+ * @param line the first line
+ * @return MHD_YES if the line is ok, MHD_NO if it is malformed
+ */
+static int
+parse_initial_message_line (struct MHD_Connection *connection, char *line)
+{
+  char *uri;
+  char *httpVersion;
+  char *args;
+
+  if (NULL == (uri = strchr (line, ' ')))
+    return MHD_NO;              /* serious error */
+  uri[0] = '\0';
+  connection->method = line;
+  uri++;
+  while (uri[0] == ' ')
+    uri++;
+  httpVersion = strchr (uri, ' ');
+  if (httpVersion != NULL)
+    {
+      httpVersion[0] = '\0';
+      httpVersion++;
+    }
+  if (connection->daemon->uri_log_callback != NULL)
+    connection->client_context
+      =
+      connection->daemon->uri_log_callback (connection->daemon->
+                                            uri_log_callback_cls, uri);
+  args = strchr (uri, '?');
+  if (NULL != args)
+    {
+      args[0] = '\0';
+      args++;
+      parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
+    }
+  connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                        connection,
+                                        uri);
+  connection->url = uri;
+  if (NULL == httpVersion)
+    connection->version = "";
+  else
+    connection->version = httpVersion;
+  return MHD_YES;
+}
+
+
+/**
+ * Call the handler of the application for this
+ * connection.  Handles chunking of the upload
+ * as well as normal uploads.
+ */
+static void
+call_connection_handler (struct MHD_Connection *connection)
+{
+  size_t processed;
+
+  if (NULL != connection->response)
+    return;                     /* already queued a response */  
+  processed = 0;
+  connection->client_aware = MHD_YES;
+  if (MHD_NO ==
+      connection->daemon->default_handler (connection->daemon->
+                                          default_handler_cls,
+                                          connection, connection->url,
+                                          connection->method,
+                                          connection->version,
+                                          NULL, &processed,
+                                          &connection->client_context))
+    {
+      /* serious internal error, close connection */
+      CONNECTION_CLOSE_ERROR (connection, 
+                             "Internal application error, closing 
connection.\n");
+      return;
+    }
+}
+
+
+
+/**
+ * Call the handler of the application for this
+ * connection.  Handles chunking of the upload
+ * as well as normal uploads.
+ */
+static void
+process_request_body (struct MHD_Connection *connection)
+{
+  size_t processed;
+  size_t available;
+  size_t used;
+  size_t i;
+  int instant_retry;
+  int malformed;
+  char *buffer_head;
+  char *end;
+
+  if (NULL != connection->response)
+    return;                     /* already queued a response */
+
+  buffer_head = connection->read_buffer;
+  available = connection->read_buffer_offset;
+  do
+    {
+      instant_retry = MHD_NO;
+      if ((connection->have_chunked_upload == MHD_YES) &&
+          (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
+        {
+          if ((connection->current_chunk_offset ==
+               connection->current_chunk_size)
+              && (connection->current_chunk_offset != 0) && (available >= 2))
+            {
+              /* skip new line at the *end* of a chunk */
+              i = 0;
+              if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
+                i++;            /* skip 1st part of line feed */
+              if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
+                i++;            /* skip 2nd part of line feed */
+              if (i == 0)
+                {
+                  /* malformed encoding */
+                  CONNECTION_CLOSE_ERROR (connection,
+                                         "Received malformed HTTP request (bad 
chunked encoding), closing connection.\n");
+                  return;
+                }
+              available -= i;
+              buffer_head += i;
+              connection->current_chunk_offset = 0;
+              connection->current_chunk_size = 0;
+            }
+          if (connection->current_chunk_offset <
+              connection->current_chunk_size)
+            {
+              /* we are in the middle of a chunk, give
+                 as much as possible to the client (without
+                 crossing chunk boundaries) */
+              processed =
+                connection->current_chunk_size -
+                connection->current_chunk_offset;
+              if (processed > available)
+                processed = available;
+              if (available > processed)
+                instant_retry = MHD_YES;
+            }
+          else
+            {
+              /* we need to read chunk boundaries */
+              i = 0;
+              while (i < available)
+                {
+                  if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
+                    break;
+                  i++;
+                  if (i >= 6)
+                    break;
+                }
+              /* take '\n' into account; if '\n'
+                 is the unavailable character, we
+                 will need to wait until we have it
+                 before going further */
+              if ((i + 1 >= available) &&
+                  !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
+                break;          /* need more data... */
+              malformed = (i >= 6);
+              if (!malformed)
+                {
+                  buffer_head[i] = '\0';
+                 connection->current_chunk_size = strtoul (buffer_head, &end, 
16);
+                  malformed = ('\0' != *end);
+                }
+              if (malformed)
+                {
+                  /* malformed encoding */
+                  CONNECTION_CLOSE_ERROR (connection,
+                                         "Received malformed HTTP request (bad 
chunked encoding), closing connection.\n");
+                  return;
+                }
+              i++;
+              if ((i < available) &&
+                  ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
+                i++;            /* skip 2nd part of line feed */
+
+              buffer_head += i;
+              available -= i;
+              connection->current_chunk_offset = 0;
+
+              if (available > 0)
+                instant_retry = MHD_YES;
+              if (connection->current_chunk_size == 0)
+                {
+                  connection->remaining_upload_size = 0;
+                  break;
+                }
+              continue;
+            }
+        }
+      else
+        {
+          /* no chunked encoding, give all to the client */
+          if ( (0 != connection->remaining_upload_size) && 
+              (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
+              (connection->remaining_upload_size < available) )
+           {
+              processed = connection->remaining_upload_size;
+           }
+          else
+           {
+              /**
+               * 1. no chunked encoding, give all to the client
+               * 2. client may send large chunked data, but only a smaller 
part is available at one time.
+               */
+              processed = available;
+           }
+        }
+      used = processed;
+      connection->client_aware = MHD_YES;
+      if (MHD_NO ==
+          connection->daemon->default_handler (connection->daemon->
+                                               default_handler_cls,
+                                               connection, connection->url,
+                                               connection->method,
+                                               connection->version,
+                                               buffer_head, &processed,
+                                               &connection->client_context))
+        {
+          /* serious internal error, close connection */
+         CONNECTION_CLOSE_ERROR (connection,
+                                 "Internal application error, closing 
connection.\n");
+          return;
+        }
+      if (processed > used)
+        mhd_panic (mhd_panic_cls, __FILE__, __LINE__
+#if HAVE_MESSAGES
+                  , "API violation"
+#else
+                  , NULL
+#endif
+                  );
+      if (processed != 0)
+        instant_retry = MHD_NO; /* client did not process everything */
+      used -= processed;
+      if (connection->have_chunked_upload == MHD_YES)
+        connection->current_chunk_offset += used;
+      /* dh left "processed" bytes in buffer for next time... */
+      buffer_head += used;
+      available -= used;
+      if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
+        connection->remaining_upload_size -= used;
+    }
+  while (MHD_YES == instant_retry);
+  if (available > 0)
+    memmove (connection->read_buffer, buffer_head, available);
+  connection->read_buffer_offset = available;
+}
+
+
+/**
+ * Try reading data from the socket into the
+ * read buffer of the connection.
+ *
+ * @return MHD_YES if something changed,
+ *         MHD_NO if we were interrupted or if
+ *                no space was available
+ */
+static int
+do_read (struct MHD_Connection *connection)
+{
+  int bytes_read;
+
+  if (connection->read_buffer_size == connection->read_buffer_offset)
+    return MHD_NO;
+
+  bytes_read = connection->recv_cls (connection,
+                                     &connection->read_buffer
+                                     [connection->read_buffer_offset],
+                                     connection->read_buffer_size -
+                                     connection->read_buffer_offset);
+  if (bytes_read < 0)
+    {
+      if ((EINTR == errno) || (EAGAIN == errno))
+        return MHD_NO;
+#if HAVE_MESSAGES
+#if HTTPS_SUPPORT
+      if (0 != (connection->daemon->options & MHD_USE_SSL))
+       MHD_DLOG (connection->daemon,
+                 "Failed to receive data: %s\n",
+                 gnutls_strerror (bytes_read));
+      else
+#endif      
+       MHD_DLOG (connection->daemon,
+                 "Failed to receive data: %s\n", STRERROR (errno));
+#endif
+      CONNECTION_CLOSE_ERROR (connection, NULL);
+      return MHD_YES;
+    }
+  if (0 == bytes_read)
+    {
+      /* other side closed connection */
+      connection->read_closed = MHD_YES;
+      SHUTDOWN (connection->socket_fd, SHUT_RD);
+      return MHD_YES;
+    }
+  connection->read_buffer_offset += bytes_read;
+  return MHD_YES;
+}
+
+/**
+ * Try writing data to the socket from the
+ * write buffer of the connection.
+ *
+ * @return MHD_YES if something changed,
+ *         MHD_NO if we were interrupted
+ */
+static int
+do_write (struct MHD_Connection *connection)
+{
+  int ret;
+
+  ret = connection->send_cls (connection,
+                              &connection->write_buffer
+                              [connection->write_buffer_send_offset],
+                              connection->write_buffer_append_offset
+                              - connection->write_buffer_send_offset);
+
+  if (ret < 0)
+    {
+      if ((EINTR == errno) || (EAGAIN == errno))
+        return MHD_NO;
+#if HAVE_MESSAGES
+#if HTTPS_SUPPORT
+      if (0 != (connection->daemon->options & MHD_USE_SSL))
+       MHD_DLOG (connection->daemon,
+                 "Failed to send data: %s\n",
+                 gnutls_strerror (ret));
+      else
+#endif      
+       MHD_DLOG (connection->daemon,
+                 "Failed to send data: %s\n", STRERROR (errno));
+#endif
+      CONNECTION_CLOSE_ERROR (connection, NULL);
+      return MHD_YES;
+    }
+#if DEBUG_SEND_DATA
+  FPRINTF (stderr,
+           "Sent response: `%.*s'\n",
+           ret,
+           &connection->write_buffer[connection->write_buffer_send_offset]);
+#endif
+  connection->write_buffer_send_offset += ret;
+  return MHD_YES;
+}
+
+
+/**
+ * Check if we are done sending the write-buffer.
+ * If so, transition into "next_state".
+ *
+ * @param connection connection to check write status for
+ * @param next_state the next state to transition to
+ * @return MHY_NO if we are not done, MHD_YES if we are
+ */
+static int
+check_write_done (struct MHD_Connection *connection,
+                  enum MHD_CONNECTION_STATE next_state)
+{
+  if (connection->write_buffer_append_offset !=
+      connection->write_buffer_send_offset)
+    return MHD_NO;
+  connection->write_buffer_append_offset = 0;
+  connection->write_buffer_send_offset = 0;
+  connection->state = next_state;
+  MHD_pool_reallocate (connection->pool, connection->write_buffer,
+                       connection->write_buffer_size, 0);
+  connection->write_buffer = NULL;
+  connection->write_buffer_size = 0;
+  return MHD_YES;
+}
+
+
+/**
+ * We have received (possibly the beginning of) a line in the
+ * header (or footer).  Validate (check for ":") and prepare
+ * to process.
+ */
+static int
+process_header_line (struct MHD_Connection *connection, char *line)
+{
+  char *colon;
+
+  /* line should be normal header line, find colon */
+  colon = strchr (line, ':');
+  if (colon == NULL)
+    {
+      /* error in header line, die hard */
+      CONNECTION_CLOSE_ERROR (connection, 
+                             "Received malformed line (no colon), closing 
connection.\n");
+      return MHD_NO;
+    }
+  /* zero-terminate header */
+  colon[0] = '\0';
+  colon++;                      /* advance to value */
+  while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
+    colon++;
+  /* we do the actual adding of the connection
+     header at the beginning of the while
+     loop since we need to be able to inspect
+     the *next* header line (in case it starts
+     with a space...) */
+  connection->last = line;
+  connection->colon = colon;
+  return MHD_YES;
+}
+
+
+/**
+ * Process a header value that spans multiple lines.
+ * The previous line(s) are in connection->last.
+ *
+ * @param connection connection we're processing
+ * @param line the current input line
+ * @param kind if the line is complete, add a header
+ *        of the given kind
+ * @return MHD_YES if the line was processed successfully
+ */
+static int
+process_broken_line (struct MHD_Connection *connection,
+                     char *line, enum MHD_ValueKind kind)
+{
+  char *last;
+  char *tmp;
+  size_t last_len;
+  size_t tmp_len;
+
+  last = connection->last;
+  if ((line[0] == ' ') || (line[0] == '\t'))
+    {
+      /* value was continued on the next line, see
+         http://www.jmarshall.com/easy/http/ */
+      last_len = strlen (last);
+      /* skip whitespace at start of 2nd line */
+      tmp = line;
+      while ((tmp[0] == ' ') || (tmp[0] == '\t'))
+        tmp++;                  
+      tmp_len = strlen (tmp);
+      last = MHD_pool_reallocate (connection->pool,
+                                  last,
+                                  last_len + 1,
+                                  last_len + tmp_len + 1);
+      if (last == NULL)
+        {
+          transmit_error_response (connection,
+                                   MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
+                                   REQUEST_TOO_BIG);
+          return MHD_NO;
+        }
+      memcpy (&last[last_len], tmp, tmp_len + 1);
+      connection->last = last;
+      return MHD_YES;           /* possibly more than 2 lines... */
+    }
+  EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
+  if ((MHD_NO == connection_add_header (connection,
+                                        last, connection->colon, kind)))
+    {
+      transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
+                               REQUEST_TOO_BIG);
+      return MHD_NO;
+    }
+  /* we still have the current line to deal with... */
+  if (strlen (line) != 0)
+    {
+      if (MHD_NO == process_header_line (connection, line))
+        {
+          transmit_error_response (connection,
+                                   MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
+          return MHD_NO;
+        }
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Parse the various headers; figure out the size
+ * of the upload and make sure the headers follow
+ * the protocol.  Advance to the appropriate state.
+ */
+static void
+parse_connection_headers (struct MHD_Connection *connection)
+{
+  const char *clen;
+  MHD_UNSIGNED_LONG_LONG cval;
+  struct MHD_Response *response;
+  const char *enc;
+  char *end;
+
+  parse_cookie_header (connection);
+  if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
+      && (NULL != connection->version)
+      && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
+      && (NULL ==
+          MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
+                                       MHD_HTTP_HEADER_HOST)))
+    {
+      /* die, http 1.1 request without host and we are pedantic */
+      connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+      connection->read_closed = MHD_YES;
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon,
+                "Received `%s' request without `%s' header.\n",
+                MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
+#endif
+      EXTRA_CHECK (connection->response == NULL);
+      response =
+        MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST),
+                                        REQUEST_LACKS_HOST,
+                                        MHD_RESPMEM_PERSISTENT);
+      MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
+      MHD_destroy_response (response);
+      return;
+    }
+
+  connection->remaining_upload_size = 0;
+  enc = MHD_lookup_connection_value (connection,
+                                    MHD_HEADER_KIND,
+                                    MHD_HTTP_HEADER_TRANSFER_ENCODING);
+  if (enc != NULL)
+    {
+      connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
+      if (0 == strcasecmp (enc, "chunked"))
+        connection->have_chunked_upload = MHD_YES;
+    }
+  else
+    {
+      clen = MHD_lookup_connection_value (connection,
+                                         MHD_HEADER_KIND,
+                                         MHD_HTTP_HEADER_CONTENT_LENGTH);
+      if (clen != NULL)
+        {
+          cval = strtoul (clen, &end, 10);
+          if ( ('\0' != *end) ||
+            ( (LONG_MAX == cval) && (errno == ERANGE) ) )
+            {
+#if HAVE_MESSAGES
+              MHD_DLOG (connection->daemon,
+                    "Failed to parse `%s' header `%s', closing connection.\n",
+                    MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
+#endif
+             CONNECTION_CLOSE_ERROR (connection, NULL);
+              return;
+            }
+          connection->remaining_upload_size = cval;
+        }
+    }
+}
+
+
+/**
+ * This function handles a particular connection when it has been
+ * determined that there is data to be read off a socket. All
+ * implementations (multithreaded, external select, internal select)
+ * call this function to handle reads.
+ *
+ * @param connection connection to handle
+ * @return always MHD_YES (we should continue to process the
+ *         connection)
+ */
+int
+MHD_connection_handle_read (struct MHD_Connection *connection)
+{
+  connection->last_activity = MHD_monotonic_time();
+  if (connection->state == MHD_CONNECTION_CLOSED)
+    return MHD_YES;
+  /* make sure "read" has a reasonable number of bytes
+     in buffer to use per system call (if possible) */
+  if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
+      connection->read_buffer_size)
+    try_grow_read_buffer (connection);
+  if (MHD_NO == do_read (connection))
+    return MHD_YES;
+  while (1)
+    {
+#if DEBUG_STATES
+      MHD_DLOG (connection->daemon, "%s: state: %s\n",
+                __FUNCTION__, MHD_state_to_string (connection->state));
+#endif
+      switch (connection->state)
+        {
+        case MHD_CONNECTION_INIT:
+        case MHD_CONNECTION_URL_RECEIVED:
+        case MHD_CONNECTION_HEADER_PART_RECEIVED:
+        case MHD_CONNECTION_HEADERS_RECEIVED:
+        case MHD_CONNECTION_HEADERS_PROCESSED:
+        case MHD_CONNECTION_CONTINUE_SENDING:
+        case MHD_CONNECTION_CONTINUE_SENT:
+        case MHD_CONNECTION_BODY_RECEIVED:
+        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+          /* nothing to do but default action */
+          if (MHD_YES == connection->read_closed)
+            {
+             MHD_connection_close (connection,
+                                   MHD_REQUEST_TERMINATED_READ_ERROR);
+              continue;
+            }
+          break;
+        case MHD_CONNECTION_CLOSED:
+          return MHD_YES;
+        default:
+          /* shrink read buffer to how much is actually used */
+          MHD_pool_reallocate (connection->pool,
+                               connection->read_buffer,
+                               connection->read_buffer_size + 1,
+                               connection->read_buffer_offset);
+          break;
+        }
+      break;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * This function was created to handle writes to sockets when it has
+ * been determined that the socket can be written to. All
+ * implementations (multithreaded, external select, internal select)
+ * call this function
+ *
+ * @param connection connection to handle
+ * @return always MHD_YES (we should continue to process the
+ *         connection)
+ */
+int
+MHD_connection_handle_write (struct MHD_Connection *connection)
+{
+  struct MHD_Response *response;
+  int ret;
+  connection->last_activity = MHD_monotonic_time();
+  while (1)
+    {
+#if DEBUG_STATES
+      MHD_DLOG (connection->daemon, "%s: state: %s\n",
+                __FUNCTION__, MHD_state_to_string (connection->state));
+#endif
+      switch (connection->state)
+        {
+        case MHD_CONNECTION_INIT:
+        case MHD_CONNECTION_URL_RECEIVED:
+        case MHD_CONNECTION_HEADER_PART_RECEIVED:
+        case MHD_CONNECTION_HEADERS_RECEIVED:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_HEADERS_PROCESSED:
+          break;
+        case MHD_CONNECTION_CONTINUE_SENDING:
+          ret = connection->send_cls (connection,
+                                      &HTTP_100_CONTINUE
+                                      
[connection->continue_message_write_offset],
+                                      strlen (HTTP_100_CONTINUE) -
+                                      
connection->continue_message_write_offset);
+          if (ret < 0)
+            {
+              if ((errno == EINTR) || (errno == EAGAIN))
+                break;
+#if HAVE_MESSAGES
+              MHD_DLOG (connection->daemon,
+                        "Failed to send data: %s\n", STRERROR (errno));
+#endif
+             CONNECTION_CLOSE_ERROR (connection, NULL);
+              return MHD_YES;
+            }
+#if DEBUG_SEND_DATA
+          FPRINTF (stderr,
+                   "Sent 100 continue response: `%.*s'\n",
+                   ret,
+                   &HTTP_100_CONTINUE
+                   [connection->continue_message_write_offset]);
+#endif
+          connection->continue_message_write_offset += ret;
+          break;
+        case MHD_CONNECTION_CONTINUE_SENT:
+        case MHD_CONNECTION_BODY_RECEIVED:
+        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+        case MHD_CONNECTION_FOOTERS_RECEIVED:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_HEADERS_SENDING:
+          do_write (connection);
+         if (connection->state != MHD_CONNECTION_HEADERS_SENDING)
+            break;
+          check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
+          break;
+        case MHD_CONNECTION_HEADERS_SENT:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_NORMAL_BODY_READY:
+          response = connection->response;
+          if (response->crc != NULL)
+            pthread_mutex_lock (&response->mutex);
+          if (MHD_YES != try_ready_normal_body (connection))
+            {
+              if (response->crc != NULL)
+                pthread_mutex_unlock (&response->mutex);
+              break;
+            }
+         ret = connection->send_cls (connection,
+                                     &response->data
+                                     [connection->response_write_position
+                                      - response->data_start],
+                                     response->data_size -
+                                     (connection->response_write_position
+                                      - response->data_start));
+#if DEBUG_SEND_DATA
+          if (ret > 0)
+            FPRINTF (stderr,
+                     "Sent DATA response: `%.*s'\n",
+                     ret,
+                     &response->data[connection->response_write_position -
+                                     response->data_start]);
+#endif
+          if (response->crc != NULL)
+            pthread_mutex_unlock (&response->mutex);
+          if (ret < 0)
+            {
+              if ((errno == EINTR) || (errno == EAGAIN))
+                return MHD_YES;
+#if HAVE_MESSAGES
+              MHD_DLOG (connection->daemon,
+                        "Failed to send data: %s\n", STRERROR (errno));
+#endif
+             CONNECTION_CLOSE_ERROR (connection, NULL);
+              return MHD_YES;
+            }
+          connection->response_write_position += ret;
+          if (connection->response_write_position ==
+              connection->response->total_size)
+            connection->state = MHD_CONNECTION_FOOTERS_SENT;    /* have no 
footers... */
+          break;
+        case MHD_CONNECTION_NORMAL_BODY_UNREADY:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_CHUNKED_BODY_READY:
+          do_write (connection);
+         if (connection->state !=  MHD_CONNECTION_CHUNKED_BODY_READY)
+            break;
+          check_write_done (connection,
+                            (connection->response->total_size ==
+                             connection->response_write_position) ?
+                            MHD_CONNECTION_BODY_SENT :
+                            MHD_CONNECTION_CHUNKED_BODY_UNREADY);
+          break;
+        case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
+        case MHD_CONNECTION_BODY_SENT:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_FOOTERS_SENDING:
+          do_write (connection);
+         if (connection->state != MHD_CONNECTION_FOOTERS_SENDING)
+           break;
+          check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
+          break;
+        case MHD_CONNECTION_FOOTERS_SENT:
+          EXTRA_CHECK (0);
+          break;
+        case MHD_CONNECTION_CLOSED:
+          return MHD_YES;
+        case MHD_TLS_CONNECTION_INIT:
+          EXTRA_CHECK (0);
+          break;
+        default:
+          EXTRA_CHECK (0);
+         CONNECTION_CLOSE_ERROR (connection, "Internal error\n");
+          return MHD_YES;
+        }
+      break;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * This function was created to handle per-connection processing that
+ * has to happen even if the socket cannot be read or written to.  All
+ * implementations (multithreaded, external select, internal select)
+ * call this function.
+ *
+ * @param connection connection to handle
+ * @return MHD_YES if we should continue to process the
+ *         connection (not dead yet), MHD_NO if it died
+ */
+int
+MHD_connection_handle_idle (struct MHD_Connection *connection)
+{
+  struct MHD_Daemon *daemon;
+  unsigned int timeout;
+  const char *end;
+  int rend;
+  char *line;
+
+  while (1)
+    {
+#if DEBUG_STATES
+      MHD_DLOG (connection->daemon, "%s: state: %s\n",
+                __FUNCTION__, MHD_state_to_string (connection->state));
+#endif
+      switch (connection->state)
+        {
+        case MHD_CONNECTION_INIT:
+          line = get_next_header_line (connection);
+          if (line == NULL)
+            {
+              if (connection->state != MHD_CONNECTION_INIT)
+                continue;
+              if (connection->read_closed)
+                {
+                 CONNECTION_CLOSE_ERROR (connection, 
+                                         NULL);
+                  continue;
+                }
+              break;
+            }
+          if (MHD_NO == parse_initial_message_line (connection, line))
+            CONNECTION_CLOSE_ERROR (connection, NULL);
+          else
+            connection->state = MHD_CONNECTION_URL_RECEIVED;
+          continue;
+        case MHD_CONNECTION_URL_RECEIVED:
+          line = get_next_header_line (connection);
+          if (line == NULL)
+            {
+              if (connection->state != MHD_CONNECTION_URL_RECEIVED)
+                continue;
+              if (connection->read_closed)
+                {
+                 CONNECTION_CLOSE_ERROR (connection, 
+                                         NULL);
+                  continue;
+                }
+              break;
+            }
+          if (strlen (line) == 0)
+            {
+              connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
+              continue;
+            }
+          if (MHD_NO == process_header_line (connection, line))
+            {
+              transmit_error_response (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       REQUEST_MALFORMED);
+              break;
+            }
+          connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
+          continue;
+        case MHD_CONNECTION_HEADER_PART_RECEIVED:
+          line = get_next_header_line (connection);
+          if (line == NULL)
+            {
+              if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
+                continue;
+              if (connection->read_closed)
+                {
+                 CONNECTION_CLOSE_ERROR (connection, 
+                                         NULL);
+                  continue;
+                }
+              break;
+            }
+          if (MHD_NO ==
+              process_broken_line (connection, line, MHD_HEADER_KIND))
+            continue;
+          if (strlen (line) == 0)
+            {
+              connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
+              continue;
+            }
+          continue;
+        case MHD_CONNECTION_HEADERS_RECEIVED:
+          parse_connection_headers (connection);
+          if (connection->state == MHD_CONNECTION_CLOSED)
+            continue;
+          connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
+          continue;
+        case MHD_CONNECTION_HEADERS_PROCESSED:
+          call_connection_handler (connection); /* first call */
+          if (connection->state == MHD_CONNECTION_CLOSED)
+            continue;
+          if (need_100_continue (connection))
+            {
+              connection->state = MHD_CONNECTION_CONTINUE_SENDING;
+              break;
+            }
+          if (connection->response != NULL)
+            {
+              /* we refused (no upload allowed!) */
+              connection->remaining_upload_size = 0;
+              /* force close, in case client still tries to upload... */
+              connection->read_closed = MHD_YES;
+            }
+          connection->state = (connection->remaining_upload_size == 0)
+            ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
+          continue;
+        case MHD_CONNECTION_CONTINUE_SENDING:
+          if (connection->continue_message_write_offset ==
+              strlen (HTTP_100_CONTINUE))
+            {
+              connection->state = MHD_CONNECTION_CONTINUE_SENT;
+              continue;
+            }
+          break;
+        case MHD_CONNECTION_CONTINUE_SENT:
+          if (connection->read_buffer_offset != 0)
+            {
+              process_request_body (connection);     /* loop call */
+              if (connection->state == MHD_CONNECTION_CLOSED)
+                continue;
+            }
+          if ((connection->remaining_upload_size == 0) ||
+              ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
+               (connection->read_buffer_offset == 0) &&
+               (MHD_YES == connection->read_closed)))
+            {
+              if ((MHD_YES == connection->have_chunked_upload) &&
+                  (MHD_NO == connection->read_closed))
+                connection->state = MHD_CONNECTION_BODY_RECEIVED;
+              else
+                connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+              continue;
+            }
+          break;
+        case MHD_CONNECTION_BODY_RECEIVED:
+          line = get_next_header_line (connection);
+          if (line == NULL)
+            {
+              if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
+                continue;
+              if (connection->read_closed)
+                {
+                 CONNECTION_CLOSE_ERROR (connection, 
+                                         NULL);
+                  continue;
+                }
+              break;
+            }
+          if (strlen (line) == 0)
+            {
+              connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+              continue;
+            }
+          if (MHD_NO == process_header_line (connection, line))
+            {
+              transmit_error_response (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       REQUEST_MALFORMED);
+              break;
+            }
+          connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
+          continue;
+        case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+          line = get_next_header_line (connection);
+          if (line == NULL)
+            {
+              if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
+                continue;
+              if (connection->read_closed)
+                {
+                 CONNECTION_CLOSE_ERROR (connection, 
+                                         NULL);
+                  continue;
+                }
+              break;
+            }
+          if (MHD_NO ==
+              process_broken_line (connection, line, MHD_FOOTER_KIND))
+            continue;
+          if (strlen (line) == 0)
+            {
+              connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
+              continue;
+            }
+          continue;
+        case MHD_CONNECTION_FOOTERS_RECEIVED:
+          call_connection_handler (connection); /* "final" call */
+          if (connection->state == MHD_CONNECTION_CLOSED)
+            continue;
+          if (connection->response == NULL)
+            break;              /* try again next time */
+          if (MHD_NO == build_header_response (connection))
+            {
+              /* oops - close! */
+             CONNECTION_CLOSE_ERROR (connection, 
+                                     "Closing connection (failed to create 
response header)\n");
+              continue;
+            }
+          connection->state = MHD_CONNECTION_HEADERS_SENDING;
+
+#if HAVE_DECL_TCP_CORK
+          /* starting header send, set TCP cork */
+          {
+            const int val = 1;
+            setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
+                        sizeof (val));
+          }
+#endif
+          break;
+        case MHD_CONNECTION_HEADERS_SENDING:
+          /* no default action */
+          break;
+        case MHD_CONNECTION_HEADERS_SENT:
+          if (connection->have_chunked_upload)
+            connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
+          else
+            connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
+          continue;
+        case MHD_CONNECTION_NORMAL_BODY_READY:
+          /* nothing to do here */
+          break;
+        case MHD_CONNECTION_NORMAL_BODY_UNREADY:
+          if (connection->response->crc != NULL)
+            pthread_mutex_lock (&connection->response->mutex);
+          if (MHD_YES == try_ready_normal_body (connection))
+            {
+              if (connection->response->crc != NULL)
+                pthread_mutex_unlock (&connection->response->mutex);
+              connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
+              break;
+            }
+          if (connection->response->crc != NULL)
+            pthread_mutex_unlock (&connection->response->mutex);
+          /* not ready, no socket action */
+          break;
+        case MHD_CONNECTION_CHUNKED_BODY_READY:
+          /* nothing to do here */
+          break;
+        case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
+          if (connection->response->crc != NULL)
+            pthread_mutex_lock (&connection->response->mutex);
+          if (MHD_YES == try_ready_chunked_body (connection))
+            {
+              if (connection->response->crc != NULL)
+                pthread_mutex_unlock (&connection->response->mutex);
+              connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
+              continue;
+            }
+          if (connection->response->crc != NULL)
+            pthread_mutex_unlock (&connection->response->mutex);
+          break;
+        case MHD_CONNECTION_BODY_SENT:
+          build_header_response (connection);
+          if (connection->write_buffer_send_offset ==
+              connection->write_buffer_append_offset)
+            connection->state = MHD_CONNECTION_FOOTERS_SENT;
+          else
+            connection->state = MHD_CONNECTION_FOOTERS_SENDING;
+          continue;
+        case MHD_CONNECTION_FOOTERS_SENDING:
+          /* no default action */
+          break;
+        case MHD_CONNECTION_FOOTERS_SENT:
+#if HAVE_DECL_TCP_CORK
+          /* done sending, uncork */
+          {
+            const int val = 0;
+            setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
+                        sizeof (val));
+          }
+#endif
+          end =
+            MHD_get_response_header (connection->response, 
+                                    MHD_HTTP_HEADER_CONNECTION);
+         rend = ( (end != NULL) && (0 == strcasecmp (end, "close")) );
+          MHD_destroy_response (connection->response);
+          connection->response = NULL;
+          if (connection->daemon->notify_completed != NULL)
+           connection->daemon->notify_completed (connection->daemon->
+                                                 notify_completed_cls,
+                                                 connection,
+                                                 &connection->client_context,
+                                                 
MHD_REQUEST_TERMINATED_COMPLETED_OK);     
+         connection->client_aware = MHD_NO;
+          end =
+            MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
+                                         MHD_HTTP_HEADER_CONNECTION);
+          connection->client_context = NULL;
+          connection->continue_message_write_offset = 0;
+          connection->responseCode = 0;
+          connection->headers_received = NULL;
+         connection->headers_received_tail = NULL;
+          connection->response_write_position = 0;
+          connection->have_chunked_upload = MHD_NO;
+          connection->method = NULL;
+          connection->url = NULL;
+          connection->write_buffer = NULL;
+          connection->write_buffer_size = 0;
+          connection->write_buffer_send_offset = 0;
+          connection->write_buffer_append_offset = 0;
+          if ( (rend) || ((end != NULL) && (0 == strcasecmp (end, "close"))) )
+            {
+              connection->read_closed = MHD_YES;
+              connection->read_buffer_offset = 0;
+            }
+          if (((MHD_YES == connection->read_closed) &&
+               (0 == connection->read_buffer_offset)) ||
+              (connection->version == NULL) ||
+              (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
+            {
+              /* http 1.0, version-less requests cannot be pipelined */
+              MHD_connection_close (connection, 
MHD_REQUEST_TERMINATED_COMPLETED_OK);
+              MHD_pool_destroy (connection->pool);
+              connection->pool = NULL;
+              connection->read_buffer = NULL;
+              connection->read_buffer_size = 0;
+              connection->read_buffer_offset = 0;
+            }
+          else
+            {
+              connection->version = NULL;
+              connection->state = MHD_CONNECTION_INIT;
+              connection->read_buffer
+                = MHD_pool_reset (connection->pool,
+                                  connection->read_buffer,
+                                  connection->read_buffer_size);
+            }
+          continue;
+        case MHD_CONNECTION_CLOSED:
+         if (connection->response != NULL)
+           {
+             MHD_destroy_response (connection->response);
+             connection->response = NULL;
+           }
+         daemon = connection->daemon;
+         if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
+           {
+             MHD_PANIC ("Failed to acquire cleanup mutex\n");
+           }
+         DLL_remove (daemon->connections_head,
+                     daemon->connections_tail,
+                     connection);
+         DLL_insert (daemon->cleanup_head,
+                     daemon->cleanup_tail,
+                     connection);
+         if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
+           {
+             MHD_PANIC ("Failed to release cleanup mutex\n");
+           }
+         return MHD_NO;
+        default:
+          EXTRA_CHECK (0);
+          break;
+        }
+      break;
+    }
+  timeout = connection->connection_timeout;
+  if ( (timeout != 0) &&
+       (timeout <= (MHD_monotonic_time() - connection->last_activity)) )
+    {
+      MHD_connection_close (connection, 
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
+      return MHD_YES;
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Set callbacks for this connection to those for HTTP.
+ *
+ * @param connection connection to initialize
+ */
+void
+MHD_set_http_callbacks_ (struct MHD_Connection *connection)
+{
+  connection->read_handler = &MHD_connection_handle_read;
+  connection->write_handler = &MHD_connection_handle_write;
+  connection->idle_handler = &MHD_connection_handle_idle;
+}
+
+
+/**
+ * Obtain information about the given connection.
+ *
+ * @param connection what connection to get information about
+ * @param infoType what information is desired?
+ * @param ... depends on infoType
+ * @return NULL if this information is not available
+ *         (or if the infoType is unknown)
+ */
+const union MHD_ConnectionInfo *
+MHD_get_connection_info (struct MHD_Connection *connection,
+                         enum MHD_ConnectionInfoType infoType, ...)
+{
+  switch (infoType)
+    {
+#if HTTPS_SUPPORT
+    case MHD_CONNECTION_INFO_CIPHER_ALGO:
+      if (connection->tls_session == NULL)
+       return NULL;
+      connection->cipher = gnutls_cipher_get (connection->tls_session);
+      return (const union MHD_ConnectionInfo *) &connection->cipher;
+    case MHD_CONNECTION_INFO_PROTOCOL:
+      if (connection->tls_session == NULL)
+       return NULL;
+      connection->protocol = gnutls_protocol_get_version 
(connection->tls_session);
+      return (const union MHD_ConnectionInfo *) &connection->protocol;
+    case MHD_CONNECTION_INFO_GNUTLS_SESSION:
+      if (connection->tls_session == NULL)
+       return NULL;
+      return (const union MHD_ConnectionInfo *) &connection->tls_session;
+#endif
+    case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
+      return (const union MHD_ConnectionInfo *) &connection->addr;
+    case MHD_CONNECTION_INFO_DAEMON:
+      return (const union MHD_ConnectionInfo *) &connection->daemon;
+    default:
+      return NULL;
+    };
+}
+
+
+/**
+ * Set a custom option for the given connection, overriding defaults.
+ *
+ * @param connection connection to modify
+ * @param option option to set
+ * @param ... arguments to the option, depending on the option type
+ * @return MHD_YES on success, MHD_NO if setting the option failed
+ */
+int 
+MHD_set_connection_option (struct MHD_Connection *connection,
+                          enum MHD_CONNECTION_OPTION option,
+                          ...)
+{
+  va_list ap;
+
+  switch (option)
+    {
+    case MHD_CONNECTION_OPTION_TIMEOUT:
+      va_start (ap, option);
+      connection->connection_timeout = va_arg (ap, unsigned int);
+      va_end (ap);
+      return MHD_YES;
+    default:
+      return MHD_NO;
+    }
+}
+
+
+/* end of connection.c */

Deleted: libmicrohttpd/src/microhttpd/daemon.c
===================================================================
--- libmicrohttpd/src/daemon/daemon.c   2013-05-05 12:01:06 UTC (rev 27023)
+++ libmicrohttpd/src/microhttpd/daemon.c       2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,2947 +0,0 @@
-/*
-  This file is part of libmicrohttpd
-  (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
-
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Lesser General Public
-  License as published by the Free Software Foundation; either
-  version 2.1 of the License, or (at your option) any later version.
-
-  This library 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
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
-
-*/
-
-/**
- * @file daemon.c
- * @brief  A minimal-HTTP server library
- * @author Daniel Pittman
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "internal.h"
-#include "response.h"
-#include "connection.h"
-#include "memorypool.h"
-#include <limits.h>
-
-#if HAVE_SEARCH_H
-#include <search.h>
-#else
-#include "tsearch.h"
-#endif
-
-#if HTTPS_SUPPORT
-#include "connection_https.h"
-#include <gnutls/gnutls.h>
-#include <gcrypt.h>
-#endif
-
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-
-#ifdef LINUX
-#include <sys/sendfile.h>
-#endif
-
-/**
- * Default connection limit.
- */
-#ifndef WINDOWS
-#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE - 4
-#else
-#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE
-#endif
-
-/**
- * Default memory allowed per connection.
- */
-#define MHD_POOL_SIZE_DEFAULT (32 * 1024)
-
-/**
- * Print extra messages with reasons for closing
- * sockets? (only adds non-error messages).
- */
-#define DEBUG_CLOSE MHD_NO
-
-/**
- * Print extra messages when establishing
- * connections? (only adds non-error messages).
- */
-#define DEBUG_CONNECT MHD_NO
-
-#ifndef LINUX
-#ifndef MSG_NOSIGNAL
-#define MSG_NOSIGNAL 0
-#endif
-#endif
-
-#ifndef SOCK_CLOEXEC
-#define SOCK_CLOEXEC 0
-#endif
-
-
-/**
- * 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 msg error message with details
- */
-static void 
-mhd_panic_std (void *cls,
-              const char *file,
-              unsigned int line,
-              const char *reason)
-{
-#if HAVE_MESSAGES
-  fprintf (stderr, "Fatal error in GNU libmicrohttpd %s:%u: %s\n",
-          file, line, reason);
-#endif
-  abort ();
-}
-
-
-/**
- * Handler for fatal errors.
- */
-MHD_PanicCallback mhd_panic;
-
-/**
- * Closure argument for "mhd_panic".
- */
-void *mhd_panic_cls;
-
-
-/**
- * Trace up to and return master daemon. If the supplied daemon
- * is a master, then return the daemon itself.
- *
- * @param daemon handle to a daemon 
- * @return master daemon handle
- */
-static struct MHD_Daemon*
-MHD_get_master (struct MHD_Daemon *daemon)
-{
-  while (NULL != daemon->master)
-    daemon = daemon->master;
-  return daemon;
-}
-
-
-/**
- * Maintain connection count for single address.
- */
-struct MHD_IPCount
-{
-  /**
-   * Address family. AF_INET or AF_INET6 for now.
-   */
-  int family;
-
-  /**
-   * Actual address.
-   */
-  union
-  {
-    /**
-     * IPv4 address.
-     */ 
-    struct in_addr ipv4;
-#if HAVE_IPV6
-    /**
-     * IPv6 address.
-     */ 
-    struct in6_addr ipv6;
-#endif
-  } addr;
-
-  /**
-   * Counter.
-   */
-  unsigned int count;
-};
-
-
-/**
- * Lock shared structure for IP connection counts and connection DLLs.
- *
- * @param daemon handle to daemon where lock is
- */
-static void
-MHD_ip_count_lock(struct MHD_Daemon *daemon)
-{
-  if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex))
-    {
-      MHD_PANIC ("Failed to acquire IP connection limit mutex\n");
-    }
-}
-
-
-/**
- * Unlock shared structure for IP connection counts and connection DLLs.
- *
- * @param daemon handle to daemon where lock is
- */
-static void
-MHD_ip_count_unlock(struct MHD_Daemon *daemon)
-{
-  if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex))
-    {
-      MHD_PANIC ("Failed to release IP connection limit mutex\n");
-    }
-}
-
-
-/**
- * Tree comparison function for IP addresses (supplied to tsearch() family).
- * We compare everything in the struct up through the beginning of the
- * 'count' field.
- * 
- * @param a1 first address to compare
- * @param a2 second address to compare
- * @return -1, 0 or 1 depending on result of compare
- */
-static int
-MHD_ip_addr_compare(const void *a1, const void *a2)
-{
-  return memcmp (a1, a2, offsetof (struct MHD_IPCount, count));
-}
-
-
-/**
- * Parse address and initialize 'key' using the address.
- *
- * @param addr address to parse
- * @param addrlen number of bytes in addr
- * @param key where to store the parsed address
- * @return MHD_YES on success and MHD_NO otherwise (e.g., invalid address type)
- */
-static int
-MHD_ip_addr_to_key(const struct sockaddr *addr, 
-                  socklen_t addrlen,
-                   struct MHD_IPCount *key)
-{
-  memset(key, 0, sizeof(*key));
-
-  /* IPv4 addresses */
-  if (sizeof (struct sockaddr_in) == addrlen)
-    {
-      const struct sockaddr_in *addr4 = (const struct sockaddr_in*) addr;
-      key->family = AF_INET;
-      memcpy (&key->addr.ipv4, &addr4->sin_addr, sizeof(addr4->sin_addr));
-      return MHD_YES;
-    }
-
-#if HAVE_IPV6
-  /* IPv6 addresses */
-  if (sizeof (struct sockaddr_in6) == addrlen)
-    {
-      const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*) addr;
-      key->family = AF_INET6;
-      memcpy (&key->addr.ipv6, &addr6->sin6_addr, sizeof(addr6->sin6_addr));
-      return MHD_YES;
-    }
-#endif
-
-  /* Some other address */
-  return MHD_NO;
-}
-
-
-/**
- * Check if IP address is over its limit.
- *
- * @param daemon handle to daemon where connection counts are tracked
- * @param addr address to add (or increment counter)
- * @param addrlen number of bytes in addr
- * @return Return MHD_YES if IP below limit, MHD_NO if IP has surpassed limit.
- *   Also returns MHD_NO if fails to allocate memory.
- */
-static int
-MHD_ip_limit_add(struct MHD_Daemon *daemon,
-                 const struct sockaddr *addr,
-                socklen_t addrlen)
-{
-  struct MHD_IPCount *key;
-  void **nodep;
-  void *node;
-  int result;
-
-  daemon = MHD_get_master (daemon);
-  /* Ignore if no connection limit assigned */
-  if (0 == daemon->per_ip_connection_limit)
-    return MHD_YES;
-
-  if (NULL == (key = malloc (sizeof(*key))))
-    return MHD_NO;
-
-  /* Initialize key */
-  if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key))
-    {
-      /* Allow unhandled address types through */
-      free (key);
-      return MHD_YES;
-    }
-  MHD_ip_count_lock (daemon);
-
-  /* Search for the IP address */
-  if (NULL == (nodep = TSEARCH (key, 
-                               &daemon->per_ip_connection_count, 
-                               &MHD_ip_addr_compare)))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-               "Failed to add IP connection count node\n");
-#endif      
-      MHD_ip_count_unlock (daemon);
-      free (key);
-      return MHD_NO;
-    }
-  node = *nodep;
-  /* If we got an existing node back, free the one we created */
-  if (node != key)
-    free(key);
-  key = (struct MHD_IPCount *) node;
-  /* Test if there is room for another connection; if so,
-   * increment count */
-  result = (key->count < daemon->per_ip_connection_limit);
-  if (MHD_YES == result)
-    ++key->count;
-
-  MHD_ip_count_unlock (daemon);
-  return result;
-}
-
-
-/**
- * Decrement connection count for IP address, removing from table
- * count reaches 0
- *
- * @param daemon handle to daemon where connection counts are tracked
- * @param addr address to remove (or decrement counter)
- * @param addrlen number of bytes in addr
- */
-static void
-MHD_ip_limit_del(struct MHD_Daemon *daemon,
-                 const struct sockaddr *addr,
-                socklen_t addrlen)
-{
-  struct MHD_IPCount search_key;
-  struct MHD_IPCount *found_key;
-  void **nodep;
-
-  daemon = MHD_get_master (daemon);
-  /* Ignore if no connection limit assigned */
-  if (0 == daemon->per_ip_connection_limit)
-    return;
-  /* Initialize search key */
-  if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key))
-    return;
-
-  MHD_ip_count_lock (daemon);
-
-  /* Search for the IP address */
-  if (NULL == (nodep = TFIND (&search_key, 
-                             &daemon->per_ip_connection_count, 
-                             &MHD_ip_addr_compare)))
-    {      
-      /* Something's wrong if we couldn't find an IP address
-       * that was previously added */
-      MHD_PANIC ("Failed to find previously-added IP address\n");
-    }
-  found_key = (struct MHD_IPCount *) *nodep;
-  /* Validate existing count for IP address */
-  if (0 == found_key->count)
-    {
-      MHD_PANIC ("Previously-added IP address had 0 count\n");
-    }
-  /* Remove the node entirely if count reduces to 0 */
-  if (0 == --found_key->count)
-    {
-      TDELETE (found_key, 
-              &daemon->per_ip_connection_count, 
-              &MHD_ip_addr_compare);
-      free (found_key);
-    }
-
-  MHD_ip_count_unlock (daemon);
-}
-
-
-#if HTTPS_SUPPORT
-/**
- * Callback for receiving data from the socket.
- *
- * @param connection the MHD connection structure
- * @param other where to write received data to
- * @param i maximum size of other (in bytes)
- * @return number of bytes actually received
- */
-static ssize_t
-recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i)
-{
-  int res;
-
-  connection->tls_read_ready = MHD_NO;
-  res = gnutls_record_recv (connection->tls_session, other, i);
-  if ( (GNUTLS_E_AGAIN == res) ||
-       (GNUTLS_E_INTERRUPTED == res) )
-    {
-      errno = EINTR;
-      return -1;
-    }
-  if (res < 0)
-    {
-      /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
-        disrupted); set errno to something caller will interpret
-        correctly as a hard error*/
-      errno = EPIPE;
-      return res;
-    }
-  if (res == i)
-    connection->tls_read_ready = MHD_YES;
-  return res;
-}
-
-
-/**
- * Callback for writing data to the socket.
- *
- * @param connection the MHD connection structure
- * @param other data to write
- * @param i number of bytes to write
- * @return actual number of bytes written
- */
-static ssize_t
-send_tls_adapter (struct MHD_Connection *connection,
-                  const void *other, size_t i)
-{
-  int res;
-
-  res = gnutls_record_send (connection->tls_session, other, i);
-  if ( (GNUTLS_E_AGAIN == res) ||
-       (GNUTLS_E_INTERRUPTED == res) )
-    {
-      errno = EINTR;
-      return -1;
-    }
-  return res;
-}
-
-
-/**
- * Read and setup our certificate and key.
- *
- * @param daemon handle to daemon to initialize
- * @return 0 on success
- */
-static int
-MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
-{
-  gnutls_datum_t key;
-  gnutls_datum_t cert;
-
-  if (NULL != daemon->https_mem_trust) 
-    {
-      cert.data = (unsigned char *) daemon->https_mem_trust;
-      cert.size = strlen (daemon->https_mem_trust);
-      if (gnutls_certificate_set_x509_trust_mem (daemon->x509_cred, &cert,
-                                                GNUTLS_X509_FMT_PEM) < 0) 
-       {
-#if HAVE_MESSAGES
-         MHD_DLOG(daemon,
-                  "Bad trust certificate format\n");
-#endif
-         return -1;
-       }
-    }
-  
-  /* certificate & key loaded from memory */
-  if ( (NULL != daemon->https_mem_cert) && 
-       (NULL != daemon->https_mem_key) )
-    {
-      key.data = (unsigned char *) daemon->https_mem_key;
-      key.size = strlen (daemon->https_mem_key);
-      cert.data = (unsigned char *) daemon->https_mem_cert;
-      cert.size = strlen (daemon->https_mem_cert);
-
-      return gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
-                                                 &cert, &key,
-                                                 GNUTLS_X509_FMT_PEM);
-    }
-#if HAVE_MESSAGES
-  MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
-#endif
-  return -1;
-}
-
-
-/**
- * Initialize security aspects of the HTTPS daemon
- *
- * @param daemon handle to daemon to initialize
- * @return 0 on success
- */
-static int
-MHD_TLS_init (struct MHD_Daemon *daemon)
-{
-  switch (daemon->cred_type)
-    {
-    case GNUTLS_CRD_CERTIFICATE:
-      if (0 !=
-          gnutls_certificate_allocate_credentials (&daemon->x509_cred))
-        return GNUTLS_E_MEMORY_ERROR;
-      return MHD_init_daemon_certificate (daemon);
-    default:
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-                "Error: invalid credentials type %d specified.\n",
-                daemon->cred_type);
-#endif
-      return -1;
-    }
-}
-#endif
-
-
-/**
- * Obtain the select sets for this daemon.
- *
- * @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 max_fd increased to largest FD added (if larger
- *               than existing value); can be NULL
- * @return MHD_YES on success, MHD_NO if this
- *         daemon was not started with the right
- *         options for this call.
- */
-int
-MHD_get_fdset (struct MHD_Daemon *daemon,
-               fd_set *read_fd_set,
-               fd_set *write_fd_set, 
-              fd_set *except_fd_set,
-              int *max_fd)
-{
-  struct MHD_Connection *pos;
-  int fd;
-
-  if ( (NULL == daemon) 
-       || (NULL == read_fd_set) 
-       || (NULL == write_fd_set)
-       || (NULL == except_fd_set) 
-       || (NULL == max_fd)
-       || (MHD_YES == daemon->shutdown)
-       || (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
-       || (0 != (daemon->options & MHD_USE_POLL)))
-    return MHD_NO;
-  fd = daemon->socket_fd;
-  if (-1 != fd)
-  {
-    FD_SET (fd, read_fd_set);
-    /* update max file descriptor */
-    if ((*max_fd) < fd) 
-      *max_fd = fd;
-  }
-  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
-    if (MHD_YES != MHD_connection_get_fdset (pos,
-                                            read_fd_set,
-                                            write_fd_set,
-                                            except_fd_set, max_fd))
-      return MHD_NO;    
-#if DEBUG_CONNECT
-  MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
-#endif
-  return MHD_YES;
-}
-
-
-/**
- * Main function of the thread that handles an individual
- * connection when MHD_USE_THREAD_PER_CONNECTION is set.
- * 
- * @param data the 'struct MHD_Connection' this thread will handle
- * @return always NULL
- */
-static void *
-MHD_handle_connection (void *data)
-{
-  struct MHD_Connection *con = data;
-  int num_ready;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  struct timeval tv;
-  struct timeval *tvp;
-  unsigned int timeout;
-  time_t now;
-#ifdef HAVE_POLL_H
-  struct MHD_Pollfd mp;
-  struct pollfd p[1];
-#endif
-
-  timeout = con->daemon->connection_timeout;
-  while ( (MHD_YES != con->daemon->shutdown) && 
-         (MHD_CONNECTION_CLOSED != con->state) ) 
-    {
-      tvp = NULL;
-      if (timeout > 0)
-       {
-         now = MHD_monotonic_time();
-         if (now - con->last_activity > timeout)
-           tv.tv_sec = 0;
-         else
-           tv.tv_sec = timeout - (now - con->last_activity);
-         tv.tv_usec = 0;
-         tvp = &tv;
-       }
-      if ( (MHD_CONNECTION_NORMAL_BODY_UNREADY == con->state) ||
-          (MHD_CONNECTION_CHUNKED_BODY_UNREADY == con->state) )
-       {
-         /* do not block (we're waiting for our callback to succeed) */
-         tv.tv_sec = 0;
-         tv.tv_usec = 0;
-         tvp = &tv;
-       }
-#if HTTPS_SUPPORT
-      if (MHD_YES == con->tls_read_ready)
-       {
-         /* do not block (more data may be inside of TLS buffers waiting for 
us) */
-         tv.tv_sec = 0;
-         tv.tv_usec = 0;
-         tvp = &tv;
-       }
-#endif
-      if (0 == (con->daemon->options & MHD_USE_POLL))
-       {
-         /* use select */
-         FD_ZERO (&rs);
-         FD_ZERO (&ws);
-         FD_ZERO (&es);
-         max = 0;
-         MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
-         num_ready = SELECT (max + 1, &rs, &ws, &es, tvp);
-         if (num_ready < 0) 
-           {
-             if (EINTR == errno)
-               continue;
-#if HAVE_MESSAGES
-             MHD_DLOG (con->daemon,
-                       "Error during select (%d): `%s'\n", 
-                       max,
-                       STRERROR (errno));
-#endif
-             break;
-           }
-         /* call appropriate connection handler if necessary */
-         if ( (FD_ISSET (con->socket_fd, &rs))
-#if HTTPS_SUPPORT
-                  || (MHD_YES == con->tls_read_ready) 
-#endif
-              )
-           con->read_handler (con);
-         if (FD_ISSET (con->socket_fd, &ws))
-           con->write_handler (con);
-         if (MHD_NO == con->idle_handler (con))
-           goto exit;
-       }
-#ifdef HAVE_POLL_H
-      else
-       {
-         /* use poll */
-         memset(&mp, 0, sizeof (struct MHD_Pollfd));
-         MHD_connection_get_pollfd(con, &mp);
-         memset(&p, 0, sizeof (p));
-         p[0].fd = mp.fd;
-         if (mp.events & MHD_POLL_ACTION_IN) 
-           p[0].events |= POLLIN;        
-         if (mp.events & MHD_POLL_ACTION_OUT) 
-           p[0].events |= POLLOUT;
-         if (poll (p, 
-                   1, 
-                   (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0)
-           {
-             if (EINTR == errno)
-               continue;
-#if HAVE_MESSAGES
-             MHD_DLOG (con->daemon, "Error during poll: `%s'\n", 
-                       STRERROR (errno));
-#endif
-             break;
-           }
-         if ( (0 != (p[0].revents & POLLIN)) 
-#if HTTPS_SUPPORT
-              || (MHD_YES == con->tls_read_ready) 
-#endif
-              )
-           con->read_handler (con);        
-         if (0 != (p[0].revents & POLLOUT)) 
-           con->write_handler (con);        
-         if (0 != (p[0].revents & (POLLERR | POLLHUP))) 
-           MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR);      
-         if (MHD_NO == con->idle_handler (con))
-           goto exit;
-       }
-#endif
-    }
-  if (MHD_CONNECTION_IN_CLEANUP != con->state)
-    {
-#if DEBUG_CLOSE
-#if HAVE_MESSAGES
-      MHD_DLOG (con->daemon,
-                "Processing thread terminating, closing connection\n");
-#endif
-#endif
-      if (MHD_CONNECTION_CLOSED != con->state)
-       MHD_connection_close (con, 
-                             MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
-      con->idle_handler (con);
-    }
-exit:
-  if (NULL != con->response)
-    {
-      MHD_destroy_response (con->response);
-      con->response = NULL;
-    }
-  return NULL;
-}
-
-
-/**
- * Callback for receiving data from the socket.
- *
- * @param conn the MHD connection structure
- * @param other where to write received data to
- * @param i maximum size of other (in bytes)
- * @return number of bytes actually received
- */
-static ssize_t
-recv_param_adapter (struct MHD_Connection *connection,
-                   void *other, 
-                   size_t i)
-{
-  if ( (-1 == connection->socket_fd) ||
-       (MHD_CONNECTION_CLOSED == connection->state) )
-    {
-      errno = ENOTCONN;
-      return -1;
-    }
-  if (0 != (connection->daemon->options & MHD_USE_SSL))
-    return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
-  return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
-}
-
-
-/**
- * Callback for writing data to the socket.
- *
- * @param conn the MHD connection structure
- * @param other data to write
- * @param i number of bytes to write
- * @return actual number of bytes written
- */
-static ssize_t
-send_param_adapter (struct MHD_Connection *connection,
-                    const void *other,
-                   size_t i)
-{
-#if LINUX
-  int fd;
-  off_t offset;
-  off_t left;
-  ssize_t ret;
-#endif
-  if ( (-1 == connection->socket_fd) ||
-       (MHD_CONNECTION_CLOSED == connection->state) )
-    {
-      errno = ENOTCONN;
-      return -1;
-    }
-  if (0 != (connection->daemon->options & MHD_USE_SSL))
-    return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
-#if LINUX
-  if ( (connection->write_buffer_append_offset ==
-       connection->write_buffer_send_offset) &&
-       (NULL != connection->response) &&
-       (-1 != (fd = connection->response->fd)) )
-    {
-      /* can use sendfile */
-      offset = (off_t) connection->response_write_position + 
connection->response->fd_off;
-      left = connection->response->total_size - 
connection->response_write_position;
-      if (left > SSIZE_MAX)
-       left = SSIZE_MAX; /* cap at return value limit */
-      if (-1 != (ret = sendfile (connection->socket_fd, 
-                                fd,
-                                &offset,
-                                (size_t) left)))
-       return ret;
-      if ( (EINTR == errno) || (EAGAIN == errno) )
-       return 0;
-      if ( (EINVAL == errno) || (EBADF == errno) )
-       return -1; 
-      /* None of the 'usual' sendfile errors occurred, so we should try
-        to fall back to 'SEND'; see also this thread for info on
-        odd libc/Linux behavior with sendfile:
-        http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html 
*/
-    }
-#endif
-  return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
-}
-
-
-/**
- * Signature of main function for a thread.
- */
-typedef void *(*ThreadStartRoutine)(void *cls);
-
-
-/**
- * Create a thread and set the attributes according to our options.
- * 
- * @param thread handle to initialize
- * @param daemon daemon with options
- * @param start_routine main function of thread
- * @param arg argument for start_routine
- * @return 0 on success
- */
-static int
-create_thread (pthread_t * thread,
-              const struct MHD_Daemon *daemon,
-              ThreadStartRoutine start_routine,
-              void *arg)
-{
-  pthread_attr_t attr;
-  pthread_attr_t *pattr;
-  int ret;
-  
-  if (0 != daemon->thread_stack_size) 
-    {
-      if (0 != (ret = pthread_attr_init (&attr))) 
-       goto ERR;
-      if (0 != (ret = pthread_attr_setstacksize (&attr, 
daemon->thread_stack_size)))
-       {
-         pthread_attr_destroy (&attr);
-         goto ERR;
-       }
-      pattr = &attr;
-    }
-  else
-    {
-      pattr = NULL;
-    }
-  ret = pthread_create (thread, pattr,
-                       start_routine, arg);
-  if (0 != daemon->thread_stack_size) 
-    pthread_attr_destroy (&attr);
-  return ret;
- ERR:
-#if HAVE_MESSAGES
-  MHD_DLOG (daemon,
-           "Failed to set thread stack size\n");
-#endif
-  errno = EINVAL;
-  return ret;
-}
-
-
-/**
- * Add another client connection to the set of connections 
- * managed by MHD.  This API is usually not needed (since
- * MHD will accept inbound connections on the server socket).
- * Use this API in special cases, for example if your HTTP
- * server is behind NAT and needs to connect out to the 
- * HTTP client.
- *
- * The given client socket will be managed (and closed!) by MHD after
- * this call and must no longer be used directly by the application
- * afterwards.
- *
- * Per-IP connection limits are ignored when using this API.
- *
- * @param daemon daemon that manages the connection
- * @param client_socket socket to manage (MHD will expect
- *        to receive an HTTP request from this socket next).
- * @param addr IP address of the client
- * @param addrlen number of bytes in addr
- * @return MHD_YES on success, MHD_NO if this daemon could
- *        not handle the connection (i.e. malloc failed, etc).
- *        The socket will be closed in any case.
- */
-int 
-MHD_add_connection (struct MHD_Daemon *daemon, 
-                   int client_socket,
-                   const struct sockaddr *addr,
-                   socklen_t addrlen)
-{
-  struct MHD_Connection *connection;
-  int res_thread_create;
-#if OSX
-  static int on = 1;
-#endif
-
-#ifndef WINDOWS
-  if ( (client_socket >= FD_SETSIZE) &&
-       (0 == (daemon->options & MHD_USE_POLL)) )
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-               "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
-               client_socket,
-               FD_SETSIZE);
-#endif
-      SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
-      return MHD_NO;
-    }
-#endif
-
-
-#if HAVE_MESSAGES
-#if DEBUG_CONNECT
-  MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
-#endif
-#endif
-  if ( (0 == daemon->max_connections) ||
-       (MHD_NO == MHD_ip_limit_add (daemon, addr, addrlen)) )
-    {
-      /* above connection limit - reject */
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-                "Server reached connection limit (closing inbound 
connection)\n");
-#endif
-      SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
-      return MHD_NO;
-    }
-
-  /* apply connection acceptance policy if present */
-  if ( (NULL != daemon->apc) && 
-       (MHD_NO == daemon->apc (daemon->apc_cls, 
-                              addr, addrlen)) )
-    {
-#if DEBUG_CLOSE
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, "Connection rejected, closing connection\n");
-#endif
-#endif
-      SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
-      MHD_ip_limit_del (daemon, addr, addrlen);
-      return MHD_YES;
-    }
-
-#if OSX
-#ifdef SOL_SOCKET
-#ifdef SO_NOSIGPIPE
-  setsockopt (client_socket, 
-             SOL_SOCKET, SO_NOSIGPIPE, 
-             &on, sizeof (on));
-#endif
-#endif
-#endif
-
-  if (NULL == (connection = malloc (sizeof (struct MHD_Connection))))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, 
-               "Error allocating memory: %s\n", 
-               STRERROR (errno));
-#endif
-      SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
-      MHD_ip_limit_del (daemon, addr, addrlen);
-      return MHD_NO;
-    }
-  memset (connection, 0, sizeof (struct MHD_Connection));
-  connection->connection_timeout = daemon->connection_timeout;
-  connection->pool = NULL;
-  if (NULL == (connection->addr = malloc (addrlen)))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, 
-               "Error allocating memory: %s\n", 
-               STRERROR (errno));
-#endif
-      SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
-      MHD_ip_limit_del (daemon, addr, addrlen);
-      free (connection);
-      return MHD_NO;
-    }
-  memcpy (connection->addr, addr, addrlen);
-  connection->addr_len = addrlen;
-  connection->socket_fd = client_socket;
-  connection->daemon = daemon;
-  connection->last_activity = MHD_monotonic_time();
-
-  /* set default connection handlers  */
-  MHD_set_http_callbacks_ (connection);
-  connection->recv_cls = &recv_param_adapter;
-  connection->send_cls = &send_param_adapter;
-  /* non-blocking sockets are required on most systems and for GNUtls;
-     however, they somehow cause serious problems on CYGWIN (#1824) */
-#ifdef CYGWIN
-  if (0 != (daemon->options & MHD_USE_SSL))
-#endif
-  {
-    /* make socket non-blocking */
-#ifndef MINGW
-    int flags = fcntl (connection->socket_fd, F_GETFL);
-    if ( (-1 == flags) ||
-        (0 != fcntl (connection->socket_fd, F_SETFL, flags | O_NONBLOCK)) )
-      {
-#if HAVE_MESSAGES
-       MHD_DLOG (daemon,
-                 "Failed to make socket %d non-blocking: %s\n", 
-                 connection->socket_fd,
-                 STRERROR (errno));
-#endif
-      }
-#else
-    unsigned long flags = 1;
-    if (0 != ioctlsocket (connection->socket_fd, FIONBIO, &flags))
-      {
-#if HAVE_MESSAGES
-       MHD_DLOG (daemon, 
-                 "Failed to make socket non-blocking: %s\n", 
-                 STRERROR (errno));
-#endif
-      }
-#endif
-  }
-
-#if HTTPS_SUPPORT
-  if (0 != (daemon->options & MHD_USE_SSL))
-    {
-      connection->recv_cls = &recv_tls_adapter;
-      connection->send_cls = &send_tls_adapter;
-      connection->state = MHD_TLS_CONNECTION_INIT;
-      MHD_set_https_callbacks (connection);
-      gnutls_init (&connection->tls_session, GNUTLS_SERVER);
-      gnutls_priority_set (connection->tls_session,
-                          daemon->priority_cache);
-      switch (daemon->cred_type)
-        {
-          /* set needed credentials for certificate authentication. */
-        case GNUTLS_CRD_CERTIFICATE:
-          gnutls_credentials_set (connection->tls_session,
-                                 GNUTLS_CRD_CERTIFICATE,
-                                 daemon->x509_cred);
-          break;
-        default:
-#if HAVE_MESSAGES
-          MHD_DLOG (connection->daemon,
-                    "Failed to setup TLS credentials: unknown credential type 
%d\n",
-                    daemon->cred_type);
-#endif
-          SHUTDOWN (client_socket, SHUT_RDWR);
-          CLOSE (client_socket);
-          MHD_ip_limit_del (daemon, addr, addrlen);
-          free (connection->addr);
-          free (connection);
-          MHD_PANIC ("Unknown credential type");
-         return MHD_NO;
-        }
-      gnutls_transport_set_ptr (connection->tls_session,
-                               (gnutls_transport_ptr_t) connection);
-      gnutls_transport_set_pull_function (connection->tls_session,
-                                         (gnutls_pull_func) &
-                                               recv_param_adapter);
-      gnutls_transport_set_push_function (connection->tls_session,
-                                         (gnutls_push_func) &
-                                               send_param_adapter);
-
-      if (daemon->https_mem_trust){
-      gnutls_certificate_server_set_request(connection->tls_session, 
GNUTLS_CERT_REQUEST);
-      }
-    }
-#endif
-
-  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to acquire cleanup mutex\n");
-    }
-  DLL_insert (daemon->connections_head,
-             daemon->connections_tail,
-             connection);
-  if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to release cleanup mutex\n");
-    }
-
-  /* attempt to create handler thread */
-  if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
-    {
-      res_thread_create = create_thread (&connection->pid, daemon,
-                                        &MHD_handle_connection, connection);
-      if (0 != res_thread_create)
-        {
-#if HAVE_MESSAGES
-          MHD_DLOG (daemon, "Failed to create a thread: %s\n",
-                    STRERROR (res_thread_create));
-#endif
-          SHUTDOWN (client_socket, SHUT_RDWR);
-          CLOSE (client_socket);
-          MHD_ip_limit_del (daemon, addr, addrlen);
-         if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to acquire cleanup mutex\n");
-           }
-         DLL_remove (daemon->connections_head,
-                     daemon->connections_tail,
-                     connection);
-         if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to release cleanup mutex\n");
-           }
-          free (connection->addr);
-          free (connection);
-          return MHD_NO;
-        }
-    }
-  daemon->max_connections--;
-  return MHD_YES;  
-}
-
-
-/**
- * Accept an incoming connection and create the MHD_Connection object for
- * it.  This function also enforces policy by way of checking with the
- * accept policy callback.
- * 
- * @param daemon handle with the listen socket
- * @return MHD_YES on success
- */
-static int
-MHD_accept_connection (struct MHD_Daemon *daemon)
-{
-#if HAVE_INET6
-  struct sockaddr_in6 addrstorage;
-#else
-  struct sockaddr_in addrstorage;
-#endif
-  struct sockaddr *addr = (struct sockaddr *) &addrstorage;
-  socklen_t addrlen;
-  int s;
-  int flags;
-  int need_fcntl;
-  int fd;
-
-  addrlen = sizeof (addrstorage);
-  memset (addr, 0, sizeof (addrstorage));
-  if (-1 == (fd = daemon->socket_fd))
-    return MHD_NO;
-#if HAVE_ACCEPT4
-  s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC);
-  need_fcntl = MHD_NO;
-#else
-  s = -1;
-  need_fcntl = MHD_YES;
-#endif
-  if (-1 == s)
-  {
-    s = ACCEPT (fd, addr, &addrlen);
-    need_fcntl = MHD_YES;
-  }
-  if ((-1 == s) || (addrlen <= 0))
-    {
-#if HAVE_MESSAGES
-      /* This could be a common occurance with multiple worker threads */
-      if ((EAGAIN != errno) && (EWOULDBLOCK != errno))
-        MHD_DLOG (daemon, 
-                 "Error accepting connection: %s\n", 
-                 STRERROR (errno));
-#endif
-      if (-1 != s)
-        {
-          SHUTDOWN (s, SHUT_RDWR);
-          CLOSE (s);
-          /* just in case */
-        }
-      return MHD_NO;
-    }
-  if (MHD_YES == need_fcntl)
-  {
-    /* make socket non-inheritable */
-#ifdef WINDOWS
-    DWORD dwFlags;
-    if (!GetHandleInformation ((HANDLE) s, &dwFlags) ||
-        ((dwFlags != dwFlags & ~HANDLE_FLAG_INHERIT) &&
-        !SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0)))
-      {
-#if HAVE_MESSAGES
-        SetErrnoFromWinError (GetLastError ());
-       MHD_DLOG (daemon,
-                 "Failed to make socket non-inheritable: %s\n", 
-                 STRERROR (errno));
-#endif
-      }
-#else
-    flags = fcntl (s, F_GETFD);
-    if ( ( (-1 == flags) ||
-          ( (flags != (flags | FD_CLOEXEC)) &&
-            (0 != fcntl (s, F_SETFD, flags | FD_CLOEXEC)) ) ) )
-      {
-#if HAVE_MESSAGES
-       MHD_DLOG (daemon,
-                 "Failed to make socket non-inheritable: %s\n", 
-                 STRERROR (errno));
-#endif
-      }
-#endif
-  }
-#if HAVE_MESSAGES
-#if DEBUG_CONNECT
-  MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
-#endif
-#endif
-  return MHD_add_connection (daemon, s,
-                            addr, addrlen);
-}
-
-
-/**
- * Free resources associated with all closed connections.
- * (destroy responses, free buffers, etc.).  All closed
- * connections are kept in the "cleanup" doubly-linked list.
- *
- * @param daemon daemon to clean up
- */
-static void
-MHD_cleanup_connections (struct MHD_Daemon *daemon)
-{
-  struct MHD_Connection *pos;
-  void *unused;
-  int rc;
-
-  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to acquire cleanup mutex\n");
-    }
-  while (NULL != (pos = daemon->cleanup_head))
-    {
-      DLL_remove (daemon->cleanup_head,
-                 daemon->cleanup_tail,
-                 pos);
-      if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
-          (MHD_NO == pos->thread_joined) )
-       { 
-         if (0 != (rc = pthread_join (pos->pid, &unused)))
-           {
-             MHD_PANIC ("Failed to join a thread\n");
-           }
-       }
-      MHD_pool_destroy (pos->pool);
-#if HTTPS_SUPPORT
-      if (pos->tls_session != NULL)
-       gnutls_deinit (pos->tls_session);
-#endif
-      MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
-      if (NULL != pos->response)
-       {
-         MHD_destroy_response (pos->response);
-         pos->response = NULL;
-       }
-      if (-1 != pos->socket_fd)
-       CLOSE (pos->socket_fd);
-      if (NULL != pos->addr)
-       free (pos->addr);
-      free (pos);
-      daemon->max_connections++;
-    }
-  if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to release cleanup mutex\n");
-    }
-}
-
-
-/**
- * Obtain timeout value for select for this daemon
- * (only needed if connection timeout is used).  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 MHD_YES on success, MHD_NO if timeouts are
- *        not used (or no connections exist that would
- *        necessiate the use of a timeout right now).
- */
-int
-MHD_get_timeout (struct MHD_Daemon *daemon,
-                MHD_UNSIGNED_LONG_LONG *timeout)
-{
-  time_t earliest_deadline;
-  time_t now;
-  struct MHD_Connection *pos;
-  int have_timeout;
-
-  if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, "Illegal call to MHD_get_timeout\n");
-#endif  
-      return MHD_NO;
-    }
-  have_timeout = MHD_NO;
-  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
-    {
-#if HTTPS_SUPPORT
-      if (MHD_YES == pos->tls_read_ready)
-       {
-         earliest_deadline = 0;
-         have_timeout = MHD_YES;
-         break;
-       }
-#endif
-      if (0 != pos->connection_timeout) 
-       {
-         if ( (! have_timeout) ||
-              (earliest_deadline > pos->last_activity + 
pos->connection_timeout) )
-           earliest_deadline = pos->last_activity + pos->connection_timeout;
-#if HTTPS_SUPPORT
-         if (  (0 != (daemon->options & MHD_USE_SSL)) &&
-               (0 != gnutls_record_check_pending (pos->tls_session)) )
-           earliest_deadline = 0;
-#endif
-         have_timeout = MHD_YES;
-       }
-    }
-  if (MHD_NO == have_timeout)
-    return MHD_NO;
-  now = MHD_monotonic_time();
-  if (earliest_deadline < now)
-    *timeout = 0;
-  else
-    *timeout = 1000 * (1 + earliest_deadline - now);
-  return MHD_YES;
-}
-
-
-/**
- * Run webserver operations. This method should be called by clients
- * in combination with MHD_get_fdset if the client-controlled select
- * method is used.
- *
- * You can use this function instead of "MHD_run" if you called
- * 'select' on the result from "MHD_get_fdset".  File descriptors in
- * the sets that are not controlled by MHD will be ignored.  Calling
- * this function instead of "MHD_run" is more efficient as MHD will
- * not have to call 'select' again to determine which operations are
- * ready.
- *
- * @param daemon daemon to run select loop for
- * @param read_fd_set read set
- * @param write_fd_set write set
- * @param except_fd_set except set (not used, can be NULL)
- * @return MHD_NO on serious errors, MHD_YES on success
- */
-int
-MHD_run_from_select (struct MHD_Daemon *daemon, 
-                    const fd_set *read_fd_set,
-                    const fd_set *write_fd_set,
-                    const fd_set *except_fd_set)
-{
-  int ds;
-  int tmp;
-  struct MHD_Connection *pos;
-  struct MHD_Connection *next;
-
-  /* select connection thread handling type */
-  if ( (-1 != (ds = daemon->socket_fd)) &&
-       (FD_ISSET (ds, read_fd_set)) )
-    MHD_accept_connection (daemon);
-  /* drain signaling pipe to avoid spinning select */
-  if ( (-1 != daemon->wpipe[0]) &&
-       (FD_ISSET (daemon->wpipe[0], read_fd_set)) )
-    (void) read (daemon->wpipe[0], &tmp, sizeof (tmp));
-
-  if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
-    {
-      /* do not have a thread per connection, process all connections now */
-      next = daemon->connections_head;
-      while (NULL != (pos = next))
-        {
-         next = pos->next;
-          ds = pos->socket_fd;
-          if (ds != -1)
-            {
-              if ( (FD_ISSET (ds, read_fd_set))
-#if HTTPS_SUPPORT
-                  || (MHD_YES == pos->tls_read_ready) 
-#endif
-                  )
-                pos->read_handler (pos);
-              if (FD_ISSET (ds, write_fd_set))
-                pos->write_handler (pos);
-             pos->idle_handler (pos);
-            }
-        }
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Main internal select call.  Will compute select sets, call 'select'
- * and then MHD_run_from_select with the result.
- *
- * @param daemon daemon to run select loop for
- * @param may_block YES if blocking, NO if non-blocking
- * @return MHD_NO on serious errors, MHD_YES on success
- */
-static int
-MHD_select (struct MHD_Daemon *daemon, 
-           int may_block)
-{
-  int num_ready;
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  int max;
-  struct timeval timeout;
-  struct timeval *tv;
-  MHD_UNSIGNED_LONG_LONG ltimeout;
-
-  timeout.tv_sec = 0;
-  timeout.tv_usec = 0;
-  if (MHD_YES == daemon->shutdown)
-    return MHD_NO;
-  FD_ZERO (&rs);
-  FD_ZERO (&ws);
-  FD_ZERO (&es);
-  max = -1;
-  if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
-    {
-      /* single-threaded, go over everything */
-      if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
-        return MHD_NO;
-
-      /* If we're at the connection limit, no need to
-         accept new connections. */
-      if ( (0 == daemon->max_connections) && 
-          (-1 != daemon->socket_fd) )
-        FD_CLR (daemon->socket_fd, &rs);
-    }
-  else
-    {
-      /* accept only, have one thread per connection */
-      if (-1 != daemon->socket_fd) 
-       {
-         max = daemon->socket_fd;
-         FD_SET (daemon->socket_fd, &rs);
-       }
-    }
-  if (-1 != daemon->wpipe[0])
-    {
-      FD_SET (daemon->wpipe[0], &rs);
-      /* update max file descriptor */
-      if (max < daemon->wpipe[0])
-       max = daemon->wpipe[0];
-    }
-
-  tv = NULL;
-  if (MHD_NO == may_block)
-    {
-      timeout.tv_usec = 0;
-      timeout.tv_sec = 0;
-      tv = &timeout;
-    }
-  else if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
-           (MHD_YES == MHD_get_timeout (daemon, &ltimeout)) )
-    {
-      /* ltimeout is in ms */
-      timeout.tv_usec = (ltimeout % 1000) * 1000;
-      timeout.tv_sec = ltimeout / 1000;
-      tv = &timeout;
-    }
-  if (-1 == max)
-    return MHD_YES;
-  num_ready = SELECT (max + 1, &rs, &ws, &es, tv);
-  if (MHD_YES == daemon->shutdown)
-    return MHD_NO;
-  if (num_ready < 0)
-    {
-      if (EINTR == errno)
-        return MHD_YES;
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno));
-#endif
-      return MHD_NO;
-    }
-  return MHD_run_from_select (daemon, &rs, &ws, &es);
-}
-
-
-#ifdef HAVE_POLL_H
-/**
- * Process all of our connections and possibly the server
- * socket using 'poll'.
- *
- * @param daemon daemon to run poll loop for
- * @param may_block YES if blocking, NO if non-blocking
- * @return MHD_NO on serious errors, MHD_YES on success
- */
-static int
-MHD_poll_all (struct MHD_Daemon *daemon,
-             int may_block)
-{
-  unsigned int num_connections;
-  struct MHD_Connection *pos;
-  struct MHD_Connection *next;
-
-  /* count number of connections and thus determine poll set size */
-  num_connections = 0;
-  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
-    num_connections++;
-
-  {
-    struct pollfd p[2 + num_connections];
-    struct MHD_Pollfd mp;
-    MHD_UNSIGNED_LONG_LONG ltimeout;
-    unsigned int i;
-    int timeout;
-    unsigned int poll_server;
-    int poll_listen;
-    
-    memset (p, 0, sizeof (p));
-    poll_server = 0;
-    poll_listen = -1;
-    if ( (-1 != daemon->socket_fd) &&
-        (0 != daemon->max_connections) )
-      {
-       /* only listen if we are not at the connection limit */
-       p[poll_server].fd = daemon->socket_fd;
-       p[poll_server].events = POLLIN;
-       p[poll_server].revents = 0;
-       poll_listen = (int) poll_server;
-       poll_server++;
-      }
-    if (-1 != daemon->wpipe[0]) 
-      {
-       p[poll_server].fd = daemon->wpipe[0];
-       p[poll_server].events = POLLIN;
-       p[poll_server].revents = 0;
-       poll_server++;
-      }
-    if (may_block == MHD_NO)
-      timeout = 0;
-    else if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
-             (MHD_YES != MHD_get_timeout (daemon, &ltimeout)) )
-      timeout = -1;
-    else
-      timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout;
-    
-    i = 0;
-    for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
-      {
-       memset(&mp, 0, sizeof (struct MHD_Pollfd));
-       MHD_connection_get_pollfd (pos, &mp);
-       p[poll_server+i].fd = mp.fd;
-       if (mp.events & MHD_POLL_ACTION_IN) 
-         p[poll_server+i].events |= POLLIN;        
-       if (mp.events & MHD_POLL_ACTION_OUT) 
-         p[poll_server+i].events |= POLLOUT;
-       i++;
-      }
-    if (0 == poll_server + num_connections)
-      return MHD_YES;
-    if (poll (p, poll_server + num_connections, timeout) < 0) 
-      {
-       if (EINTR == errno)
-         return MHD_YES;
-#if HAVE_MESSAGES
-       MHD_DLOG (daemon, 
-                 "poll failed: %s\n", 
-                 STRERROR (errno));
-#endif
-       return MHD_NO;
-      }
-    /* handle shutdown */
-    if (MHD_YES == daemon->shutdown)
-      return MHD_NO;  
-    i = 0;
-    next = daemon->connections_head;
-    while (NULL != (pos = next))
-      {
-       next = pos->next;
-       /* first, sanity checks */
-       if (i >= num_connections)
-         break; /* connection list changed somehow, retry later ... */
-       MHD_connection_get_pollfd (pos, &mp);
-       if (p[poll_server+i].fd != mp.fd)
-         break; /* fd mismatch, something else happened, retry later ... */
-
-       /* normal handling */
-       if (0 != (p[poll_server+i].revents & POLLIN)) 
-         pos->read_handler (pos);
-       if (0 != (p[poll_server+i].revents & POLLOUT)) 
-         pos->write_handler (pos);     
-       pos->idle_handler (pos);
-       i++;
-      }
-    if ( (-1 != poll_listen) &&
-        (0 != (p[poll_listen].revents & POLLIN)) )
-      MHD_accept_connection (daemon);
-  }
-  return MHD_YES;
-}
-
-
-/**
- * Process only the listen socket using 'poll'.
- *
- * @param daemon daemon to run poll loop for
- * @param may_block YES if blocking, NO if non-blocking
- * @return MHD_NO on serious errors, MHD_YES on success
- */
-static int
-MHD_poll_listen_socket (struct MHD_Daemon *daemon,
-                       int may_block)
-{
-  struct pollfd p[2];
-  int timeout;
-  unsigned int poll_count;
-  int poll_listen;
-    
-  memset (&p, 0, sizeof (p));
-  poll_count = 0;
-  poll_listen = -1;
-  if (-1 != daemon->socket_fd)
-    {
-      p[poll_count].fd = daemon->socket_fd;
-      p[poll_count].events = POLLIN;
-      p[poll_count].revents = 0;
-      poll_listen = poll_count;
-      poll_count++;
-    }
-  if (-1 != daemon->wpipe[0])
-    {
-      p[poll_count].fd = daemon->wpipe[0];
-      p[poll_count].events = POLLIN;
-      p[poll_count].revents = 0;
-      poll_count++;
-    }
-  if (MHD_NO == may_block)
-    timeout = 0;
-  else
-    timeout = -1;
-  if (0 == poll_count)
-    return MHD_YES;
-  if (poll (p, poll_count, timeout) < 0)
-    {
-      if (EINTR == errno)
-       return MHD_YES;
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno));
-#endif
-      return MHD_NO;
-    }
-  /* handle shutdown */
-  if (MHD_YES == daemon->shutdown)
-    return MHD_NO;  
-  if ( (-1 != poll_listen) &&
-       (0 != (p[poll_listen].revents & POLLIN)) )
-    MHD_accept_connection (daemon);  
-  return MHD_YES;
-}
-#endif
-
-
-/**
- * Do 'poll'-based processing.
- *
- * @param daemon daemon to run poll loop for
- * @param may_block YES if blocking, NO if non-blocking
- * @return MHD_NO on serious errors, MHD_YES on success
- */
-static int
-MHD_poll (struct MHD_Daemon *daemon,
-         int may_block)
-{
-#ifdef HAVE_POLL_H
-  if (MHD_YES == daemon->shutdown)
-    return MHD_NO;
-  if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
-    return MHD_poll_all (daemon, may_block);
-  else
-    return MHD_poll_listen_socket (daemon, may_block);
-#else
-  return MHD_NO;
-#endif
-}
-
-
-/**
- * Run webserver operations (without blocking unless
- * in client callbacks).  This method should be called
- * by clients in combination with MHD_get_fdset
- * if the client-controlled select method is used.
- *
- * This function will work for external 'poll' and 'select' mode.
- * However, if using external 'select' mode, you may want to
- * instead use 'MHD_run_from_select', as it is more efficient.
- *
- * @return MHD_YES on success, MHD_NO if this
- *         daemon was not started with the right
- *         options for this call.
- */
-int
-MHD_run (struct MHD_Daemon *daemon)
-{
-  if ( (MHD_YES == daemon->shutdown) || 
-       (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
-       (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) )
-    return MHD_NO;
-  if (0 == (daemon->options & MHD_USE_POLL)) 
-    MHD_select (daemon, MHD_NO);    
-  else    
-    MHD_poll (daemon, MHD_NO);    
-  MHD_cleanup_connections (daemon);
-  return MHD_YES;
-}
-
-
-/**
- * Thread that runs the select loop until the daemon
- * is explicitly shut down.
- *
- * @param cls 'struct MHD_Deamon' to run select loop in a thread for
- * @return always NULL (on shutdown)
- */
-static void *
-MHD_select_thread (void *cls)
-{
-  struct MHD_Daemon *daemon = cls;
-
-  while (MHD_YES != daemon->shutdown)
-    {
-      if (0 == (daemon->options & MHD_USE_POLL)) 
-       MHD_select (daemon, MHD_YES);
-      else 
-       MHD_poll (daemon, MHD_YES);      
-      MHD_cleanup_connections (daemon);
-    }
-  return NULL;
-}
-
-
-/**
- * Start a webserver on the given port.
- *
- * @param port port to bind to
- * @param apc callback to call to check which clients
- *        will be allowed to connect
- * @param apc_cls extra argument to apc
- * @param dh default handler for all URIs
- * @param dh_cls extra argument to dh
- * @return NULL on error, handle to daemon on success
- */
-struct MHD_Daemon *
-MHD_start_daemon (unsigned int options,
-                  uint16_t port,
-                  MHD_AcceptPolicyCallback apc,
-                  void *apc_cls,
-                  MHD_AccessHandlerCallback dh, void *dh_cls, ...)
-{
-  struct MHD_Daemon *daemon;
-  va_list ap;
-
-  va_start (ap, dh_cls);
-  daemon = MHD_start_daemon_va (options, port, apc, apc_cls, dh, dh_cls, ap);
-  va_end (ap);
-  return daemon;
-}
-
-
-/**
- * Stop accepting connections from the listening socket.  Allows
- * clients to continue processing, but stops accepting new
- * connections.  Note that the caller is responsible for closing the
- * returned socket; however, if MHD is run using threads (anything but
- * external select mode), it must not be closed until AFTER
- * "MHD_stop_daemon" has been called (as it is theoretically possible
- * that an existing thread is still using it).
- *
- * @param daemon daemon to stop accepting new connections for
- * @return old listen socket on success, -1 if the daemon was 
- *         already not listening anymore
- */
-int
-MHD_quiesce_daemon (struct MHD_Daemon *daemon)
-{
-  unsigned int i;
-  int ret;
-
-  ret = daemon->socket_fd;
-  if (NULL != daemon->worker_pool)
-    for (i = 0; i < daemon->worker_pool_size; i++)        
-      daemon->worker_pool[i].socket_fd = -1;    
-  daemon->socket_fd = -1;
-  return ret;
-}
-
-
-/**
- * Signature of the MHD custom logger function.
- *
- * @param cls closure
- * @param format format string
- * @param va arguments to the format string (fprintf-style)
- */
-typedef void (*VfprintfFunctionPointerType)(void *cls,
-                                           const char *format, 
-                                           va_list va);
-
-
-/**
- * Parse a list of options given as varargs.
- * 
- * @param daemon the daemon to initialize
- * @param servaddr where to store the server's listen address
- * @param ap the options
- * @return MHD_YES on success, MHD_NO on error
- */
-static int
-parse_options_va (struct MHD_Daemon *daemon,
-                 const struct sockaddr **servaddr,
-                 va_list ap);
-
-
-/**
- * Parse a list of options given as varargs.
- * 
- * @param daemon the daemon to initialize
- * @param servaddr where to store the server's listen address
- * @param ... the options
- * @return MHD_YES on success, MHD_NO on error
- */
-static int
-parse_options (struct MHD_Daemon *daemon,
-              const struct sockaddr **servaddr,
-              ...)
-{
-  va_list ap;
-  int ret;
-
-  va_start (ap, servaddr);
-  ret = parse_options_va (daemon, servaddr, ap);
-  va_end (ap);
-  return ret;
-}
-
-
-/**
- * Parse a list of options given as varargs.
- * 
- * @param daemon the daemon to initialize
- * @param servaddr where to store the server's listen address
- * @param ap the options
- * @return MHD_YES on success, MHD_NO on error
- */
-static int
-parse_options_va (struct MHD_Daemon *daemon,
-                 const struct sockaddr **servaddr,
-                 va_list ap)
-{
-  enum MHD_OPTION opt;
-  struct MHD_OptionItem *oa;
-  unsigned int i;
-#if HTTPS_SUPPORT
-  int ret;
-  const char *pstr;
-#endif
-  
-  while (MHD_OPTION_END != (opt = (enum MHD_OPTION) va_arg (ap, int)))
-    {
-      switch (opt)
-        {
-        case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
-          daemon->pool_size = va_arg (ap, size_t);
-          break;
-        case MHD_OPTION_CONNECTION_LIMIT:
-          daemon->max_connections = va_arg (ap, unsigned int);
-          break;
-        case MHD_OPTION_CONNECTION_TIMEOUT:
-          daemon->connection_timeout = va_arg (ap, unsigned int);
-          break;
-        case MHD_OPTION_NOTIFY_COMPLETED:
-          daemon->notify_completed =
-            va_arg (ap, MHD_RequestCompletedCallback);
-          daemon->notify_completed_cls = va_arg (ap, void *);
-          break;
-        case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
-          daemon->per_ip_connection_limit = va_arg (ap, unsigned int);
-          break;
-        case MHD_OPTION_SOCK_ADDR:
-          *servaddr = va_arg (ap, const struct sockaddr *);
-          break;
-        case MHD_OPTION_URI_LOG_CALLBACK:
-          daemon->uri_log_callback =
-            va_arg (ap, LogCallback);
-          daemon->uri_log_callback_cls = va_arg (ap, void *);
-          break;
-        case MHD_OPTION_THREAD_POOL_SIZE:
-          daemon->worker_pool_size = va_arg (ap, unsigned int);
-         if (daemon->worker_pool_size >= (SIZE_MAX / sizeof (struct 
MHD_Daemon)))
-           {
-#if HAVE_MESSAGES
-             MHD_DLOG (daemon,
-                       "Specified thread pool size (%u) too big\n",
-                       daemon->worker_pool_size);
-#endif
-             return MHD_NO;
-           }
-          break;
-#if HTTPS_SUPPORT
-        case MHD_OPTION_HTTPS_MEM_KEY:
-         if (0 != (daemon->options & MHD_USE_SSL))
-           daemon->https_mem_key = va_arg (ap, const char *);
-#if HAVE_MESSAGES
-         else
-           MHD_DLOG (daemon,
-                     "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not 
set\n",
-                     opt);       
-#endif
-          break;
-        case MHD_OPTION_HTTPS_MEM_CERT:
-         if (0 != (daemon->options & MHD_USE_SSL))
-           daemon->https_mem_cert = va_arg (ap, const char *);
-#if HAVE_MESSAGES
-         else
-           MHD_DLOG (daemon,
-                     "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not 
set\n",
-                     opt);       
-#endif
-          break;
-        case MHD_OPTION_HTTPS_MEM_TRUST:
-         if (0 != (daemon->options & MHD_USE_SSL))
-           daemon->https_mem_trust = va_arg (ap, const char *);
-#if HAVE_MESSAGES
-         else
-           MHD_DLOG (daemon,
-                     "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not 
set\n",
-                     opt);
-#endif
-          break;
-       case MHD_OPTION_HTTPS_CRED_TYPE:
-         daemon->cred_type = (gnutls_credentials_type_t) va_arg (ap, int);
-         break;
-        case MHD_OPTION_HTTPS_PRIORITIES:
-         if (0 != (daemon->options & MHD_USE_SSL))
-           {
-             gnutls_priority_deinit (daemon->priority_cache);
-             ret = gnutls_priority_init (&daemon->priority_cache,
-                                         pstr = va_arg (ap, const char*),
-                                         NULL);
-             if (ret != GNUTLS_E_SUCCESS)
-             {
-#if HAVE_MESSAGES
-               MHD_DLOG (daemon,
-                         "Setting priorities to `%s' failed: %s\n",
-                         pstr,
-                         gnutls_strerror (ret));
-#endif   
-               daemon->priority_cache = NULL;
-               return MHD_NO;
-             }
-           }
-          break;
-#endif
-#ifdef DAUTH_SUPPORT
-       case MHD_OPTION_DIGEST_AUTH_RANDOM:
-         daemon->digest_auth_rand_size = va_arg (ap, size_t);
-         daemon->digest_auth_random = va_arg (ap, const char *);
-         break;
-       case MHD_OPTION_NONCE_NC_SIZE:
-         daemon->nonce_nc_size = va_arg (ap, unsigned int);
-         break;
-#endif
-       case MHD_OPTION_LISTEN_SOCKET:
-         daemon->socket_fd = va_arg (ap, int);   
-         break;
-        case MHD_OPTION_EXTERNAL_LOGGER:
-#if HAVE_MESSAGES
-          daemon->custom_error_log =
-            va_arg (ap, VfprintfFunctionPointerType);
-          daemon->custom_error_log_cls = va_arg (ap, void *);
-#else
-          va_arg (ap, VfprintfFunctionPointerType);
-          va_arg (ap, void *);
-#endif
-          break;
-        case MHD_OPTION_THREAD_STACK_SIZE:
-          daemon->thread_stack_size = va_arg (ap, size_t);
-          break;
-       case MHD_OPTION_ARRAY:
-         oa = va_arg (ap, struct MHD_OptionItem*);
-         i = 0;
-         while (MHD_OPTION_END != (opt = oa[i].option))
-           {
-             switch (opt)
-               {
-                 /* all options taking 'size_t' */
-               case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
-               case MHD_OPTION_THREAD_STACK_SIZE:
-                 if (MHD_YES != parse_options (daemon,
-                                               servaddr,
-                                               opt,
-                                               (size_t) oa[i].value,
-                                               MHD_OPTION_END))
-                   return MHD_NO;
-                 break;
-                 /* all options taking 'unsigned int' */
-               case MHD_OPTION_NONCE_NC_SIZE:
-               case MHD_OPTION_CONNECTION_LIMIT:
-               case MHD_OPTION_CONNECTION_TIMEOUT:
-               case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
-               case MHD_OPTION_THREAD_POOL_SIZE:
-                 if (MHD_YES != parse_options (daemon,
-                                               servaddr,
-                                               opt,
-                                               (unsigned int) oa[i].value,
-                                               MHD_OPTION_END))
-                   return MHD_NO;
-                 break;
-                 /* all options taking 'int' or 'enum' */
-               case MHD_OPTION_HTTPS_CRED_TYPE:
-               case MHD_OPTION_LISTEN_SOCKET:
-                 if (MHD_YES != parse_options (daemon,
-                                               servaddr,
-                                               opt,
-                                               (int) oa[i].value,
-                                               MHD_OPTION_END))
-                   return MHD_NO;
-                 break;
-                 /* all options taking one pointer */
-               case MHD_OPTION_SOCK_ADDR:
-               case MHD_OPTION_HTTPS_MEM_KEY:
-               case MHD_OPTION_HTTPS_MEM_CERT:
-               case MHD_OPTION_HTTPS_MEM_TRUST:
-               case MHD_OPTION_HTTPS_PRIORITIES:
-               case MHD_OPTION_ARRAY:
-                 if (MHD_YES != parse_options (daemon,
-                                               servaddr,
-                                               opt,
-                                               oa[i].ptr_value,
-                                               MHD_OPTION_END))
-                   return MHD_NO;
-                 break;
-                 /* all options taking two pointers */
-               case MHD_OPTION_NOTIFY_COMPLETED:
-               case MHD_OPTION_URI_LOG_CALLBACK:
-               case MHD_OPTION_EXTERNAL_LOGGER:
-               case MHD_OPTION_UNESCAPE_CALLBACK:
-                 if (MHD_YES != parse_options (daemon,
-                                               servaddr,
-                                               opt,
-                                               (void *) oa[i].value,
-                                               oa[i].ptr_value,
-                                               MHD_OPTION_END))
-                   return MHD_NO;
-                 break;
-                 /* options taking size_t-number followed by pointer */
-               case MHD_OPTION_DIGEST_AUTH_RANDOM:
-                 if (MHD_YES != parse_options (daemon,
-                                               servaddr,
-                                               opt,
-                                               (size_t) oa[i].value,
-                                               oa[i].ptr_value,
-                                               MHD_OPTION_END))
-                   return MHD_NO;
-                 break;
-               default:
-                 return MHD_NO;
-               }
-             i++;
-           }
-         break;
-        case MHD_OPTION_UNESCAPE_CALLBACK:
-          daemon->unescape_callback =
-            va_arg (ap, UnescapeCallback);
-          daemon->unescape_callback_cls = va_arg (ap, void *);
-          break;
-        default:
-#if HAVE_MESSAGES
-          if (((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
-              (opt <= MHD_OPTION_HTTPS_PRIORITIES)) || (opt == 
MHD_OPTION_HTTPS_MEM_TRUST))
-            {
-              MHD_DLOG (daemon,
-                       "MHD HTTPS option %d passed to MHD compiled without 
HTTPS support\n",
-                       opt);
-            }
-          else
-            {
-              MHD_DLOG (daemon,
-                       "Invalid option %d! (Did you terminate the list with 
MHD_OPTION_END?)\n",
-                       opt);
-            }
-#endif
-         return MHD_NO;
-        }
-    }  
-  return MHD_YES;
-}
-
-
-/**
- * Create a listen socket, if possible with CLOEXEC flag set.
- *
- * @param domain socket domain (i.e. PF_INET)
- * @param type socket type (usually SOCK_STREAM)
- * @param protocol desired protocol, 0 for default
- */
-static int
-create_socket (int domain, int type, int protocol)
-{
-  static int sock_cloexec = SOCK_CLOEXEC;
-  int ctype = SOCK_STREAM | sock_cloexec;
-  int fd;
-  int flags;
-#ifdef WINDOWS
-  DWORD dwFlags;
-#endif
- 
-  /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo
-   * implementations do not set ai_socktype, e.g. RHL6.2. */
-  fd = SOCKET (domain, ctype, protocol);
-  if ( (-1 == fd) && (EINVAL == errno) && (0 != sock_cloexec) )
-  {
-    sock_cloexec = 0;
-    fd = SOCKET(domain, type, protocol);
-  }
-  if (-1 == fd)
-    return -1;
-  if (0 != sock_cloexec)
-    return fd; /* this is it */  
-  /* flag was not set during 'socket' call, let's try setting it manually */
-#ifndef WINDOWS
-  flags = fcntl (fd, F_GETFD);
-  if (flags < 0)
-#else
-  if (!GetHandleInformation ((HANDLE) fd, &dwFlags))
-#endif
-  {
-#ifdef WINDOWS
-    SetErrnoFromWinError (GetLastError ());
-#endif
-    return fd; /* good luck */
-  }
-#ifndef WINDOWS
-  if (flags == (flags | FD_CLOEXEC))
-    return fd; /* already set */
-  flags |= FD_CLOEXEC;
-  if (0 != fcntl (fd, F_SETFD, flags))
-#else
-  if (dwFlags != (dwFlags | HANDLE_FLAG_INHERIT))
-    return fd; /* already unset */
-  if (!SetHandleInformation ((HANDLE) fd, HANDLE_FLAG_INHERIT, 0))
-#endif
-  {
-#ifdef WINDOWS
-    SetErrnoFromWinError (GetLastError ());
-#endif
-    return fd; /* good luck */
-  }
-  return fd;
-}
-
-
-/**
- * Start a webserver on the given port.
- *
- * @param port port to bind to
- * @param apc callback to call to check which clients
- *        will be allowed to connect
- * @param apc_cls extra argument to apc
- * @param dh default handler for all URIs
- * @param dh_cls extra argument to dh
- * @return NULL on error, handle to daemon on success
- */
-struct MHD_Daemon *
-MHD_start_daemon_va (unsigned int options,
-                     uint16_t port,
-                     MHD_AcceptPolicyCallback apc,
-                     void *apc_cls,
-                     MHD_AccessHandlerCallback dh, void *dh_cls,
-                    va_list ap)
-{
-  const int on = 1;
-  struct MHD_Daemon *daemon;
-  int socket_fd;
-  struct sockaddr_in servaddr4;
-#if HAVE_INET6
-  struct sockaddr_in6 servaddr6;
-#endif
-  const struct sockaddr *servaddr = NULL;
-  socklen_t addrlen;
-  unsigned int i;
-  int res_thread_create;
-  int use_pipe;
-
-#ifndef HAVE_INET6
-  if (0 != (options & MHD_USE_IPv6))
-    return NULL;    
-#endif
-#ifndef HAVE_POLL_H
-  if (0 != (options & MHD_USE_POLL))
-    return NULL;    
-#endif
-#if ! HTTPS_SUPPORT
-  if (0 != (options & MHD_USE_SSL))
-    return NULL;    
-#endif
-  if (NULL == dh)
-    return NULL;
-  if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon))))
-    return NULL;
-  memset (daemon, 0, sizeof (struct MHD_Daemon));
-  /* try to open listen socket */
-#if HTTPS_SUPPORT
-  if (0 != (options & MHD_USE_SSL))
-    {
-      gnutls_priority_init (&daemon->priority_cache,
-                           "NORMAL",
-                           NULL);
-    }
-#endif
-  daemon->socket_fd = -1;
-  daemon->options = (enum MHD_OPTION) options;
-  daemon->port = port;
-  daemon->apc = apc;
-  daemon->apc_cls = apc_cls;
-  daemon->default_handler = dh;
-  daemon->default_handler_cls = dh_cls;
-  daemon->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
-  daemon->pool_size = MHD_POOL_SIZE_DEFAULT;
-  daemon->unescape_callback = &MHD_http_unescape;
-  daemon->connection_timeout = 0;       /* no timeout */
-  daemon->wpipe[0] = -1;
-  daemon->wpipe[1] = -1;
-#if HAVE_MESSAGES
-  daemon->custom_error_log = (MHD_LogCallback) &vfprintf;
-  daemon->custom_error_log_cls = stderr;
-#endif
-#ifdef HAVE_LISTEN_SHUTDOWN
-  use_pipe = (0 != (daemon->options & MHD_USE_NO_LISTEN_SOCKET));
-#else
-  use_pipe = 1; /* yes, must use pipe to signal shutdown */
-#endif
-  if ( (use_pipe) &&
-       (0 != PIPE (daemon->wpipe)) )
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, 
-               "Failed to create control pipe: %s\n",
-               STRERROR (errno));
-#endif
-      free (daemon);
-      return NULL;
-    }
-#ifndef WINDOWS
-  if ( (0 == (options & MHD_USE_POLL)) &&
-       (daemon->wpipe[0] >= FD_SETSIZE) )
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, 
-               "file descriptor for control pipe exceeds maximum value\n");
-#endif
-      CLOSE (daemon->wpipe[0]);
-      CLOSE (daemon->wpipe[1]);
-      free (daemon);
-      return NULL;
-    }
-#endif
-#ifdef DAUTH_SUPPORT
-  daemon->digest_auth_rand_size = 0;
-  daemon->digest_auth_random = NULL;
-  daemon->nonce_nc_size = 4; /* tiny */
-#endif
-#if HTTPS_SUPPORT
-  if (0 != (options & MHD_USE_SSL))
-    {
-      daemon->cred_type = GNUTLS_CRD_CERTIFICATE;
-    }
-#endif
-
-
-  if (MHD_YES != parse_options_va (daemon, &servaddr, ap))
-    {
-#if HTTPS_SUPPORT
-      if ( (0 != (options & MHD_USE_SSL)) &&
-          (NULL != daemon->priority_cache) )
-       gnutls_priority_deinit (daemon->priority_cache);
-#endif
-      free (daemon);
-      return NULL;
-    }
-#ifdef DAUTH_SUPPORT
-  if (daemon->nonce_nc_size > 0) 
-    {
-      if ( ( (size_t) (daemon->nonce_nc_size * sizeof(struct MHD_NonceNc))) / 
-          sizeof(struct MHD_NonceNc) != daemon->nonce_nc_size)
-       {
-#if HAVE_MESSAGES
-         MHD_DLOG (daemon,
-                   "Specified value for NC_SIZE too large\n");
-#endif
-#if HTTPS_SUPPORT
-         if (0 != (options & MHD_USE_SSL))
-           gnutls_priority_deinit (daemon->priority_cache);
-#endif
-         free (daemon);
-         return NULL;    
-       }
-      daemon->nnc = malloc (daemon->nonce_nc_size * sizeof(struct 
MHD_NonceNc));
-      if (NULL == daemon->nnc)
-       {
-#if HAVE_MESSAGES
-         MHD_DLOG (daemon,
-                   "Failed to allocate memory for nonce-nc map: %s\n",
-                   STRERROR (errno));
-#endif
-#if HTTPS_SUPPORT
-         if (0 != (options & MHD_USE_SSL))
-           gnutls_priority_deinit (daemon->priority_cache);
-#endif
-         free (daemon);
-         return NULL;
-       }
-    }
-  
-  if (0 != pthread_mutex_init (&daemon->nnc_lock, NULL))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-               "MHD failed to initialize nonce-nc mutex\n");
-#endif
-#if HTTPS_SUPPORT
-      if (0 != (options & MHD_USE_SSL))
-       gnutls_priority_deinit (daemon->priority_cache);
-#endif
-      free (daemon->nnc);
-      free (daemon);
-      return NULL;
-    }
-#endif
-
-  /* Thread pooling currently works only with internal select thread model */
-  if ( (0 == (options & MHD_USE_SELECT_INTERNALLY)) && 
-       (daemon->worker_pool_size > 0) )
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-               "MHD thread pooling only works with 
MHD_USE_SELECT_INTERNALLY\n");
-#endif
-      goto free_and_fail;
-    }
-
-#ifdef __SYMBIAN32__
-  if (0 != (options & (MHD_USE_SELECT_INTERNALLY | 
MHD_USE_THREAD_PER_CONNECTION)))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-               "Threaded operations are not supported on Symbian.\n");
-#endif
-      goto free_and_fail;
-    }
-#endif
-  if ( (-1 == daemon->socket_fd) &&
-       (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
-    {
-      /* try to open listen socket */
-      if ((options & MHD_USE_IPv6) != 0)
-       socket_fd = create_socket (PF_INET6, SOCK_STREAM, 0);
-      else
-       socket_fd = create_socket (PF_INET, SOCK_STREAM, 0);
-      if (-1 == socket_fd)
-       {
-#if HAVE_MESSAGES
-         if (0 != (options & MHD_USE_DEBUG))
-           MHD_DLOG (daemon, 
-                     "Call to socket failed: %s\n", 
-                     STRERROR (errno));
-#endif
-         goto free_and_fail;
-       }
-      if ((SETSOCKOPT (socket_fd,
-                      SOL_SOCKET,
-                      SO_REUSEADDR,
-                      &on, sizeof (on)) < 0) && ((options & MHD_USE_DEBUG) != 
0))
-       {
-#if HAVE_MESSAGES
-         MHD_DLOG (daemon, 
-                   "setsockopt failed: %s\n", 
-                   STRERROR (errno));
-#endif
-       }
-      
-      /* check for user supplied sockaddr */
-#if HAVE_INET6
-      if (0 != (options & MHD_USE_IPv6))
-       addrlen = sizeof (struct sockaddr_in6);
-      else
-#endif
-       addrlen = sizeof (struct sockaddr_in);
-      if (NULL == servaddr)
-       {
-#if HAVE_INET6
-         if (0 != (options & MHD_USE_IPv6))
-           {
-             memset (&servaddr6, 0, sizeof (struct sockaddr_in6));
-             servaddr6.sin6_family = AF_INET6;
-             servaddr6.sin6_port = htons (port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-             servaddr6.sin6_len = sizeof (struct sockaddr_in6);
-#endif
-             servaddr = (struct sockaddr *) &servaddr6;
-           }
-         else
-#endif
-           {
-             memset (&servaddr4, 0, sizeof (struct sockaddr_in));
-             servaddr4.sin_family = AF_INET;
-             servaddr4.sin_port = htons (port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-             servaddr4.sin_len = sizeof (struct sockaddr_in);
-#endif
-             servaddr = (struct sockaddr *) &servaddr4;
-           }
-       }
-      daemon->socket_fd = socket_fd;
-
-      if (0 != (options & MHD_USE_IPv6))
-       {
-#ifdef IPPROTO_IPV6
-#ifdef IPV6_V6ONLY
-         /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see 
"IPPROTO_IPV6 Socket Options" 
-            
(http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx); 
-            and may also be missing on older POSIX systems; good luck if you 
have any of those,
-            your IPv6 socket may then also bind against IPv4... */
-#ifndef WINDOWS
-         const int on = 1;
-         setsockopt (socket_fd, 
-                     IPPROTO_IPV6, IPV6_V6ONLY, 
-                     &on, sizeof (on));
-#else
-         const char on = 1;
-         setsockopt (socket_fd, 
-                     IPPROTO_IPV6, IPV6_V6ONLY, 
-                     &on, sizeof (on));
-#endif
-#endif
-#endif
-       }
-      if (-1 == BIND (socket_fd, servaddr, addrlen))
-       {
-#if HAVE_MESSAGES
-         if (0 != (options & MHD_USE_DEBUG))
-           MHD_DLOG (daemon,
-                     "Failed to bind to port %u: %s\n", 
-                     (unsigned int) port, 
-                     STRERROR (errno));
-#endif
-         CLOSE (socket_fd);
-         goto free_and_fail;
-       }
-      
-      if (LISTEN (socket_fd, 20) < 0)
-       {
-#if HAVE_MESSAGES
-         if (0 != (options & MHD_USE_DEBUG))
-           MHD_DLOG (daemon,
-                     "Failed to listen for connections: %s\n", 
-                     STRERROR (errno));
-#endif
-         CLOSE (socket_fd);
-         goto free_and_fail;
-       }      
-    }
-  else
-    {
-      socket_fd = daemon->socket_fd;
-    }
-#ifndef WINDOWS
-  if ( (socket_fd >= FD_SETSIZE) &&
-       (0 == (options & MHD_USE_POLL)) )
-    {
-#if HAVE_MESSAGES
-      if ((options & MHD_USE_DEBUG) != 0)
-        MHD_DLOG (daemon,
-                 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
-                 socket_fd,
-                 FD_SETSIZE);
-#endif
-      CLOSE (socket_fd);
-      goto free_and_fail;
-    }
-#endif
-
-  if (0 != pthread_mutex_init (&daemon->per_ip_connection_mutex, NULL))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-               "MHD failed to initialize IP connection limit mutex\n");
-#endif
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
-      goto free_and_fail;
-    }
-  if (0 != pthread_mutex_init (&daemon->cleanup_connection_mutex, NULL))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-               "MHD failed to initialize IP connection limit mutex\n");
-#endif
-      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
-      goto free_and_fail;
-    }
-
-#if HTTPS_SUPPORT
-  /* initialize HTTPS daemon certificate aspects & send / recv functions */
-  if ((0 != (options & MHD_USE_SSL)) && (0 != MHD_TLS_init (daemon)))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon, 
-               "Failed to initialize TLS support\n");
-#endif
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
-      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
-      pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
-      goto free_and_fail;
-    }
-#endif
-  if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
-        ( (0 != (options & MHD_USE_SELECT_INTERNALLY)) &&
-          (0 == daemon->worker_pool_size)) ) && 
-       (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) &&
-       (0 != (res_thread_create =
-             create_thread (&daemon->pid, daemon, &MHD_select_thread, 
daemon))))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (daemon,
-                "Failed to create listen thread: %s\n", 
-               STRERROR (res_thread_create));
-#endif
-      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
-      pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
-      goto free_and_fail;
-    }
-  if ( (daemon->worker_pool_size > 0) &&
-       (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
-    {
-#ifndef MINGW
-      int sk_flags;
-#else
-      unsigned long sk_flags;
-#endif
-
-      /* Coarse-grained count of connections per thread (note error
-       * due to integer division). Also keep track of how many
-       * connections are leftover after an equal split. */
-      unsigned int conns_per_thread = daemon->max_connections
-                                      / daemon->worker_pool_size;
-      unsigned int leftover_conns = daemon->max_connections
-                                    % daemon->worker_pool_size;
-
-      i = 0; /* we need this in case fcntl or malloc fails */
-
-      /* Accept must be non-blocking. Multiple children may wake up
-       * to handle a new connection, but only one will win the race.
-       * The others must immediately return. */
-#ifndef MINGW
-      sk_flags = fcntl (socket_fd, F_GETFL);
-      if (sk_flags < 0)
-        goto thread_failed;
-      if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK))
-        goto thread_failed;
-#else
-      sk_flags = 1;
-#if HAVE_PLIBC_FD
-      if (SOCKET_ERROR ==
-         ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags))
-        goto thread_failed;
-#else
-      if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR)
-        goto thread_failed;
-#endif // PLIBC_FD
-#endif // MINGW
-
-      /* Allocate memory for pooled objects */
-      daemon->worker_pool = malloc (sizeof (struct MHD_Daemon)
-                                    * daemon->worker_pool_size);
-      if (NULL == daemon->worker_pool)
-        goto thread_failed;
-
-      /* Start the workers in the pool */
-      for (i = 0; i < daemon->worker_pool_size; ++i)
-        {
-          /* Create copy of the Daemon object for each worker */
-          struct MHD_Daemon *d = &daemon->worker_pool[i];
-          memcpy (d, daemon, sizeof (struct MHD_Daemon));
-
-          /* Adjust pooling params for worker daemons; note that memcpy()
-             has already copied MHD_USE_SELECT_INTERNALLY thread model into
-             the worker threads. */
-          d->master = daemon;
-          d->worker_pool_size = 0;
-          d->worker_pool = NULL;
-
-          /* Divide available connections evenly amongst the threads.
-           * Thread indexes in [0, leftover_conns) each get one of the
-           * leftover connections. */
-          d->max_connections = conns_per_thread;
-          if (i < leftover_conns)
-            ++d->max_connections;
-
-          /* Must init cleanup connection mutex for each worker */
-          if (0 != pthread_mutex_init (&d->cleanup_connection_mutex, NULL))
-            {
-#if HAVE_MESSAGES
-              MHD_DLOG (daemon,
-                       "MHD failed to initialize cleanup connection mutex for 
thread worker %d\n", i);
-#endif
-              goto thread_failed;
-            }
-
-          /* Spawn the worker thread */
-          if (0 != (res_thread_create = create_thread (&d->pid, daemon, 
&MHD_select_thread, d)))
-            {
-#if HAVE_MESSAGES
-              MHD_DLOG (daemon,
-                        "Failed to create pool thread: %s\n", 
-                       STRERROR (res_thread_create));
-#endif
-              /* Free memory for this worker; cleanup below handles
-               * all previously-created workers. */
-              pthread_mutex_destroy (&d->cleanup_connection_mutex);
-              goto thread_failed;
-            }
-        }
-    }
-  return daemon;
-
-thread_failed:
-  /* If no worker threads created, then shut down normally. Calling
-     MHD_stop_daemon (as we do below) doesn't work here since it
-     assumes a 0-sized thread pool means we had been in the default
-     MHD_USE_SELECT_INTERNALLY mode. */
-  if (0 == i)
-    {
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
-      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
-      pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
-      if (NULL != daemon->worker_pool)
-        free (daemon->worker_pool);
-      goto free_and_fail;
-    }
-
-  /* Shutdown worker threads we've already created. Pretend
-     as though we had fully initialized our daemon, but
-     with a smaller number of threads than had been
-     requested. */
-  daemon->worker_pool_size = i - 1;
-  MHD_stop_daemon (daemon);
-  return NULL;
-
- free_and_fail:
-  /* clean up basic memory state in 'daemon' and return NULL to 
-     indicate failure */
-#ifdef DAUTH_SUPPORT
-  free (daemon->nnc);
-  pthread_mutex_destroy (&daemon->nnc_lock);
-#endif
-#if HTTPS_SUPPORT
-  if (0 != (options & MHD_USE_SSL))
-    gnutls_priority_deinit (daemon->priority_cache);
-#endif
-  free (daemon);
-  return NULL;
-}
-
-
-/**
- * Close all connections for the daemon; must only be called after
- * all of the threads have been joined and there is no more concurrent
- * activity on the connection lists.
- *
- * @param daemon daemon to close down
- */
-static void
-close_all_connections (struct MHD_Daemon *daemon)
-{
-  struct MHD_Connection *pos;
-  void *unused;
-  int rc;
-  
-  /* first, make sure all threads are aware of shutdown; need to
-     traverse DLLs in peace... */
-  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to acquire cleanup mutex\n");
-    }
-  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)    
-    SHUTDOWN (pos->socket_fd, 
-             (pos->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);    
-  if (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to release cleanup mutex\n");
-    }
-
-  /* now, collect threads */
-  if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
-    {
-      while (NULL != (pos = daemon->connections_head))
-       {
-         if (0 != (rc = pthread_join (pos->pid, &unused)))
-           {
-             MHD_PANIC ("Failed to join a thread\n");
-           }
-         pos->thread_joined = MHD_YES;
-       }
-    }
-
-  /* now that we're alone, move everyone to cleanup */
-  while (NULL != (pos = daemon->connections_head))
-    {
-      MHD_connection_close (pos,
-                           MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
-      DLL_remove (daemon->connections_head,
-                 daemon->connections_tail,
-                 pos);
-      DLL_insert (daemon->cleanup_head,
-                 daemon->cleanup_tail,
-                 pos);
-    }
-  MHD_cleanup_connections (daemon);
-}
-
-
-/**
- * Shutdown an http daemon
- *
- * @param daemon daemon to stop
- */
-void
-MHD_stop_daemon (struct MHD_Daemon *daemon)
-{
-  void *unused;
-  int fd;
-  unsigned int i;
-  int rc;
-
-  if (NULL == daemon)
-    return;
-  daemon->shutdown = MHD_YES;
-  fd = daemon->socket_fd;
-  daemon->socket_fd = -1;
-  /* Prepare workers for shutdown */
-  if (NULL != daemon->worker_pool)
-    {
-      /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to 
check */
-      for (i = 0; i < daemon->worker_pool_size; ++i)
-       {
-         daemon->worker_pool[i].shutdown = MHD_YES;
-         daemon->worker_pool[i].socket_fd = -1;
-       }
-    }
-  if (-1 != daemon->wpipe[1])
-    {
-      if (1 != WRITE (daemon->wpipe[1], "e", 1))
-       MHD_PANIC ("failed to signal shutdownn via pipe");
-    }
-#ifdef HAVE_LISTEN_SHUTDOWN
-  else
-    {
-      /* fd might be -1 here due to 'MHD_quiesce_daemon' */
-      if (-1 != fd)
-       (void) SHUTDOWN (fd, SHUT_RDWR);
-    }
-#endif
-#if DEBUG_CLOSE
-#if HAVE_MESSAGES
-  MHD_DLOG (daemon, "MHD listen socket shutdown\n");
-#endif
-#endif
-
-
-  /* Signal workers to stop and clean them up */
-  if (NULL != daemon->worker_pool)
-    {
-      /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to 
check */
-      for (i = 0; i < daemon->worker_pool_size; ++i)
-       {
-         if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused)))
-           {
-             MHD_PANIC ("Failed to join a thread\n");
-           }
-         close_all_connections (&daemon->worker_pool[i]);
-         pthread_mutex_destroy 
(&daemon->worker_pool[i].cleanup_connection_mutex);
-       }
-      free (daemon->worker_pool);
-    }
-  else
-    {
-      /* clean up master threads */
-      if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
-         ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
-          && (0 == daemon->worker_pool_size)))
-       {
-         if (0 != (rc = pthread_join (daemon->pid, &unused)))
-           {
-             MHD_PANIC ("Failed to join a thread\n");
-           }
-       }
-    }
-  close_all_connections (daemon);
-  if (-1 != fd)
-    (void) CLOSE (fd);
-
-  /* TLS clean up */
-#if HTTPS_SUPPORT
-  if (0 != (daemon->options & MHD_USE_SSL))
-    {
-      gnutls_priority_deinit (daemon->priority_cache);
-      if (daemon->x509_cred)
-        gnutls_certificate_free_credentials (daemon->x509_cred);
-    }
-#endif
-
-#ifdef DAUTH_SUPPORT
-  free (daemon->nnc);
-  pthread_mutex_destroy (&daemon->nnc_lock);
-#endif
-  pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
-  pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
-
-  if (-1 != daemon->wpipe[1])
-    {
-      (void) CLOSE (daemon->wpipe[0]);
-      (void) CLOSE (daemon->wpipe[1]);
-    }
-  free (daemon);
-}
-
-
-/**
- * Obtain information about the given daemon
- * (not fully implemented!).
- *
- * @param daemon what daemon to get information about
- * @param infoType what information is desired?
- * @param ... depends on infoType
- * @return NULL if this information is not available
- *         (or if the infoType is unknown)
- */
-const union MHD_DaemonInfo *
-MHD_get_daemon_info (struct MHD_Daemon *daemon,
-                     enum MHD_DaemonInfoType infoType, ...)
-{
-  switch (infoType)
-    {
-    case MHD_DAEMON_INFO_LISTEN_FD:
-      return (const union MHD_DaemonInfo *) &daemon->socket_fd;
-    default:
-      return NULL;
-    };
-}
-
-
-/**
- * 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.  While "cb" is allowed to return and MHD will then
- * try to continue, this is never safe.
- *
- * The default implementation that is used if no panic function is set
- * simply prints an error message and calls "abort".  Alternative
- * implementations might call "exit" or other similar functions.
- *
- * @param cb new error handler
- * @param cls passed to error handler
- */
-void 
-MHD_set_panic_func (MHD_PanicCallback cb, void *cls)
-{
-  mhd_panic = cb;
-  mhd_panic_cls = cls;
-}
-
-
-/**
- * Obtain the version of this library
- *
- * @return static version string, e.g. "0.4.1"
- */
-const char *
-MHD_get_version (void)
-{
-  return PACKAGE_VERSION;
-}
-
-
-#ifdef __GNUC__
-#define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor))
-#define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor))
-#else  // !__GNUC__
-#define ATTRIBUTE_CONSTRUCTOR
-#define ATTRIBUTE_DESTRUCTOR
-#endif  // __GNUC__
-
-#if HTTPS_SUPPORT
-GCRY_THREAD_OPTION_PTHREAD_IMPL;
-#endif
-
-
-/**
- * Initialize do setup work.
- */
-void ATTRIBUTE_CONSTRUCTOR 
-MHD_init ()
-{
-  mhd_panic = &mhd_panic_std;
-  mhd_panic_cls = NULL;
-
-#ifdef WINDOWS
-  plibc_init ("GNU", "libmicrohttpd");
-#endif
-#if HTTPS_SUPPORT
-  gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
-  gnutls_global_init ();
-#endif
-}
-
-
-void ATTRIBUTE_DESTRUCTOR 
-MHD_fini ()
-{
-#if HTTPS_SUPPORT
-  gnutls_global_deinit ();
-#endif
-#ifdef WINDOWS
-  plibc_shutdown ();
-#endif
-}
-
-/* end of daemon.c */

Copied: libmicrohttpd/src/microhttpd/daemon.c (from rev 27024, 
libmicrohttpd/src/daemon/daemon.c)
===================================================================
--- libmicrohttpd/src/microhttpd/daemon.c                               (rev 0)
+++ libmicrohttpd/src/microhttpd/daemon.c       2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,2947 @@
+/*
+  This file is part of libmicrohttpd
+  (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+
+*/
+
+/**
+ * @file daemon.c
+ * @brief  A minimal-HTTP server library
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "internal.h"
+#include "response.h"
+#include "connection.h"
+#include "memorypool.h"
+#include <limits.h>
+
+#if HAVE_SEARCH_H
+#include <search.h>
+#else
+#include "tsearch.h"
+#endif
+
+#if HTTPS_SUPPORT
+#include "connection_https.h"
+#include <gnutls/gnutls.h>
+#include <gcrypt.h>
+#endif
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+
+#ifdef LINUX
+#include <sys/sendfile.h>
+#endif
+
+/**
+ * Default connection limit.
+ */
+#ifndef WINDOWS
+#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE - 4
+#else
+#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE
+#endif
+
+/**
+ * Default memory allowed per connection.
+ */
+#define MHD_POOL_SIZE_DEFAULT (32 * 1024)
+
+/**
+ * Print extra messages with reasons for closing
+ * sockets? (only adds non-error messages).
+ */
+#define DEBUG_CLOSE MHD_NO
+
+/**
+ * Print extra messages when establishing
+ * connections? (only adds non-error messages).
+ */
+#define DEBUG_CONNECT MHD_NO
+
+#ifndef LINUX
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+#endif
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+
+/**
+ * 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 
+mhd_panic_std (void *cls,
+              const char *file,
+              unsigned int line,
+              const char *reason)
+{
+#if HAVE_MESSAGES
+  fprintf (stderr, "Fatal error in GNU libmicrohttpd %s:%u: %s\n",
+          file, line, reason);
+#endif
+  abort ();
+}
+
+
+/**
+ * Handler for fatal errors.
+ */
+MHD_PanicCallback mhd_panic;
+
+/**
+ * Closure argument for "mhd_panic".
+ */
+void *mhd_panic_cls;
+
+
+/**
+ * Trace up to and return master daemon. If the supplied daemon
+ * is a master, then return the daemon itself.
+ *
+ * @param daemon handle to a daemon 
+ * @return master daemon handle
+ */
+static struct MHD_Daemon*
+MHD_get_master (struct MHD_Daemon *daemon)
+{
+  while (NULL != daemon->master)
+    daemon = daemon->master;
+  return daemon;
+}
+
+
+/**
+ * Maintain connection count for single address.
+ */
+struct MHD_IPCount
+{
+  /**
+   * Address family. AF_INET or AF_INET6 for now.
+   */
+  int family;
+
+  /**
+   * Actual address.
+   */
+  union
+  {
+    /**
+     * IPv4 address.
+     */ 
+    struct in_addr ipv4;
+#if HAVE_IPV6
+    /**
+     * IPv6 address.
+     */ 
+    struct in6_addr ipv6;
+#endif
+  } addr;
+
+  /**
+   * Counter.
+   */
+  unsigned int count;
+};
+
+
+/**
+ * Lock shared structure for IP connection counts and connection DLLs.
+ *
+ * @param daemon handle to daemon where lock is
+ */
+static void
+MHD_ip_count_lock(struct MHD_Daemon *daemon)
+{
+  if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex))
+    {
+      MHD_PANIC ("Failed to acquire IP connection limit mutex\n");
+    }
+}
+
+
+/**
+ * Unlock shared structure for IP connection counts and connection DLLs.
+ *
+ * @param daemon handle to daemon where lock is
+ */
+static void
+MHD_ip_count_unlock(struct MHD_Daemon *daemon)
+{
+  if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex))
+    {
+      MHD_PANIC ("Failed to release IP connection limit mutex\n");
+    }
+}
+
+
+/**
+ * Tree comparison function for IP addresses (supplied to tsearch() family).
+ * We compare everything in the struct up through the beginning of the
+ * 'count' field.
+ * 
+ * @param a1 first address to compare
+ * @param a2 second address to compare
+ * @return -1, 0 or 1 depending on result of compare
+ */
+static int
+MHD_ip_addr_compare(const void *a1, const void *a2)
+{
+  return memcmp (a1, a2, offsetof (struct MHD_IPCount, count));
+}
+
+
+/**
+ * Parse address and initialize 'key' using the address.
+ *
+ * @param addr address to parse
+ * @param addrlen number of bytes in addr
+ * @param key where to store the parsed address
+ * @return MHD_YES on success and MHD_NO otherwise (e.g., invalid address type)
+ */
+static int
+MHD_ip_addr_to_key(const struct sockaddr *addr, 
+                  socklen_t addrlen,
+                   struct MHD_IPCount *key)
+{
+  memset(key, 0, sizeof(*key));
+
+  /* IPv4 addresses */
+  if (sizeof (struct sockaddr_in) == addrlen)
+    {
+      const struct sockaddr_in *addr4 = (const struct sockaddr_in*) addr;
+      key->family = AF_INET;
+      memcpy (&key->addr.ipv4, &addr4->sin_addr, sizeof(addr4->sin_addr));
+      return MHD_YES;
+    }
+
+#if HAVE_IPV6
+  /* IPv6 addresses */
+  if (sizeof (struct sockaddr_in6) == addrlen)
+    {
+      const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*) addr;
+      key->family = AF_INET6;
+      memcpy (&key->addr.ipv6, &addr6->sin6_addr, sizeof(addr6->sin6_addr));
+      return MHD_YES;
+    }
+#endif
+
+  /* Some other address */
+  return MHD_NO;
+}
+
+
+/**
+ * Check if IP address is over its limit.
+ *
+ * @param daemon handle to daemon where connection counts are tracked
+ * @param addr address to add (or increment counter)
+ * @param addrlen number of bytes in addr
+ * @return Return MHD_YES if IP below limit, MHD_NO if IP has surpassed limit.
+ *   Also returns MHD_NO if fails to allocate memory.
+ */
+static int
+MHD_ip_limit_add(struct MHD_Daemon *daemon,
+                 const struct sockaddr *addr,
+                socklen_t addrlen)
+{
+  struct MHD_IPCount *key;
+  void **nodep;
+  void *node;
+  int result;
+
+  daemon = MHD_get_master (daemon);
+  /* Ignore if no connection limit assigned */
+  if (0 == daemon->per_ip_connection_limit)
+    return MHD_YES;
+
+  if (NULL == (key = malloc (sizeof(*key))))
+    return MHD_NO;
+
+  /* Initialize key */
+  if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key))
+    {
+      /* Allow unhandled address types through */
+      free (key);
+      return MHD_YES;
+    }
+  MHD_ip_count_lock (daemon);
+
+  /* Search for the IP address */
+  if (NULL == (nodep = TSEARCH (key, 
+                               &daemon->per_ip_connection_count, 
+                               &MHD_ip_addr_compare)))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "Failed to add IP connection count node\n");
+#endif      
+      MHD_ip_count_unlock (daemon);
+      free (key);
+      return MHD_NO;
+    }
+  node = *nodep;
+  /* If we got an existing node back, free the one we created */
+  if (node != key)
+    free(key);
+  key = (struct MHD_IPCount *) node;
+  /* Test if there is room for another connection; if so,
+   * increment count */
+  result = (key->count < daemon->per_ip_connection_limit);
+  if (MHD_YES == result)
+    ++key->count;
+
+  MHD_ip_count_unlock (daemon);
+  return result;
+}
+
+
+/**
+ * Decrement connection count for IP address, removing from table
+ * count reaches 0
+ *
+ * @param daemon handle to daemon where connection counts are tracked
+ * @param addr address to remove (or decrement counter)
+ * @param addrlen number of bytes in addr
+ */
+static void
+MHD_ip_limit_del(struct MHD_Daemon *daemon,
+                 const struct sockaddr *addr,
+                socklen_t addrlen)
+{
+  struct MHD_IPCount search_key;
+  struct MHD_IPCount *found_key;
+  void **nodep;
+
+  daemon = MHD_get_master (daemon);
+  /* Ignore if no connection limit assigned */
+  if (0 == daemon->per_ip_connection_limit)
+    return;
+  /* Initialize search key */
+  if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key))
+    return;
+
+  MHD_ip_count_lock (daemon);
+
+  /* Search for the IP address */
+  if (NULL == (nodep = TFIND (&search_key, 
+                             &daemon->per_ip_connection_count, 
+                             &MHD_ip_addr_compare)))
+    {      
+      /* Something's wrong if we couldn't find an IP address
+       * that was previously added */
+      MHD_PANIC ("Failed to find previously-added IP address\n");
+    }
+  found_key = (struct MHD_IPCount *) *nodep;
+  /* Validate existing count for IP address */
+  if (0 == found_key->count)
+    {
+      MHD_PANIC ("Previously-added IP address had 0 count\n");
+    }
+  /* Remove the node entirely if count reduces to 0 */
+  if (0 == --found_key->count)
+    {
+      TDELETE (found_key, 
+              &daemon->per_ip_connection_count, 
+              &MHD_ip_addr_compare);
+      free (found_key);
+    }
+
+  MHD_ip_count_unlock (daemon);
+}
+
+
+#if HTTPS_SUPPORT
+/**
+ * Callback for receiving data from the socket.
+ *
+ * @param connection the MHD connection structure
+ * @param other where to write received data to
+ * @param i maximum size of other (in bytes)
+ * @return number of bytes actually received
+ */
+static ssize_t
+recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i)
+{
+  int res;
+
+  connection->tls_read_ready = MHD_NO;
+  res = gnutls_record_recv (connection->tls_session, other, i);
+  if ( (GNUTLS_E_AGAIN == res) ||
+       (GNUTLS_E_INTERRUPTED == res) )
+    {
+      errno = EINTR;
+      return -1;
+    }
+  if (res < 0)
+    {
+      /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
+        disrupted); set errno to something caller will interpret
+        correctly as a hard error*/
+      errno = EPIPE;
+      return res;
+    }
+  if (res == i)
+    connection->tls_read_ready = MHD_YES;
+  return res;
+}
+
+
+/**
+ * Callback for writing data to the socket.
+ *
+ * @param connection the MHD connection structure
+ * @param other data to write
+ * @param i number of bytes to write
+ * @return actual number of bytes written
+ */
+static ssize_t
+send_tls_adapter (struct MHD_Connection *connection,
+                  const void *other, size_t i)
+{
+  int res;
+
+  res = gnutls_record_send (connection->tls_session, other, i);
+  if ( (GNUTLS_E_AGAIN == res) ||
+       (GNUTLS_E_INTERRUPTED == res) )
+    {
+      errno = EINTR;
+      return -1;
+    }
+  return res;
+}
+
+
+/**
+ * Read and setup our certificate and key.
+ *
+ * @param daemon handle to daemon to initialize
+ * @return 0 on success
+ */
+static int
+MHD_init_daemon_certificate (struct MHD_Daemon *daemon)
+{
+  gnutls_datum_t key;
+  gnutls_datum_t cert;
+
+  if (NULL != daemon->https_mem_trust) 
+    {
+      cert.data = (unsigned char *) daemon->https_mem_trust;
+      cert.size = strlen (daemon->https_mem_trust);
+      if (gnutls_certificate_set_x509_trust_mem (daemon->x509_cred, &cert,
+                                                GNUTLS_X509_FMT_PEM) < 0) 
+       {
+#if HAVE_MESSAGES
+         MHD_DLOG(daemon,
+                  "Bad trust certificate format\n");
+#endif
+         return -1;
+       }
+    }
+  
+  /* certificate & key loaded from memory */
+  if ( (NULL != daemon->https_mem_cert) && 
+       (NULL != daemon->https_mem_key) )
+    {
+      key.data = (unsigned char *) daemon->https_mem_key;
+      key.size = strlen (daemon->https_mem_key);
+      cert.data = (unsigned char *) daemon->https_mem_cert;
+      cert.size = strlen (daemon->https_mem_cert);
+
+      return gnutls_certificate_set_x509_key_mem (daemon->x509_cred,
+                                                 &cert, &key,
+                                                 GNUTLS_X509_FMT_PEM);
+    }
+#if HAVE_MESSAGES
+  MHD_DLOG (daemon, "You need to specify a certificate and key location\n");
+#endif
+  return -1;
+}
+
+
+/**
+ * Initialize security aspects of the HTTPS daemon
+ *
+ * @param daemon handle to daemon to initialize
+ * @return 0 on success
+ */
+static int
+MHD_TLS_init (struct MHD_Daemon *daemon)
+{
+  switch (daemon->cred_type)
+    {
+    case GNUTLS_CRD_CERTIFICATE:
+      if (0 !=
+          gnutls_certificate_allocate_credentials (&daemon->x509_cred))
+        return GNUTLS_E_MEMORY_ERROR;
+      return MHD_init_daemon_certificate (daemon);
+    default:
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+                "Error: invalid credentials type %d specified.\n",
+                daemon->cred_type);
+#endif
+      return -1;
+    }
+}
+#endif
+
+
+/**
+ * Obtain the select sets for this daemon.
+ *
+ * @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 max_fd increased to largest FD added (if larger
+ *               than existing value); can be NULL
+ * @return MHD_YES on success, MHD_NO if this
+ *         daemon was not started with the right
+ *         options for this call.
+ */
+int
+MHD_get_fdset (struct MHD_Daemon *daemon,
+               fd_set *read_fd_set,
+               fd_set *write_fd_set, 
+              fd_set *except_fd_set,
+              int *max_fd)
+{
+  struct MHD_Connection *pos;
+  int fd;
+
+  if ( (NULL == daemon) 
+       || (NULL == read_fd_set) 
+       || (NULL == write_fd_set)
+       || (NULL == except_fd_set) 
+       || (NULL == max_fd)
+       || (MHD_YES == daemon->shutdown)
+       || (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+       || (0 != (daemon->options & MHD_USE_POLL)))
+    return MHD_NO;
+  fd = daemon->socket_fd;
+  if (-1 != fd)
+  {
+    FD_SET (fd, read_fd_set);
+    /* update max file descriptor */
+    if ((*max_fd) < fd) 
+      *max_fd = fd;
+  }
+  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
+    if (MHD_YES != MHD_connection_get_fdset (pos,
+                                            read_fd_set,
+                                            write_fd_set,
+                                            except_fd_set, max_fd))
+      return MHD_NO;    
+#if DEBUG_CONNECT
+  MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
+#endif
+  return MHD_YES;
+}
+
+
+/**
+ * Main function of the thread that handles an individual
+ * connection when MHD_USE_THREAD_PER_CONNECTION is set.
+ * 
+ * @param data the 'struct MHD_Connection' this thread will handle
+ * @return always NULL
+ */
+static void *
+MHD_handle_connection (void *data)
+{
+  struct MHD_Connection *con = data;
+  int num_ready;
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  int max;
+  struct timeval tv;
+  struct timeval *tvp;
+  unsigned int timeout;
+  time_t now;
+#ifdef HAVE_POLL_H
+  struct MHD_Pollfd mp;
+  struct pollfd p[1];
+#endif
+
+  timeout = con->daemon->connection_timeout;
+  while ( (MHD_YES != con->daemon->shutdown) && 
+         (MHD_CONNECTION_CLOSED != con->state) ) 
+    {
+      tvp = NULL;
+      if (timeout > 0)
+       {
+         now = MHD_monotonic_time();
+         if (now - con->last_activity > timeout)
+           tv.tv_sec = 0;
+         else
+           tv.tv_sec = timeout - (now - con->last_activity);
+         tv.tv_usec = 0;
+         tvp = &tv;
+       }
+      if ( (MHD_CONNECTION_NORMAL_BODY_UNREADY == con->state) ||
+          (MHD_CONNECTION_CHUNKED_BODY_UNREADY == con->state) )
+       {
+         /* do not block (we're waiting for our callback to succeed) */
+         tv.tv_sec = 0;
+         tv.tv_usec = 0;
+         tvp = &tv;
+       }
+#if HTTPS_SUPPORT
+      if (MHD_YES == con->tls_read_ready)
+       {
+         /* do not block (more data may be inside of TLS buffers waiting for 
us) */
+         tv.tv_sec = 0;
+         tv.tv_usec = 0;
+         tvp = &tv;
+       }
+#endif
+      if (0 == (con->daemon->options & MHD_USE_POLL))
+       {
+         /* use select */
+         FD_ZERO (&rs);
+         FD_ZERO (&ws);
+         FD_ZERO (&es);
+         max = 0;
+         MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
+         num_ready = SELECT (max + 1, &rs, &ws, &es, tvp);
+         if (num_ready < 0) 
+           {
+             if (EINTR == errno)
+               continue;
+#if HAVE_MESSAGES
+             MHD_DLOG (con->daemon,
+                       "Error during select (%d): `%s'\n", 
+                       max,
+                       STRERROR (errno));
+#endif
+             break;
+           }
+         /* call appropriate connection handler if necessary */
+         if ( (FD_ISSET (con->socket_fd, &rs))
+#if HTTPS_SUPPORT
+                  || (MHD_YES == con->tls_read_ready) 
+#endif
+              )
+           con->read_handler (con);
+         if (FD_ISSET (con->socket_fd, &ws))
+           con->write_handler (con);
+         if (MHD_NO == con->idle_handler (con))
+           goto exit;
+       }
+#ifdef HAVE_POLL_H
+      else
+       {
+         /* use poll */
+         memset(&mp, 0, sizeof (struct MHD_Pollfd));
+         MHD_connection_get_pollfd(con, &mp);
+         memset(&p, 0, sizeof (p));
+         p[0].fd = mp.fd;
+         if (mp.events & MHD_POLL_ACTION_IN) 
+           p[0].events |= POLLIN;        
+         if (mp.events & MHD_POLL_ACTION_OUT) 
+           p[0].events |= POLLOUT;
+         if (poll (p, 
+                   1, 
+                   (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0)
+           {
+             if (EINTR == errno)
+               continue;
+#if HAVE_MESSAGES
+             MHD_DLOG (con->daemon, "Error during poll: `%s'\n", 
+                       STRERROR (errno));
+#endif
+             break;
+           }
+         if ( (0 != (p[0].revents & POLLIN)) 
+#if HTTPS_SUPPORT
+              || (MHD_YES == con->tls_read_ready) 
+#endif
+              )
+           con->read_handler (con);        
+         if (0 != (p[0].revents & POLLOUT)) 
+           con->write_handler (con);        
+         if (0 != (p[0].revents & (POLLERR | POLLHUP))) 
+           MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR);      
+         if (MHD_NO == con->idle_handler (con))
+           goto exit;
+       }
+#endif
+    }
+  if (MHD_CONNECTION_IN_CLEANUP != con->state)
+    {
+#if DEBUG_CLOSE
+#if HAVE_MESSAGES
+      MHD_DLOG (con->daemon,
+                "Processing thread terminating, closing connection\n");
+#endif
+#endif
+      if (MHD_CONNECTION_CLOSED != con->state)
+       MHD_connection_close (con, 
+                             MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
+      con->idle_handler (con);
+    }
+exit:
+  if (NULL != con->response)
+    {
+      MHD_destroy_response (con->response);
+      con->response = NULL;
+    }
+  return NULL;
+}
+
+
+/**
+ * Callback for receiving data from the socket.
+ *
+ * @param connection the MHD connection structure
+ * @param other where to write received data to
+ * @param i maximum size of other (in bytes)
+ * @return number of bytes actually received
+ */
+static ssize_t
+recv_param_adapter (struct MHD_Connection *connection,
+                   void *other, 
+                   size_t i)
+{
+  if ( (-1 == connection->socket_fd) ||
+       (MHD_CONNECTION_CLOSED == connection->state) )
+    {
+      errno = ENOTCONN;
+      return -1;
+    }
+  if (0 != (connection->daemon->options & MHD_USE_SSL))
+    return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
+  return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
+}
+
+
+/**
+ * Callback for writing data to the socket.
+ *
+ * @param connection the MHD connection structure
+ * @param other data to write
+ * @param i number of bytes to write
+ * @return actual number of bytes written
+ */
+static ssize_t
+send_param_adapter (struct MHD_Connection *connection,
+                    const void *other,
+                   size_t i)
+{
+#if LINUX
+  int fd;
+  off_t offset;
+  off_t left;
+  ssize_t ret;
+#endif
+  if ( (-1 == connection->socket_fd) ||
+       (MHD_CONNECTION_CLOSED == connection->state) )
+    {
+      errno = ENOTCONN;
+      return -1;
+    }
+  if (0 != (connection->daemon->options & MHD_USE_SSL))
+    return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
+#if LINUX
+  if ( (connection->write_buffer_append_offset ==
+       connection->write_buffer_send_offset) &&
+       (NULL != connection->response) &&
+       (-1 != (fd = connection->response->fd)) )
+    {
+      /* can use sendfile */
+      offset = (off_t) connection->response_write_position + 
connection->response->fd_off;
+      left = connection->response->total_size - 
connection->response_write_position;
+      if (left > SSIZE_MAX)
+       left = SSIZE_MAX; /* cap at return value limit */
+      if (-1 != (ret = sendfile (connection->socket_fd, 
+                                fd,
+                                &offset,
+                                (size_t) left)))
+       return ret;
+      if ( (EINTR == errno) || (EAGAIN == errno) )
+       return 0;
+      if ( (EINVAL == errno) || (EBADF == errno) )
+       return -1; 
+      /* None of the 'usual' sendfile errors occurred, so we should try
+        to fall back to 'SEND'; see also this thread for info on
+        odd libc/Linux behavior with sendfile:
+        http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html 
*/
+    }
+#endif
+  return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
+}
+
+
+/**
+ * Signature of main function for a thread.
+ *
+ * @param cls closure argument for the function
+ * @return termination code from the thread
+ */
+typedef void *(*ThreadStartRoutine)(void *cls);
+
+
+/**
+ * Create a thread and set the attributes according to our options.
+ * 
+ * @param thread handle to initialize
+ * @param daemon daemon with options
+ * @param start_routine main function of thread
+ * @param arg argument for start_routine
+ * @return 0 on success
+ */
+static int
+create_thread (pthread_t *thread,
+              const struct MHD_Daemon *daemon,
+              ThreadStartRoutine start_routine,
+              void *arg)
+{
+  pthread_attr_t attr;
+  pthread_attr_t *pattr;
+  int ret;
+  
+  if (0 != daemon->thread_stack_size) 
+    {
+      if (0 != (ret = pthread_attr_init (&attr))) 
+       goto ERR;
+      if (0 != (ret = pthread_attr_setstacksize (&attr, 
daemon->thread_stack_size)))
+       {
+         pthread_attr_destroy (&attr);
+         goto ERR;
+       }
+      pattr = &attr;
+    }
+  else
+    {
+      pattr = NULL;
+    }
+  ret = pthread_create (thread, pattr,
+                       start_routine, arg);
+  if (0 != daemon->thread_stack_size) 
+    pthread_attr_destroy (&attr);
+  return ret;
+ ERR:
+#if HAVE_MESSAGES
+  MHD_DLOG (daemon,
+           "Failed to set thread stack size\n");
+#endif
+  errno = EINVAL;
+  return ret;
+}
+
+
+/**
+ * Add another client connection to the set of connections 
+ * managed by MHD.  This API is usually not needed (since
+ * MHD will accept inbound connections on the server socket).
+ * Use this API in special cases, for example if your HTTP
+ * server is behind NAT and needs to connect out to the 
+ * HTTP client.
+ *
+ * The given client socket will be managed (and closed!) by MHD after
+ * this call and must no longer be used directly by the application
+ * afterwards.
+ *
+ * Per-IP connection limits are ignored when using this API.
+ *
+ * @param daemon daemon that manages the connection
+ * @param client_socket socket to manage (MHD will expect
+ *        to receive an HTTP request from this socket next).
+ * @param addr IP address of the client
+ * @param addrlen number of bytes in addr
+ * @return MHD_YES on success, MHD_NO if this daemon could
+ *        not handle the connection (i.e. malloc failed, etc).
+ *        The socket will be closed in any case.
+ */
+int 
+MHD_add_connection (struct MHD_Daemon *daemon, 
+                   int client_socket,
+                   const struct sockaddr *addr,
+                   socklen_t addrlen)
+{
+  struct MHD_Connection *connection;
+  int res_thread_create;
+#if OSX
+  static int on = 1;
+#endif
+
+#ifndef WINDOWS
+  if ( (client_socket >= FD_SETSIZE) &&
+       (0 == (daemon->options & MHD_USE_POLL)) )
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
+               client_socket,
+               FD_SETSIZE);
+#endif
+      SHUTDOWN (client_socket, SHUT_RDWR);
+      CLOSE (client_socket);
+      return MHD_NO;
+    }
+#endif
+
+
+#if HAVE_MESSAGES
+#if DEBUG_CONNECT
+  MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
+#endif
+#endif
+  if ( (0 == daemon->max_connections) ||
+       (MHD_NO == MHD_ip_limit_add (daemon, addr, addrlen)) )
+    {
+      /* above connection limit - reject */
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+                "Server reached connection limit (closing inbound 
connection)\n");
+#endif
+      SHUTDOWN (client_socket, SHUT_RDWR);
+      CLOSE (client_socket);
+      return MHD_NO;
+    }
+
+  /* apply connection acceptance policy if present */
+  if ( (NULL != daemon->apc) && 
+       (MHD_NO == daemon->apc (daemon->apc_cls, 
+                              addr, addrlen)) )
+    {
+#if DEBUG_CLOSE
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, "Connection rejected, closing connection\n");
+#endif
+#endif
+      SHUTDOWN (client_socket, SHUT_RDWR);
+      CLOSE (client_socket);
+      MHD_ip_limit_del (daemon, addr, addrlen);
+      return MHD_YES;
+    }
+
+#if OSX
+#ifdef SOL_SOCKET
+#ifdef SO_NOSIGPIPE
+  setsockopt (client_socket, 
+             SOL_SOCKET, SO_NOSIGPIPE, 
+             &on, sizeof (on));
+#endif
+#endif
+#endif
+
+  if (NULL == (connection = malloc (sizeof (struct MHD_Connection))))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, 
+               "Error allocating memory: %s\n", 
+               STRERROR (errno));
+#endif
+      SHUTDOWN (client_socket, SHUT_RDWR);
+      CLOSE (client_socket);
+      MHD_ip_limit_del (daemon, addr, addrlen);
+      return MHD_NO;
+    }
+  memset (connection, 0, sizeof (struct MHD_Connection));
+  connection->connection_timeout = daemon->connection_timeout;
+  connection->pool = NULL;
+  if (NULL == (connection->addr = malloc (addrlen)))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, 
+               "Error allocating memory: %s\n", 
+               STRERROR (errno));
+#endif
+      SHUTDOWN (client_socket, SHUT_RDWR);
+      CLOSE (client_socket);
+      MHD_ip_limit_del (daemon, addr, addrlen);
+      free (connection);
+      return MHD_NO;
+    }
+  memcpy (connection->addr, addr, addrlen);
+  connection->addr_len = addrlen;
+  connection->socket_fd = client_socket;
+  connection->daemon = daemon;
+  connection->last_activity = MHD_monotonic_time();
+
+  /* set default connection handlers  */
+  MHD_set_http_callbacks_ (connection);
+  connection->recv_cls = &recv_param_adapter;
+  connection->send_cls = &send_param_adapter;
+  /* non-blocking sockets are required on most systems and for GNUtls;
+     however, they somehow cause serious problems on CYGWIN (#1824) */
+#ifdef CYGWIN
+  if (0 != (daemon->options & MHD_USE_SSL))
+#endif
+  {
+    /* make socket non-blocking */
+#ifndef MINGW
+    int flags = fcntl (connection->socket_fd, F_GETFL);
+    if ( (-1 == flags) ||
+        (0 != fcntl (connection->socket_fd, F_SETFL, flags | O_NONBLOCK)) )
+      {
+#if HAVE_MESSAGES
+       MHD_DLOG (daemon,
+                 "Failed to make socket %d non-blocking: %s\n", 
+                 connection->socket_fd,
+                 STRERROR (errno));
+#endif
+      }
+#else
+    unsigned long flags = 1;
+    if (0 != ioctlsocket (connection->socket_fd, FIONBIO, &flags))
+      {
+#if HAVE_MESSAGES
+       MHD_DLOG (daemon, 
+                 "Failed to make socket non-blocking: %s\n", 
+                 STRERROR (errno));
+#endif
+      }
+#endif
+  }
+
+#if HTTPS_SUPPORT
+  if (0 != (daemon->options & MHD_USE_SSL))
+    {
+      connection->recv_cls = &recv_tls_adapter;
+      connection->send_cls = &send_tls_adapter;
+      connection->state = MHD_TLS_CONNECTION_INIT;
+      MHD_set_https_callbacks (connection);
+      gnutls_init (&connection->tls_session, GNUTLS_SERVER);
+      gnutls_priority_set (connection->tls_session,
+                          daemon->priority_cache);
+      switch (daemon->cred_type)
+        {
+          /* set needed credentials for certificate authentication. */
+        case GNUTLS_CRD_CERTIFICATE:
+          gnutls_credentials_set (connection->tls_session,
+                                 GNUTLS_CRD_CERTIFICATE,
+                                 daemon->x509_cred);
+          break;
+        default:
+#if HAVE_MESSAGES
+          MHD_DLOG (connection->daemon,
+                    "Failed to setup TLS credentials: unknown credential type 
%d\n",
+                    daemon->cred_type);
+#endif
+          SHUTDOWN (client_socket, SHUT_RDWR);
+          CLOSE (client_socket);
+          MHD_ip_limit_del (daemon, addr, addrlen);
+          free (connection->addr);
+          free (connection);
+          MHD_PANIC ("Unknown credential type");
+         return MHD_NO;
+        }
+      gnutls_transport_set_ptr (connection->tls_session,
+                               (gnutls_transport_ptr_t) connection);
+      gnutls_transport_set_pull_function (connection->tls_session,
+                                         (gnutls_pull_func) 
&recv_param_adapter);
+      gnutls_transport_set_push_function (connection->tls_session,
+                                         (gnutls_push_func) 
&send_param_adapter);
+
+      if (daemon->https_mem_trust)
+         gnutls_certificate_server_set_request(connection->tls_session, 
GNUTLS_CERT_REQUEST);
+    }
+#endif
+
+  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
+    MHD_PANIC ("Failed to acquire cleanup mutex\n");    
+  DLL_insert (daemon->connections_head,
+             daemon->connections_tail,
+             connection);
+  if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
+    MHD_PANIC ("Failed to release cleanup mutex\n");    
+
+  /* attempt to create handler thread */
+  if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+    {
+      res_thread_create = create_thread (&connection->pid, daemon,
+                                        &MHD_handle_connection, connection);
+      if (0 != res_thread_create)
+        {
+#if HAVE_MESSAGES
+          MHD_DLOG (daemon, "Failed to create a thread: %s\n",
+                    STRERROR (res_thread_create));
+#endif
+          SHUTDOWN (client_socket, SHUT_RDWR);
+          CLOSE (client_socket);
+          MHD_ip_limit_del (daemon, addr, addrlen);
+         if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
+           {
+             MHD_PANIC ("Failed to acquire cleanup mutex\n");
+           }
+         DLL_remove (daemon->connections_head,
+                     daemon->connections_tail,
+                     connection);
+         if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
+           {
+             MHD_PANIC ("Failed to release cleanup mutex\n");
+           }
+          free (connection->addr);
+          free (connection);
+          return MHD_NO;
+        }
+    }
+  daemon->max_connections--;
+  return MHD_YES;  
+}
+
+
+/**
+ * Accept an incoming connection and create the MHD_Connection object for
+ * it.  This function also enforces policy by way of checking with the
+ * accept policy callback.
+ * 
+ * @param daemon handle with the listen socket
+ * @return MHD_YES on success
+ */
+static int
+MHD_accept_connection (struct MHD_Daemon *daemon)
+{
+#if HAVE_INET6
+  struct sockaddr_in6 addrstorage;
+#else
+  struct sockaddr_in addrstorage;
+#endif
+  struct sockaddr *addr = (struct sockaddr *) &addrstorage;
+  socklen_t addrlen;
+  int s;
+  int flags;
+  int need_fcntl;
+  int fd;
+
+  addrlen = sizeof (addrstorage);
+  memset (addr, 0, sizeof (addrstorage));
+  if (-1 == (fd = daemon->socket_fd))
+    return MHD_NO;
+#if HAVE_ACCEPT4
+  s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC);
+  need_fcntl = MHD_NO;
+#else
+  s = -1;
+  need_fcntl = MHD_YES;
+#endif
+  if (-1 == s)
+  {
+    s = ACCEPT (fd, addr, &addrlen);
+    need_fcntl = MHD_YES;
+  }
+  if ((-1 == s) || (addrlen <= 0))
+    {
+#if HAVE_MESSAGES
+      /* This could be a common occurance with multiple worker threads */
+      if ((EAGAIN != errno) && (EWOULDBLOCK != errno))
+        MHD_DLOG (daemon, 
+                 "Error accepting connection: %s\n", 
+                 STRERROR (errno));
+#endif
+      if (-1 != s)
+        {
+          SHUTDOWN (s, SHUT_RDWR);
+          CLOSE (s);
+          /* just in case */
+        }
+      return MHD_NO;
+    }
+  if (MHD_YES == need_fcntl)
+  {
+    /* make socket non-inheritable */
+#ifdef WINDOWS
+    DWORD dwFlags;
+    if (!GetHandleInformation ((HANDLE) s, &dwFlags) ||
+        ((dwFlags != dwFlags & ~HANDLE_FLAG_INHERIT) &&
+        !SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0)))
+      {
+#if HAVE_MESSAGES
+        SetErrnoFromWinError (GetLastError ());
+       MHD_DLOG (daemon,
+                 "Failed to make socket non-inheritable: %s\n", 
+                 STRERROR (errno));
+#endif
+      }
+#else
+    flags = fcntl (s, F_GETFD);
+    if ( ( (-1 == flags) ||
+          ( (flags != (flags | FD_CLOEXEC)) &&
+            (0 != fcntl (s, F_SETFD, flags | FD_CLOEXEC)) ) ) )
+      {
+#if HAVE_MESSAGES
+       MHD_DLOG (daemon,
+                 "Failed to make socket non-inheritable: %s\n", 
+                 STRERROR (errno));
+#endif
+      }
+#endif
+  }
+#if HAVE_MESSAGES
+#if DEBUG_CONNECT
+  MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
+#endif
+#endif
+  return MHD_add_connection (daemon, s,
+                            addr, addrlen);
+}
+
+
+/**
+ * Free resources associated with all closed connections.
+ * (destroy responses, free buffers, etc.).  All closed
+ * connections are kept in the "cleanup" doubly-linked list.
+ *
+ * @param daemon daemon to clean up
+ */
+static void
+MHD_cleanup_connections (struct MHD_Daemon *daemon)
+{
+  struct MHD_Connection *pos;
+  void *unused;
+  int rc;
+
+  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
+    {
+      MHD_PANIC ("Failed to acquire cleanup mutex\n");
+    }
+  while (NULL != (pos = daemon->cleanup_head))
+    {
+      DLL_remove (daemon->cleanup_head,
+                 daemon->cleanup_tail,
+                 pos);
+      if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+          (MHD_NO == pos->thread_joined) )
+       { 
+         if (0 != (rc = pthread_join (pos->pid, &unused)))
+           {
+             MHD_PANIC ("Failed to join a thread\n");
+           }
+       }
+      MHD_pool_destroy (pos->pool);
+#if HTTPS_SUPPORT
+      if (pos->tls_session != NULL)
+       gnutls_deinit (pos->tls_session);
+#endif
+      MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
+      if (NULL != pos->response)
+       {
+         MHD_destroy_response (pos->response);
+         pos->response = NULL;
+       }
+      if (-1 != pos->socket_fd)
+       CLOSE (pos->socket_fd);
+      if (NULL != pos->addr)
+       free (pos->addr);
+      free (pos);
+      daemon->max_connections++;
+    }
+  if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
+    {
+      MHD_PANIC ("Failed to release cleanup mutex\n");
+    }
+}
+
+
+/**
+ * Obtain timeout value for select for this daemon
+ * (only needed if connection timeout is used).  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 MHD_YES on success, MHD_NO if timeouts are
+ *        not used (or no connections exist that would
+ *        necessiate the use of a timeout right now).
+ */
+int
+MHD_get_timeout (struct MHD_Daemon *daemon,
+                MHD_UNSIGNED_LONG_LONG *timeout)
+{
+  time_t earliest_deadline;
+  time_t now;
+  struct MHD_Connection *pos;
+  int have_timeout;
+
+  if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, "Illegal call to MHD_get_timeout\n");
+#endif  
+      return MHD_NO;
+    }
+  have_timeout = MHD_NO;
+  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
+    {
+#if HTTPS_SUPPORT
+      if (MHD_YES == pos->tls_read_ready)
+       {
+         earliest_deadline = 0;
+         have_timeout = MHD_YES;
+         break;
+       }
+#endif
+      if (0 != pos->connection_timeout) 
+       {
+         if ( (! have_timeout) ||
+              (earliest_deadline > pos->last_activity + 
pos->connection_timeout) )
+           earliest_deadline = pos->last_activity + pos->connection_timeout;
+#if HTTPS_SUPPORT
+         if (  (0 != (daemon->options & MHD_USE_SSL)) &&
+               (0 != gnutls_record_check_pending (pos->tls_session)) )
+           earliest_deadline = 0;
+#endif
+         have_timeout = MHD_YES;
+       }
+    }
+  if (MHD_NO == have_timeout)
+    return MHD_NO;
+  now = MHD_monotonic_time();
+  if (earliest_deadline < now)
+    *timeout = 0;
+  else
+    *timeout = 1000 * (1 + earliest_deadline - now);
+  return MHD_YES;
+}
+
+
+/**
+ * Run webserver operations. This method should be called by clients
+ * in combination with MHD_get_fdset if the client-controlled select
+ * method is used.
+ *
+ * You can use this function instead of "MHD_run" if you called
+ * 'select' on the result from "MHD_get_fdset".  File descriptors in
+ * the sets that are not controlled by MHD will be ignored.  Calling
+ * this function instead of "MHD_run" is more efficient as MHD will
+ * not have to call 'select' again to determine which operations are
+ * ready.
+ *
+ * @param daemon daemon to run select loop for
+ * @param read_fd_set read set
+ * @param write_fd_set write set
+ * @param except_fd_set except set (not used, can be NULL)
+ * @return MHD_NO on serious errors, MHD_YES on success
+ */
+int
+MHD_run_from_select (struct MHD_Daemon *daemon, 
+                    const fd_set *read_fd_set,
+                    const fd_set *write_fd_set,
+                    const fd_set *except_fd_set)
+{
+  int ds;
+  int tmp;
+  struct MHD_Connection *pos;
+  struct MHD_Connection *next;
+
+  /* select connection thread handling type */
+  if ( (-1 != (ds = daemon->socket_fd)) &&
+       (FD_ISSET (ds, read_fd_set)) )
+    MHD_accept_connection (daemon);
+  /* drain signaling pipe to avoid spinning select */
+  if ( (-1 != daemon->wpipe[0]) &&
+       (FD_ISSET (daemon->wpipe[0], read_fd_set)) )
+    (void) read (daemon->wpipe[0], &tmp, sizeof (tmp));
+
+  if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+    {
+      /* do not have a thread per connection, process all connections now */
+      next = daemon->connections_head;
+      while (NULL != (pos = next))
+        {
+         next = pos->next;
+          ds = pos->socket_fd;
+          if (ds != -1)
+            {
+              if ( (FD_ISSET (ds, read_fd_set))
+#if HTTPS_SUPPORT
+                  || (MHD_YES == pos->tls_read_ready) 
+#endif
+                  )
+                pos->read_handler (pos);
+              if (FD_ISSET (ds, write_fd_set))
+                pos->write_handler (pos);
+             pos->idle_handler (pos);
+            }
+        }
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Main internal select call.  Will compute select sets, call 'select'
+ * and then MHD_run_from_select with the result.
+ *
+ * @param daemon daemon to run select loop for
+ * @param may_block YES if blocking, NO if non-blocking
+ * @return MHD_NO on serious errors, MHD_YES on success
+ */
+static int
+MHD_select (struct MHD_Daemon *daemon, 
+           int may_block)
+{
+  int num_ready;
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  int max;
+  struct timeval timeout;
+  struct timeval *tv;
+  MHD_UNSIGNED_LONG_LONG ltimeout;
+
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 0;
+  if (MHD_YES == daemon->shutdown)
+    return MHD_NO;
+  FD_ZERO (&rs);
+  FD_ZERO (&ws);
+  FD_ZERO (&es);
+  max = -1;
+  if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+    {
+      /* single-threaded, go over everything */
+      if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max))
+        return MHD_NO;
+
+      /* If we're at the connection limit, no need to
+         accept new connections. */
+      if ( (0 == daemon->max_connections) && 
+          (-1 != daemon->socket_fd) )
+        FD_CLR (daemon->socket_fd, &rs);
+    }
+  else
+    {
+      /* accept only, have one thread per connection */
+      if (-1 != daemon->socket_fd) 
+       {
+         max = daemon->socket_fd;
+         FD_SET (daemon->socket_fd, &rs);
+       }
+    }
+  if (-1 != daemon->wpipe[0])
+    {
+      FD_SET (daemon->wpipe[0], &rs);
+      /* update max file descriptor */
+      if (max < daemon->wpipe[0])
+       max = daemon->wpipe[0];
+    }
+
+  tv = NULL;
+  if (MHD_NO == may_block)
+    {
+      timeout.tv_usec = 0;
+      timeout.tv_sec = 0;
+      tv = &timeout;
+    }
+  else if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+           (MHD_YES == MHD_get_timeout (daemon, &ltimeout)) )
+    {
+      /* ltimeout is in ms */
+      timeout.tv_usec = (ltimeout % 1000) * 1000;
+      timeout.tv_sec = ltimeout / 1000;
+      tv = &timeout;
+    }
+  if (-1 == max)
+    return MHD_YES;
+  num_ready = SELECT (max + 1, &rs, &ws, &es, tv);
+  if (MHD_YES == daemon->shutdown)
+    return MHD_NO;
+  if (num_ready < 0)
+    {
+      if (EINTR == errno)
+        return MHD_YES;
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno));
+#endif
+      return MHD_NO;
+    }
+  return MHD_run_from_select (daemon, &rs, &ws, &es);
+}
+
+
+#ifdef HAVE_POLL_H
+/**
+ * Process all of our connections and possibly the server
+ * socket using 'poll'.
+ *
+ * @param daemon daemon to run poll loop for
+ * @param may_block YES if blocking, NO if non-blocking
+ * @return MHD_NO on serious errors, MHD_YES on success
+ */
+static int
+MHD_poll_all (struct MHD_Daemon *daemon,
+             int may_block)
+{
+  unsigned int num_connections;
+  struct MHD_Connection *pos;
+  struct MHD_Connection *next;
+
+  /* count number of connections and thus determine poll set size */
+  num_connections = 0;
+  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
+    num_connections++;
+
+  {
+    struct pollfd p[2 + num_connections];
+    struct MHD_Pollfd mp;
+    MHD_UNSIGNED_LONG_LONG ltimeout;
+    unsigned int i;
+    int timeout;
+    unsigned int poll_server;
+    int poll_listen;
+    
+    memset (p, 0, sizeof (p));
+    poll_server = 0;
+    poll_listen = -1;
+    if ( (-1 != daemon->socket_fd) &&
+        (0 != daemon->max_connections) )
+      {
+       /* only listen if we are not at the connection limit */
+       p[poll_server].fd = daemon->socket_fd;
+       p[poll_server].events = POLLIN;
+       p[poll_server].revents = 0;
+       poll_listen = (int) poll_server;
+       poll_server++;
+      }
+    if (-1 != daemon->wpipe[0]) 
+      {
+       p[poll_server].fd = daemon->wpipe[0];
+       p[poll_server].events = POLLIN;
+       p[poll_server].revents = 0;
+       poll_server++;
+      }
+    if (may_block == MHD_NO)
+      timeout = 0;
+    else if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
+             (MHD_YES != MHD_get_timeout (daemon, &ltimeout)) )
+      timeout = -1;
+    else
+      timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout;
+    
+    i = 0;
+    for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
+      {
+       memset(&mp, 0, sizeof (struct MHD_Pollfd));
+       MHD_connection_get_pollfd (pos, &mp);
+       p[poll_server+i].fd = mp.fd;
+       if (mp.events & MHD_POLL_ACTION_IN) 
+         p[poll_server+i].events |= POLLIN;        
+       if (mp.events & MHD_POLL_ACTION_OUT) 
+         p[poll_server+i].events |= POLLOUT;
+       i++;
+      }
+    if (0 == poll_server + num_connections)
+      return MHD_YES;
+    if (poll (p, poll_server + num_connections, timeout) < 0) 
+      {
+       if (EINTR == errno)
+         return MHD_YES;
+#if HAVE_MESSAGES
+       MHD_DLOG (daemon, 
+                 "poll failed: %s\n", 
+                 STRERROR (errno));
+#endif
+       return MHD_NO;
+      }
+    /* handle shutdown */
+    if (MHD_YES == daemon->shutdown)
+      return MHD_NO;  
+    i = 0;
+    next = daemon->connections_head;
+    while (NULL != (pos = next))
+      {
+       next = pos->next;
+       /* first, sanity checks */
+       if (i >= num_connections)
+         break; /* connection list changed somehow, retry later ... */
+       MHD_connection_get_pollfd (pos, &mp);
+       if (p[poll_server+i].fd != mp.fd)
+         break; /* fd mismatch, something else happened, retry later ... */
+
+       /* normal handling */
+       if (0 != (p[poll_server+i].revents & POLLIN)) 
+         pos->read_handler (pos);
+       if (0 != (p[poll_server+i].revents & POLLOUT)) 
+         pos->write_handler (pos);     
+       pos->idle_handler (pos);
+       i++;
+      }
+    if ( (-1 != poll_listen) &&
+        (0 != (p[poll_listen].revents & POLLIN)) )
+      MHD_accept_connection (daemon);
+  }
+  return MHD_YES;
+}
+
+
+/**
+ * Process only the listen socket using 'poll'.
+ *
+ * @param daemon daemon to run poll loop for
+ * @param may_block YES if blocking, NO if non-blocking
+ * @return MHD_NO on serious errors, MHD_YES on success
+ */
+static int
+MHD_poll_listen_socket (struct MHD_Daemon *daemon,
+                       int may_block)
+{
+  struct pollfd p[2];
+  int timeout;
+  unsigned int poll_count;
+  int poll_listen;
+    
+  memset (&p, 0, sizeof (p));
+  poll_count = 0;
+  poll_listen = -1;
+  if (-1 != daemon->socket_fd)
+    {
+      p[poll_count].fd = daemon->socket_fd;
+      p[poll_count].events = POLLIN;
+      p[poll_count].revents = 0;
+      poll_listen = poll_count;
+      poll_count++;
+    }
+  if (-1 != daemon->wpipe[0])
+    {
+      p[poll_count].fd = daemon->wpipe[0];
+      p[poll_count].events = POLLIN;
+      p[poll_count].revents = 0;
+      poll_count++;
+    }
+  if (MHD_NO == may_block)
+    timeout = 0;
+  else
+    timeout = -1;
+  if (0 == poll_count)
+    return MHD_YES;
+  if (poll (p, poll_count, timeout) < 0)
+    {
+      if (EINTR == errno)
+       return MHD_YES;
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno));
+#endif
+      return MHD_NO;
+    }
+  /* handle shutdown */
+  if (MHD_YES == daemon->shutdown)
+    return MHD_NO;  
+  if ( (-1 != poll_listen) &&
+       (0 != (p[poll_listen].revents & POLLIN)) )
+    MHD_accept_connection (daemon);  
+  return MHD_YES;
+}
+#endif
+
+
+/**
+ * Do 'poll'-based processing.
+ *
+ * @param daemon daemon to run poll loop for
+ * @param may_block YES if blocking, NO if non-blocking
+ * @return MHD_NO on serious errors, MHD_YES on success
+ */
+static int
+MHD_poll (struct MHD_Daemon *daemon,
+         int may_block)
+{
+#ifdef HAVE_POLL_H
+  if (MHD_YES == daemon->shutdown)
+    return MHD_NO;
+  if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+    return MHD_poll_all (daemon, may_block);
+  else
+    return MHD_poll_listen_socket (daemon, may_block);
+#else
+  return MHD_NO;
+#endif
+}
+
+
+/**
+ * Run webserver operations (without blocking unless
+ * in client callbacks).  This method should be called
+ * by clients in combination with MHD_get_fdset
+ * if the client-controlled select method is used.
+ *
+ * This function will work for external 'poll' and 'select' mode.
+ * However, if using external 'select' mode, you may want to
+ * instead use 'MHD_run_from_select', as it is more efficient.
+ *
+ * @return MHD_YES on success, MHD_NO if this
+ *         daemon was not started with the right
+ *         options for this call.
+ */
+int
+MHD_run (struct MHD_Daemon *daemon)
+{
+  if ( (MHD_YES == daemon->shutdown) || 
+       (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
+       (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) )
+    return MHD_NO;
+  if (0 == (daemon->options & MHD_USE_POLL)) 
+    MHD_select (daemon, MHD_NO);    
+  else    
+    MHD_poll (daemon, MHD_NO);    
+  MHD_cleanup_connections (daemon);
+  return MHD_YES;
+}
+
+
+/**
+ * Thread that runs the select loop until the daemon
+ * is explicitly shut down.
+ *
+ * @param cls 'struct MHD_Deamon' to run select loop in a thread for
+ * @return always NULL (on shutdown)
+ */
+static void *
+MHD_select_thread (void *cls)
+{
+  struct MHD_Daemon *daemon = cls;
+
+  while (MHD_YES != daemon->shutdown)
+    {
+      if (0 == (daemon->options & MHD_USE_POLL)) 
+       MHD_select (daemon, MHD_YES);
+      else 
+       MHD_poll (daemon, MHD_YES);      
+      MHD_cleanup_connections (daemon);
+    }
+  return NULL;
+}
+
+
+/**
+ * Start a webserver on the given port.
+ *
+ * @param flags combination of MHD_FLAG values
+ * @param port port to bind to
+ * @param apc callback to call to check which clients
+ *        will be allowed to connect
+ * @param apc_cls extra argument to apc
+ * @param dh default handler for all URIs
+ * @param dh_cls extra argument to dh
+ * @return NULL on error, handle to daemon on success
+ */
+struct MHD_Daemon *
+MHD_start_daemon (unsigned int flags,
+                  uint16_t port,
+                  MHD_AcceptPolicyCallback apc,
+                  void *apc_cls,
+                  MHD_AccessHandlerCallback dh, void *dh_cls, ...)
+{
+  struct MHD_Daemon *daemon;
+  va_list ap;
+
+  va_start (ap, dh_cls);
+  daemon = MHD_start_daemon_va (flags, port, apc, apc_cls, dh, dh_cls, ap);
+  va_end (ap);
+  return daemon;
+}
+
+
+/**
+ * Stop accepting connections from the listening socket.  Allows
+ * clients to continue processing, but stops accepting new
+ * connections.  Note that the caller is responsible for closing the
+ * returned socket; however, if MHD is run using threads (anything but
+ * external select mode), it must not be closed until AFTER
+ * "MHD_stop_daemon" has been called (as it is theoretically possible
+ * that an existing thread is still using it).
+ *
+ * @param daemon daemon to stop accepting new connections for
+ * @return old listen socket on success, -1 if the daemon was 
+ *         already not listening anymore
+ */
+int
+MHD_quiesce_daemon (struct MHD_Daemon *daemon)
+{
+  unsigned int i;
+  int ret;
+
+  ret = daemon->socket_fd;
+  if (NULL != daemon->worker_pool)
+    for (i = 0; i < daemon->worker_pool_size; i++)        
+      daemon->worker_pool[i].socket_fd = -1;    
+  daemon->socket_fd = -1;
+  return ret;
+}
+
+
+/**
+ * Signature of the MHD custom logger function.
+ *
+ * @param cls closure
+ * @param format format string
+ * @param va arguments to the format string (fprintf-style)
+ */
+typedef void (*VfprintfFunctionPointerType)(void *cls,
+                                           const char *format, 
+                                           va_list va);
+
+
+/**
+ * Parse a list of options given as varargs.
+ * 
+ * @param daemon the daemon to initialize
+ * @param servaddr where to store the server's listen address
+ * @param ap the options
+ * @return MHD_YES on success, MHD_NO on error
+ */
+static int
+parse_options_va (struct MHD_Daemon *daemon,
+                 const struct sockaddr **servaddr,
+                 va_list ap);
+
+
+/**
+ * Parse a list of options given as varargs.
+ * 
+ * @param daemon the daemon to initialize
+ * @param servaddr where to store the server's listen address
+ * @param ... the options
+ * @return MHD_YES on success, MHD_NO on error
+ */
+static int
+parse_options (struct MHD_Daemon *daemon,
+              const struct sockaddr **servaddr,
+              ...)
+{
+  va_list ap;
+  int ret;
+
+  va_start (ap, servaddr);
+  ret = parse_options_va (daemon, servaddr, ap);
+  va_end (ap);
+  return ret;
+}
+
+
+/**
+ * Parse a list of options given as varargs.
+ * 
+ * @param daemon the daemon to initialize
+ * @param servaddr where to store the server's listen address
+ * @param ap the options
+ * @return MHD_YES on success, MHD_NO on error
+ */
+static int
+parse_options_va (struct MHD_Daemon *daemon,
+                 const struct sockaddr **servaddr,
+                 va_list ap)
+{
+  enum MHD_OPTION opt;
+  struct MHD_OptionItem *oa;
+  unsigned int i;
+#if HTTPS_SUPPORT
+  int ret;
+  const char *pstr;
+#endif
+  
+  while (MHD_OPTION_END != (opt = (enum MHD_OPTION) va_arg (ap, int)))
+    {
+      switch (opt)
+        {
+        case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
+          daemon->pool_size = va_arg (ap, size_t);
+          break;
+        case MHD_OPTION_CONNECTION_LIMIT:
+          daemon->max_connections = va_arg (ap, unsigned int);
+          break;
+        case MHD_OPTION_CONNECTION_TIMEOUT:
+          daemon->connection_timeout = va_arg (ap, unsigned int);
+          break;
+        case MHD_OPTION_NOTIFY_COMPLETED:
+          daemon->notify_completed =
+            va_arg (ap, MHD_RequestCompletedCallback);
+          daemon->notify_completed_cls = va_arg (ap, void *);
+          break;
+        case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
+          daemon->per_ip_connection_limit = va_arg (ap, unsigned int);
+          break;
+        case MHD_OPTION_SOCK_ADDR:
+          *servaddr = va_arg (ap, const struct sockaddr *);
+          break;
+        case MHD_OPTION_URI_LOG_CALLBACK:
+          daemon->uri_log_callback =
+            va_arg (ap, LogCallback);
+          daemon->uri_log_callback_cls = va_arg (ap, void *);
+          break;
+        case MHD_OPTION_THREAD_POOL_SIZE:
+          daemon->worker_pool_size = va_arg (ap, unsigned int);
+         if (daemon->worker_pool_size >= (SIZE_MAX / sizeof (struct 
MHD_Daemon)))
+           {
+#if HAVE_MESSAGES
+             MHD_DLOG (daemon,
+                       "Specified thread pool size (%u) too big\n",
+                       daemon->worker_pool_size);
+#endif
+             return MHD_NO;
+           }
+          break;
+#if HTTPS_SUPPORT
+        case MHD_OPTION_HTTPS_MEM_KEY:
+         if (0 != (daemon->options & MHD_USE_SSL))
+           daemon->https_mem_key = va_arg (ap, const char *);
+#if HAVE_MESSAGES
+         else
+           MHD_DLOG (daemon,
+                     "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not 
set\n",
+                     opt);       
+#endif
+          break;
+        case MHD_OPTION_HTTPS_MEM_CERT:
+         if (0 != (daemon->options & MHD_USE_SSL))
+           daemon->https_mem_cert = va_arg (ap, const char *);
+#if HAVE_MESSAGES
+         else
+           MHD_DLOG (daemon,
+                     "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not 
set\n",
+                     opt);       
+#endif
+          break;
+        case MHD_OPTION_HTTPS_MEM_TRUST:
+         if (0 != (daemon->options & MHD_USE_SSL))
+           daemon->https_mem_trust = va_arg (ap, const char *);
+#if HAVE_MESSAGES
+         else
+           MHD_DLOG (daemon,
+                     "MHD HTTPS option %d passed to MHD but MHD_USE_SSL not 
set\n",
+                     opt);
+#endif
+          break;
+       case MHD_OPTION_HTTPS_CRED_TYPE:
+         daemon->cred_type = (gnutls_credentials_type_t) va_arg (ap, int);
+         break;
+        case MHD_OPTION_HTTPS_PRIORITIES:
+         if (0 != (daemon->options & MHD_USE_SSL))
+           {
+             gnutls_priority_deinit (daemon->priority_cache);
+             ret = gnutls_priority_init (&daemon->priority_cache,
+                                         pstr = va_arg (ap, const char*),
+                                         NULL);
+             if (ret != GNUTLS_E_SUCCESS)
+             {
+#if HAVE_MESSAGES
+               MHD_DLOG (daemon,
+                         "Setting priorities to `%s' failed: %s\n",
+                         pstr,
+                         gnutls_strerror (ret));
+#endif   
+               daemon->priority_cache = NULL;
+               return MHD_NO;
+             }
+           }
+          break;
+#endif
+#ifdef DAUTH_SUPPORT
+       case MHD_OPTION_DIGEST_AUTH_RANDOM:
+         daemon->digest_auth_rand_size = va_arg (ap, size_t);
+         daemon->digest_auth_random = va_arg (ap, const char *);
+         break;
+       case MHD_OPTION_NONCE_NC_SIZE:
+         daemon->nonce_nc_size = va_arg (ap, unsigned int);
+         break;
+#endif
+       case MHD_OPTION_LISTEN_SOCKET:
+         daemon->socket_fd = va_arg (ap, int);   
+         break;
+        case MHD_OPTION_EXTERNAL_LOGGER:
+#if HAVE_MESSAGES
+          daemon->custom_error_log =
+            va_arg (ap, VfprintfFunctionPointerType);
+          daemon->custom_error_log_cls = va_arg (ap, void *);
+#else
+          va_arg (ap, VfprintfFunctionPointerType);
+          va_arg (ap, void *);
+#endif
+          break;
+        case MHD_OPTION_THREAD_STACK_SIZE:
+          daemon->thread_stack_size = va_arg (ap, size_t);
+          break;
+       case MHD_OPTION_ARRAY:
+         oa = va_arg (ap, struct MHD_OptionItem*);
+         i = 0;
+         while (MHD_OPTION_END != (opt = oa[i].option))
+           {
+             switch (opt)
+               {
+                 /* all options taking 'size_t' */
+               case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
+               case MHD_OPTION_THREAD_STACK_SIZE:
+                 if (MHD_YES != parse_options (daemon,
+                                               servaddr,
+                                               opt,
+                                               (size_t) oa[i].value,
+                                               MHD_OPTION_END))
+                   return MHD_NO;
+                 break;
+                 /* all options taking 'unsigned int' */
+               case MHD_OPTION_NONCE_NC_SIZE:
+               case MHD_OPTION_CONNECTION_LIMIT:
+               case MHD_OPTION_CONNECTION_TIMEOUT:
+               case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
+               case MHD_OPTION_THREAD_POOL_SIZE:
+                 if (MHD_YES != parse_options (daemon,
+                                               servaddr,
+                                               opt,
+                                               (unsigned int) oa[i].value,
+                                               MHD_OPTION_END))
+                   return MHD_NO;
+                 break;
+                 /* all options taking 'int' or 'enum' */
+               case MHD_OPTION_HTTPS_CRED_TYPE:
+               case MHD_OPTION_LISTEN_SOCKET:
+                 if (MHD_YES != parse_options (daemon,
+                                               servaddr,
+                                               opt,
+                                               (int) oa[i].value,
+                                               MHD_OPTION_END))
+                   return MHD_NO;
+                 break;
+                 /* all options taking one pointer */
+               case MHD_OPTION_SOCK_ADDR:
+               case MHD_OPTION_HTTPS_MEM_KEY:
+               case MHD_OPTION_HTTPS_MEM_CERT:
+               case MHD_OPTION_HTTPS_MEM_TRUST:
+               case MHD_OPTION_HTTPS_PRIORITIES:
+               case MHD_OPTION_ARRAY:
+                 if (MHD_YES != parse_options (daemon,
+                                               servaddr,
+                                               opt,
+                                               oa[i].ptr_value,
+                                               MHD_OPTION_END))
+                   return MHD_NO;
+                 break;
+                 /* all options taking two pointers */
+               case MHD_OPTION_NOTIFY_COMPLETED:
+               case MHD_OPTION_URI_LOG_CALLBACK:
+               case MHD_OPTION_EXTERNAL_LOGGER:
+               case MHD_OPTION_UNESCAPE_CALLBACK:
+                 if (MHD_YES != parse_options (daemon,
+                                               servaddr,
+                                               opt,
+                                               (void *) oa[i].value,
+                                               oa[i].ptr_value,
+                                               MHD_OPTION_END))
+                   return MHD_NO;
+                 break;
+                 /* options taking size_t-number followed by pointer */
+               case MHD_OPTION_DIGEST_AUTH_RANDOM:
+                 if (MHD_YES != parse_options (daemon,
+                                               servaddr,
+                                               opt,
+                                               (size_t) oa[i].value,
+                                               oa[i].ptr_value,
+                                               MHD_OPTION_END))
+                   return MHD_NO;
+                 break;
+               default:
+                 return MHD_NO;
+               }
+             i++;
+           }
+         break;
+        case MHD_OPTION_UNESCAPE_CALLBACK:
+          daemon->unescape_callback =
+            va_arg (ap, UnescapeCallback);
+          daemon->unescape_callback_cls = va_arg (ap, void *);
+          break;
+        default:
+#if HAVE_MESSAGES
+          if (((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
+              (opt <= MHD_OPTION_HTTPS_PRIORITIES)) || (opt == 
MHD_OPTION_HTTPS_MEM_TRUST))
+            {
+              MHD_DLOG (daemon,
+                       "MHD HTTPS option %d passed to MHD compiled without 
HTTPS support\n",
+                       opt);
+            }
+          else
+            {
+              MHD_DLOG (daemon,
+                       "Invalid option %d! (Did you terminate the list with 
MHD_OPTION_END?)\n",
+                       opt);
+            }
+#endif
+         return MHD_NO;
+        }
+    }  
+  return MHD_YES;
+}
+
+
+/**
+ * Create a listen socket, if possible with CLOEXEC flag set.
+ *
+ * @param domain socket domain (i.e. PF_INET)
+ * @param type socket type (usually SOCK_STREAM)
+ * @param protocol desired protocol, 0 for default
+ */
+static int
+create_socket (int domain, int type, int protocol)
+{
+  static int sock_cloexec = SOCK_CLOEXEC;
+  int ctype = SOCK_STREAM | sock_cloexec;
+  int fd;
+  int flags;
+#ifdef WINDOWS
+  DWORD dwFlags;
+#endif
+ 
+  /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo
+   * implementations do not set ai_socktype, e.g. RHL6.2. */
+  fd = SOCKET (domain, ctype, protocol);
+  if ( (-1 == fd) && (EINVAL == errno) && (0 != sock_cloexec) )
+  {
+    sock_cloexec = 0;
+    fd = SOCKET(domain, type, protocol);
+  }
+  if (-1 == fd)
+    return -1;
+  if (0 != sock_cloexec)
+    return fd; /* this is it */  
+  /* flag was not set during 'socket' call, let's try setting it manually */
+#ifndef WINDOWS
+  flags = fcntl (fd, F_GETFD);
+  if (flags < 0)
+#else
+  if (!GetHandleInformation ((HANDLE) fd, &dwFlags))
+#endif
+  {
+#ifdef WINDOWS
+    SetErrnoFromWinError (GetLastError ());
+#endif
+    return fd; /* good luck */
+  }
+#ifndef WINDOWS
+  if (flags == (flags | FD_CLOEXEC))
+    return fd; /* already set */
+  flags |= FD_CLOEXEC;
+  if (0 != fcntl (fd, F_SETFD, flags))
+#else
+  if (dwFlags != (dwFlags | HANDLE_FLAG_INHERIT))
+    return fd; /* already unset */
+  if (!SetHandleInformation ((HANDLE) fd, HANDLE_FLAG_INHERIT, 0))
+#endif
+  {
+#ifdef WINDOWS
+    SetErrnoFromWinError (GetLastError ());
+#endif
+    return fd; /* good luck */
+  }
+  return fd;
+}
+
+
+/**
+ * Start a webserver on the given port.
+ *
+ * @param flags combination of MHD_FLAG values
+ * @param port port to bind to
+ * @param apc callback to call to check which clients
+ *        will be allowed to connect
+ * @param apc_cls extra argument to apc
+ * @param dh default handler for all URIs
+ * @param dh_cls extra argument to dh
+ * @param ap list of options (type-value pairs,
+ *        terminated with MHD_OPTION_END).
+ * @return NULL on error, handle to daemon on success
+ */
+struct MHD_Daemon *
+MHD_start_daemon_va (unsigned int flags,
+                     uint16_t port,
+                     MHD_AcceptPolicyCallback apc,
+                     void *apc_cls,
+                     MHD_AccessHandlerCallback dh, void *dh_cls,
+                    va_list ap)
+{
+  const int on = 1;
+  struct MHD_Daemon *daemon;
+  int socket_fd;
+  struct sockaddr_in servaddr4;
+#if HAVE_INET6
+  struct sockaddr_in6 servaddr6;
+#endif
+  const struct sockaddr *servaddr = NULL;
+  socklen_t addrlen;
+  unsigned int i;
+  int res_thread_create;
+  int use_pipe;
+
+#ifndef HAVE_INET6
+  if (0 != (flags & MHD_USE_IPv6))
+    return NULL;    
+#endif
+#ifndef HAVE_POLL_H
+  if (0 != (flags & MHD_USE_POLL))
+    return NULL;    
+#endif
+#if ! HTTPS_SUPPORT
+  if (0 != (flags & MHD_USE_SSL))
+    return NULL;    
+#endif
+  if (NULL == dh)
+    return NULL;
+  if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon))))
+    return NULL;
+  memset (daemon, 0, sizeof (struct MHD_Daemon));
+  /* try to open listen socket */
+#if HTTPS_SUPPORT
+  if (0 != (flags & MHD_USE_SSL))
+    {
+      gnutls_priority_init (&daemon->priority_cache,
+                           "NORMAL",
+                           NULL);
+    }
+#endif
+  daemon->socket_fd = -1;
+  daemon->options = (enum MHD_OPTION) flags;
+  daemon->port = port;
+  daemon->apc = apc;
+  daemon->apc_cls = apc_cls;
+  daemon->default_handler = dh;
+  daemon->default_handler_cls = dh_cls;
+  daemon->max_connections = MHD_MAX_CONNECTIONS_DEFAULT;
+  daemon->pool_size = MHD_POOL_SIZE_DEFAULT;
+  daemon->unescape_callback = &MHD_http_unescape;
+  daemon->connection_timeout = 0;       /* no timeout */
+  daemon->wpipe[0] = -1;
+  daemon->wpipe[1] = -1;
+#if HAVE_MESSAGES
+  daemon->custom_error_log = (MHD_LogCallback) &vfprintf;
+  daemon->custom_error_log_cls = stderr;
+#endif
+#ifdef HAVE_LISTEN_SHUTDOWN
+  use_pipe = (0 != (daemon->options & MHD_USE_NO_LISTEN_SOCKET));
+#else
+  use_pipe = 1; /* yes, must use pipe to signal shutdown */
+#endif
+  if ( (use_pipe) &&
+       (0 != PIPE (daemon->wpipe)) )
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, 
+               "Failed to create control pipe: %s\n",
+               STRERROR (errno));
+#endif
+      free (daemon);
+      return NULL;
+    }
+#ifndef WINDOWS
+  if ( (0 == (flags & MHD_USE_POLL)) &&
+       (daemon->wpipe[0] >= FD_SETSIZE) )
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, 
+               "file descriptor for control pipe exceeds maximum value\n");
+#endif
+      CLOSE (daemon->wpipe[0]);
+      CLOSE (daemon->wpipe[1]);
+      free (daemon);
+      return NULL;
+    }
+#endif
+#ifdef DAUTH_SUPPORT
+  daemon->digest_auth_rand_size = 0;
+  daemon->digest_auth_random = NULL;
+  daemon->nonce_nc_size = 4; /* tiny */
+#endif
+#if HTTPS_SUPPORT
+  if (0 != (flags & MHD_USE_SSL))
+    {
+      daemon->cred_type = GNUTLS_CRD_CERTIFICATE;
+    }
+#endif
+
+
+  if (MHD_YES != parse_options_va (daemon, &servaddr, ap))
+    {
+#if HTTPS_SUPPORT
+      if ( (0 != (flags & MHD_USE_SSL)) &&
+          (NULL != daemon->priority_cache) )
+       gnutls_priority_deinit (daemon->priority_cache);
+#endif
+      free (daemon);
+      return NULL;
+    }
+#ifdef DAUTH_SUPPORT
+  if (daemon->nonce_nc_size > 0) 
+    {
+      if ( ( (size_t) (daemon->nonce_nc_size * sizeof(struct MHD_NonceNc))) / 
+          sizeof(struct MHD_NonceNc) != daemon->nonce_nc_size)
+       {
+#if HAVE_MESSAGES
+         MHD_DLOG (daemon,
+                   "Specified value for NC_SIZE too large\n");
+#endif
+#if HTTPS_SUPPORT
+         if (0 != (flags & MHD_USE_SSL))
+           gnutls_priority_deinit (daemon->priority_cache);
+#endif
+         free (daemon);
+         return NULL;    
+       }
+      daemon->nnc = malloc (daemon->nonce_nc_size * sizeof(struct 
MHD_NonceNc));
+      if (NULL == daemon->nnc)
+       {
+#if HAVE_MESSAGES
+         MHD_DLOG (daemon,
+                   "Failed to allocate memory for nonce-nc map: %s\n",
+                   STRERROR (errno));
+#endif
+#if HTTPS_SUPPORT
+         if (0 != (flags & MHD_USE_SSL))
+           gnutls_priority_deinit (daemon->priority_cache);
+#endif
+         free (daemon);
+         return NULL;
+       }
+    }
+  
+  if (0 != pthread_mutex_init (&daemon->nnc_lock, NULL))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "MHD failed to initialize nonce-nc mutex\n");
+#endif
+#if HTTPS_SUPPORT
+      if (0 != (flags & MHD_USE_SSL))
+       gnutls_priority_deinit (daemon->priority_cache);
+#endif
+      free (daemon->nnc);
+      free (daemon);
+      return NULL;
+    }
+#endif
+
+  /* Thread pooling currently works only with internal select thread model */
+  if ( (0 == (flags & MHD_USE_SELECT_INTERNALLY)) && 
+       (daemon->worker_pool_size > 0) )
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "MHD thread pooling only works with 
MHD_USE_SELECT_INTERNALLY\n");
+#endif
+      goto free_and_fail;
+    }
+
+#ifdef __SYMBIAN32__
+  if (0 != (flags & (MHD_USE_SELECT_INTERNALLY | 
MHD_USE_THREAD_PER_CONNECTION)))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "Threaded operations are not supported on Symbian.\n");
+#endif
+      goto free_and_fail;
+    }
+#endif
+  if ( (-1 == daemon->socket_fd) &&
+       (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
+    {
+      /* try to open listen socket */
+      if ((flags & MHD_USE_IPv6) != 0)
+       socket_fd = create_socket (PF_INET6, SOCK_STREAM, 0);
+      else
+       socket_fd = create_socket (PF_INET, SOCK_STREAM, 0);
+      if (-1 == socket_fd)
+       {
+#if HAVE_MESSAGES
+         if (0 != (flags & MHD_USE_DEBUG))
+           MHD_DLOG (daemon, 
+                     "Call to socket failed: %s\n", 
+                     STRERROR (errno));
+#endif
+         goto free_and_fail;
+       }
+      if ((SETSOCKOPT (socket_fd,
+                      SOL_SOCKET,
+                      SO_REUSEADDR,
+                      &on, sizeof (on)) < 0) && ((flags & MHD_USE_DEBUG) != 0))
+       {
+#if HAVE_MESSAGES
+         MHD_DLOG (daemon, 
+                   "setsockopt failed: %s\n", 
+                   STRERROR (errno));
+#endif
+       }
+      
+      /* check for user supplied sockaddr */
+#if HAVE_INET6
+      if (0 != (flags & MHD_USE_IPv6))
+       addrlen = sizeof (struct sockaddr_in6);
+      else
+#endif
+       addrlen = sizeof (struct sockaddr_in);
+      if (NULL == servaddr)
+       {
+#if HAVE_INET6
+         if (0 != (flags & MHD_USE_IPv6))
+           {
+             memset (&servaddr6, 0, sizeof (struct sockaddr_in6));
+             servaddr6.sin6_family = AF_INET6;
+             servaddr6.sin6_port = htons (port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+             servaddr6.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+             servaddr = (struct sockaddr *) &servaddr6;
+           }
+         else
+#endif
+           {
+             memset (&servaddr4, 0, sizeof (struct sockaddr_in));
+             servaddr4.sin_family = AF_INET;
+             servaddr4.sin_port = htons (port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+             servaddr4.sin_len = sizeof (struct sockaddr_in);
+#endif
+             servaddr = (struct sockaddr *) &servaddr4;
+           }
+       }
+      daemon->socket_fd = socket_fd;
+
+      if (0 != (flags & MHD_USE_IPv6))
+       {
+#ifdef IPPROTO_IPV6
+#ifdef IPV6_V6ONLY
+         /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see 
"IPPROTO_IPV6 Socket Options" 
+            
(http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx); 
+            and may also be missing on older POSIX systems; good luck if you 
have any of those,
+            your IPv6 socket may then also bind against IPv4... */
+#ifndef WINDOWS
+         const int on = 1;
+         setsockopt (socket_fd, 
+                     IPPROTO_IPV6, IPV6_V6ONLY, 
+                     &on, sizeof (on));
+#else
+         const char on = 1;
+         setsockopt (socket_fd, 
+                     IPPROTO_IPV6, IPV6_V6ONLY, 
+                     &on, sizeof (on));
+#endif
+#endif
+#endif
+       }
+      if (-1 == BIND (socket_fd, servaddr, addrlen))
+       {
+#if HAVE_MESSAGES
+         if (0 != (flags & MHD_USE_DEBUG))
+           MHD_DLOG (daemon,
+                     "Failed to bind to port %u: %s\n", 
+                     (unsigned int) port, 
+                     STRERROR (errno));
+#endif
+         CLOSE (socket_fd);
+         goto free_and_fail;
+       }
+      
+      if (LISTEN (socket_fd, 20) < 0)
+       {
+#if HAVE_MESSAGES
+         if (0 != (flags & MHD_USE_DEBUG))
+           MHD_DLOG (daemon,
+                     "Failed to listen for connections: %s\n", 
+                     STRERROR (errno));
+#endif
+         CLOSE (socket_fd);
+         goto free_and_fail;
+       }      
+    }
+  else
+    {
+      socket_fd = daemon->socket_fd;
+    }
+#ifndef WINDOWS
+  if ( (socket_fd >= FD_SETSIZE) &&
+       (0 == (flags & MHD_USE_POLL)) )
+    {
+#if HAVE_MESSAGES
+      if ((flags & MHD_USE_DEBUG) != 0)
+        MHD_DLOG (daemon,
+                 "Socket descriptor larger than FD_SETSIZE: %d > %d\n",
+                 socket_fd,
+                 FD_SETSIZE);
+#endif
+      CLOSE (socket_fd);
+      goto free_and_fail;
+    }
+#endif
+
+  if (0 != pthread_mutex_init (&daemon->per_ip_connection_mutex, NULL))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "MHD failed to initialize IP connection limit mutex\n");
+#endif
+      if (-1 != socket_fd)
+       CLOSE (socket_fd);
+      goto free_and_fail;
+    }
+  if (0 != pthread_mutex_init (&daemon->cleanup_connection_mutex, NULL))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "MHD failed to initialize IP connection limit mutex\n");
+#endif
+      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
+      if (-1 != socket_fd)
+       CLOSE (socket_fd);
+      goto free_and_fail;
+    }
+
+#if HTTPS_SUPPORT
+  /* initialize HTTPS daemon certificate aspects & send / recv functions */
+  if ((0 != (flags & MHD_USE_SSL)) && (0 != MHD_TLS_init (daemon)))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, 
+               "Failed to initialize TLS support\n");
+#endif
+      if (-1 != socket_fd)
+       CLOSE (socket_fd);
+      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
+      pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
+      goto free_and_fail;
+    }
+#endif
+  if ( ( (0 != (flags & MHD_USE_THREAD_PER_CONNECTION)) ||
+        ( (0 != (flags & MHD_USE_SELECT_INTERNALLY)) &&
+          (0 == daemon->worker_pool_size)) ) && 
+       (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) &&
+       (0 != (res_thread_create =
+             create_thread (&daemon->pid, daemon, &MHD_select_thread, 
daemon))))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+                "Failed to create listen thread: %s\n", 
+               STRERROR (res_thread_create));
+#endif
+      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
+      pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
+      if (-1 != socket_fd)
+       CLOSE (socket_fd);
+      goto free_and_fail;
+    }
+  if ( (daemon->worker_pool_size > 0) &&
+       (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
+    {
+#ifndef MINGW
+      int sk_flags;
+#else
+      unsigned long sk_flags;
+#endif
+
+      /* Coarse-grained count of connections per thread (note error
+       * due to integer division). Also keep track of how many
+       * connections are leftover after an equal split. */
+      unsigned int conns_per_thread = daemon->max_connections
+                                      / daemon->worker_pool_size;
+      unsigned int leftover_conns = daemon->max_connections
+                                    % daemon->worker_pool_size;
+
+      i = 0; /* we need this in case fcntl or malloc fails */
+
+      /* Accept must be non-blocking. Multiple children may wake up
+       * to handle a new connection, but only one will win the race.
+       * The others must immediately return. */
+#ifndef MINGW
+      sk_flags = fcntl (socket_fd, F_GETFL);
+      if (sk_flags < 0)
+        goto thread_failed;
+      if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK))
+        goto thread_failed;
+#else
+      sk_flags = 1;
+#if HAVE_PLIBC_FD
+      if (SOCKET_ERROR ==
+         ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags))
+        goto thread_failed;
+#else
+      if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR)
+        goto thread_failed;
+#endif // PLIBC_FD
+#endif // MINGW
+
+      /* Allocate memory for pooled objects */
+      daemon->worker_pool = malloc (sizeof (struct MHD_Daemon)
+                                    * daemon->worker_pool_size);
+      if (NULL == daemon->worker_pool)
+        goto thread_failed;
+
+      /* Start the workers in the pool */
+      for (i = 0; i < daemon->worker_pool_size; ++i)
+        {
+          /* Create copy of the Daemon object for each worker */
+          struct MHD_Daemon *d = &daemon->worker_pool[i];
+          memcpy (d, daemon, sizeof (struct MHD_Daemon));
+
+          /* Adjust pooling params for worker daemons; note that memcpy()
+             has already copied MHD_USE_SELECT_INTERNALLY thread model into
+             the worker threads. */
+          d->master = daemon;
+          d->worker_pool_size = 0;
+          d->worker_pool = NULL;
+
+          /* Divide available connections evenly amongst the threads.
+           * Thread indexes in [0, leftover_conns) each get one of the
+           * leftover connections. */
+          d->max_connections = conns_per_thread;
+          if (i < leftover_conns)
+            ++d->max_connections;
+
+          /* Must init cleanup connection mutex for each worker */
+          if (0 != pthread_mutex_init (&d->cleanup_connection_mutex, NULL))
+            {
+#if HAVE_MESSAGES
+              MHD_DLOG (daemon,
+                       "MHD failed to initialize cleanup connection mutex for 
thread worker %d\n", i);
+#endif
+              goto thread_failed;
+            }
+
+          /* Spawn the worker thread */
+          if (0 != (res_thread_create = create_thread (&d->pid, daemon, 
&MHD_select_thread, d)))
+            {
+#if HAVE_MESSAGES
+              MHD_DLOG (daemon,
+                        "Failed to create pool thread: %s\n", 
+                       STRERROR (res_thread_create));
+#endif
+              /* Free memory for this worker; cleanup below handles
+               * all previously-created workers. */
+              pthread_mutex_destroy (&d->cleanup_connection_mutex);
+              goto thread_failed;
+            }
+        }
+    }
+  return daemon;
+
+thread_failed:
+  /* If no worker threads created, then shut down normally. Calling
+     MHD_stop_daemon (as we do below) doesn't work here since it
+     assumes a 0-sized thread pool means we had been in the default
+     MHD_USE_SELECT_INTERNALLY mode. */
+  if (0 == i)
+    {
+      if (-1 != socket_fd)
+       CLOSE (socket_fd);
+      pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
+      pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
+      if (NULL != daemon->worker_pool)
+        free (daemon->worker_pool);
+      goto free_and_fail;
+    }
+
+  /* Shutdown worker threads we've already created. Pretend
+     as though we had fully initialized our daemon, but
+     with a smaller number of threads than had been
+     requested. */
+  daemon->worker_pool_size = i - 1;
+  MHD_stop_daemon (daemon);
+  return NULL;
+
+ free_and_fail:
+  /* clean up basic memory state in 'daemon' and return NULL to 
+     indicate failure */
+#ifdef DAUTH_SUPPORT
+  free (daemon->nnc);
+  pthread_mutex_destroy (&daemon->nnc_lock);
+#endif
+#if HTTPS_SUPPORT
+  if (0 != (flags & MHD_USE_SSL))
+    gnutls_priority_deinit (daemon->priority_cache);
+#endif
+  free (daemon);
+  return NULL;
+}
+
+
+/**
+ * Close all connections for the daemon; must only be called after
+ * all of the threads have been joined and there is no more concurrent
+ * activity on the connection lists.
+ *
+ * @param daemon daemon to close down
+ */
+static void
+close_all_connections (struct MHD_Daemon *daemon)
+{
+  struct MHD_Connection *pos;
+  void *unused;
+  int rc;
+  
+  /* first, make sure all threads are aware of shutdown; need to
+     traverse DLLs in peace... */
+  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
+    {
+      MHD_PANIC ("Failed to acquire cleanup mutex\n");
+    }
+  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)    
+    SHUTDOWN (pos->socket_fd, 
+             (pos->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);    
+  if (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex))
+    {
+      MHD_PANIC ("Failed to release cleanup mutex\n");
+    }
+
+  /* now, collect threads */
+  if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
+    {
+      while (NULL != (pos = daemon->connections_head))
+       {
+         if (0 != (rc = pthread_join (pos->pid, &unused)))
+           {
+             MHD_PANIC ("Failed to join a thread\n");
+           }
+         pos->thread_joined = MHD_YES;
+       }
+    }
+
+  /* now that we're alone, move everyone to cleanup */
+  while (NULL != (pos = daemon->connections_head))
+    {
+      MHD_connection_close (pos,
+                           MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
+      DLL_remove (daemon->connections_head,
+                 daemon->connections_tail,
+                 pos);
+      DLL_insert (daemon->cleanup_head,
+                 daemon->cleanup_tail,
+                 pos);
+    }
+  MHD_cleanup_connections (daemon);
+}
+
+
+/**
+ * Shutdown an http daemon
+ *
+ * @param daemon daemon to stop
+ */
+void
+MHD_stop_daemon (struct MHD_Daemon *daemon)
+{
+  void *unused;
+  int fd;
+  unsigned int i;
+  int rc;
+
+  if (NULL == daemon)
+    return;
+  daemon->shutdown = MHD_YES;
+  fd = daemon->socket_fd;
+  daemon->socket_fd = -1;
+  /* Prepare workers for shutdown */
+  if (NULL != daemon->worker_pool)
+    {
+      /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to 
check */
+      for (i = 0; i < daemon->worker_pool_size; ++i)
+       {
+         daemon->worker_pool[i].shutdown = MHD_YES;
+         daemon->worker_pool[i].socket_fd = -1;
+       }
+    }
+  if (-1 != daemon->wpipe[1])
+    {
+      if (1 != WRITE (daemon->wpipe[1], "e", 1))
+       MHD_PANIC ("failed to signal shutdownn via pipe");
+    }
+#ifdef HAVE_LISTEN_SHUTDOWN
+  else
+    {
+      /* fd might be -1 here due to 'MHD_quiesce_daemon' */
+      if (-1 != fd)
+       (void) SHUTDOWN (fd, SHUT_RDWR);
+    }
+#endif
+#if DEBUG_CLOSE
+#if HAVE_MESSAGES
+  MHD_DLOG (daemon, "MHD listen socket shutdown\n");
+#endif
+#endif
+
+
+  /* Signal workers to stop and clean them up */
+  if (NULL != daemon->worker_pool)
+    {
+      /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to 
check */
+      for (i = 0; i < daemon->worker_pool_size; ++i)
+       {
+         if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused)))
+           {
+             MHD_PANIC ("Failed to join a thread\n");
+           }
+         close_all_connections (&daemon->worker_pool[i]);
+         pthread_mutex_destroy 
(&daemon->worker_pool[i].cleanup_connection_mutex);
+       }
+      free (daemon->worker_pool);
+    }
+  else
+    {
+      /* clean up master threads */
+      if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
+         ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
+          && (0 == daemon->worker_pool_size)))
+       {
+         if (0 != (rc = pthread_join (daemon->pid, &unused)))
+           {
+             MHD_PANIC ("Failed to join a thread\n");
+           }
+       }
+    }
+  close_all_connections (daemon);
+  if (-1 != fd)
+    (void) CLOSE (fd);
+
+  /* TLS clean up */
+#if HTTPS_SUPPORT
+  if (0 != (daemon->options & MHD_USE_SSL))
+    {
+      gnutls_priority_deinit (daemon->priority_cache);
+      if (daemon->x509_cred)
+        gnutls_certificate_free_credentials (daemon->x509_cred);
+    }
+#endif
+
+#ifdef DAUTH_SUPPORT
+  free (daemon->nnc);
+  pthread_mutex_destroy (&daemon->nnc_lock);
+#endif
+  pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
+  pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
+
+  if (-1 != daemon->wpipe[1])
+    {
+      (void) CLOSE (daemon->wpipe[0]);
+      (void) CLOSE (daemon->wpipe[1]);
+    }
+  free (daemon);
+}
+
+
+/**
+ * Obtain information about the given daemon
+ * (not fully implemented!).
+ *
+ * @param daemon what daemon to get information about
+ * @param infoType what information is desired?
+ * @param ... depends on infoType
+ * @return NULL if this information is not available
+ *         (or if the infoType is unknown)
+ */
+const union MHD_DaemonInfo *
+MHD_get_daemon_info (struct MHD_Daemon *daemon,
+                     enum MHD_DaemonInfoType infoType, ...)
+{
+  switch (infoType)
+    {
+    case MHD_DAEMON_INFO_LISTEN_FD:
+      return (const union MHD_DaemonInfo *) &daemon->socket_fd;
+    default:
+      return NULL;
+    };
+}
+
+
+/**
+ * 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.  While "cb" is allowed to return and MHD will then
+ * try to continue, this is never safe.
+ *
+ * The default implementation that is used if no panic function is set
+ * simply prints an error message and calls "abort".  Alternative
+ * implementations might call "exit" or other similar functions.
+ *
+ * @param cb new error handler
+ * @param cls passed to error handler
+ */
+void 
+MHD_set_panic_func (MHD_PanicCallback cb, void *cls)
+{
+  mhd_panic = cb;
+  mhd_panic_cls = cls;
+}
+
+
+/**
+ * Obtain the version of this library
+ *
+ * @return static version string, e.g. "0.4.1"
+ */
+const char *
+MHD_get_version (void)
+{
+  return PACKAGE_VERSION;
+}
+
+
+#ifdef __GNUC__
+#define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor))
+#define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor))
+#else  // !__GNUC__
+#define ATTRIBUTE_CONSTRUCTOR
+#define ATTRIBUTE_DESTRUCTOR
+#endif  // __GNUC__
+
+#if HTTPS_SUPPORT
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+#endif
+
+
+/**
+ * Initialize do setup work.
+ */
+void ATTRIBUTE_CONSTRUCTOR 
+MHD_init ()
+{
+  mhd_panic = &mhd_panic_std;
+  mhd_panic_cls = NULL;
+
+#ifdef WINDOWS
+  plibc_init ("GNU", "libmicrohttpd");
+#endif
+#if HTTPS_SUPPORT
+  gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+  gnutls_global_init ();
+#endif
+}
+
+
+void ATTRIBUTE_DESTRUCTOR 
+MHD_fini ()
+{
+#if HTTPS_SUPPORT
+  gnutls_global_deinit ();
+#endif
+#ifdef WINDOWS
+  plibc_shutdown ();
+#endif
+}
+
+/* end of daemon.c */

Deleted: libmicrohttpd/src/microhttpd/digestauth.c
===================================================================
--- libmicrohttpd/src/daemon/digestauth.c       2013-05-05 12:01:06 UTC (rev 
27023)
+++ libmicrohttpd/src/microhttpd/digestauth.c   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,804 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-*/
-/**
- * @file digestauth.c
- * @brief Implements HTTP digest authentication
- * @author Amr Ali
- * @author Matthieu Speder
- */
-#include "platform.h"
-#include <limits.h>
-#include "internal.h"
-#include "md5.h"
-
-#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
-
-/**
- * Beginning string for any valid Digest authentication header.
- */
-#define _BASE          "Digest "
-
-/**
- * Maximum length of a username for digest authentication.
- */
-#define MAX_USERNAME_LENGTH 128
-
-/**
- * Maximum length of a realm for digest authentication.
- */
-#define MAX_REALM_LENGTH 256
-
-/**
- * Maximum length of the response in digest authentication.
- */
-#define MAX_AUTH_RESPONSE_LENGTH 128
-
-
-/**
- * convert bin to hex 
- *
- * @param bin binary data
- * @param len number of bytes in bin
- * @param hex pointer to len*2+1 bytes
- */
-static void
-cvthex (const unsigned char *bin,
-       size_t len,
-       char *hex)
-{
-  size_t i;
-  unsigned int j;
-  
-  for (i = 0; i < len; ++i) 
-    {
-      j = (bin[i] >> 4) & 0x0f;      
-      hex[i * 2] = j <= 9 ? (j + '0') : (j + 'a' - 10);    
-      j = bin[i] & 0x0f;    
-      hex[i * 2 + 1] = j <= 9 ? (j + '0') : (j + 'a' - 10);
-    }
-  hex[len * 2] = '\0';
-}
-
-
-/**
- * calculate H(A1) as per RFC2617 spec and store the
- * result in 'sessionkey'.
- *
- * @param alg The hash algorithm used, can be "md5" or "md5-sess"
- * @param username A `char *' pointer to the username value
- * @param realm A `char *' pointer to the realm value
- * @param password A `char *' pointer to the password value
- * @param nonce A `char *' pointer to the nonce value
- * @param cnonce A `char *' pointer to the cnonce value
- * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
- */
-static void
-digest_calc_ha1 (const char *alg,
-                const char *username,
-                const char *realm,
-                const char *password,
-                const char *nonce,
-                const char *cnonce,
-                char *sessionkey)
-{
-  struct MD5Context md5;
-  unsigned char ha1[MD5_DIGEST_SIZE];
-  
-  MD5Init (&md5);
-  MD5Update (&md5, username, strlen (username));
-  MD5Update (&md5, ":", 1);
-  MD5Update (&md5, realm, strlen (realm));
-  MD5Update (&md5, ":", 1);
-  MD5Update (&md5, password, strlen (password));
-  MD5Final (ha1, &md5);
-  if (0 == strcasecmp (alg, "md5-sess")) 
-    {
-      MD5Init (&md5);
-      MD5Update (&md5, ha1, sizeof (ha1));
-      MD5Update (&md5, ":", 1);
-      MD5Update (&md5, nonce, strlen (nonce));
-      MD5Update (&md5, ":", 1);
-      MD5Update (&md5, cnonce, strlen (cnonce));
-      MD5Final (ha1, &md5);
-    }
-  cvthex (ha1, sizeof (ha1), sessionkey);
-}
-
-
-/**
- * Calculate request-digest/response-digest as per RFC2617 spec 
- * 
- * @param ha1 H(A1)
- * @param nonce nonce from server
- * @param noncecount 8 hex digits
- * @param cnonce client nonce
- * @param qop qop-value: "", "auth" or "auth-int"
- * @param method method from request
- * @param uri requested URL
- * @param hentity H(entity body) if qop="auth-int"
- * @param response request-digest or response-digest
- */
-static void
-digest_calc_response (const char *ha1,
-                     const char *nonce,
-                     const char *noncecount,
-                     const char *cnonce,
-                     const char *qop,
-                     const char *method,
-                     const char *uri,
-                     const char *hentity,
-                     char *response)
-{
-  struct MD5Context md5;
-  unsigned char ha2[MD5_DIGEST_SIZE];
-  unsigned char resphash[MD5_DIGEST_SIZE];
-  char ha2hex[HASH_MD5_HEX_LEN + 1];
-  
-  MD5Init (&md5);
-  MD5Update (&md5, method, strlen(method));
-  MD5Update (&md5, ":", 1);
-  MD5Update (&md5, uri, strlen(uri)); 
-#if 0
-  if (0 == strcasecmp(qop, "auth-int"))
-    {
-      /* This is dead code since the rest of this module does
-        not support auth-int. */
-      MD5Update (&md5, ":", 1);
-      if (NULL != hentity)
-       MD5Update (&md5, hentity, strlen(hentity));
-    }
-#endif  
-  MD5Final (ha2, &md5);
-  cvthex (ha2, MD5_DIGEST_SIZE, ha2hex);
-  MD5Init (&md5);  
-  /* calculate response */  
-  MD5Update (&md5, ha1, HASH_MD5_HEX_LEN);
-  MD5Update (&md5, ":", 1);
-  MD5Update (&md5, nonce, strlen(nonce));
-  MD5Update (&md5, ":", 1);  
-  if ('\0' != *qop)
-    {
-      MD5Update (&md5, noncecount, strlen(noncecount));
-      MD5Update (&md5, ":", 1);
-      MD5Update (&md5, cnonce, strlen(cnonce));
-      MD5Update (&md5, ":", 1);
-      MD5Update (&md5, qop, strlen(qop));
-      MD5Update (&md5, ":", 1);
-    }  
-  MD5Update (&md5, ha2hex, HASH_MD5_HEX_LEN);
-  MD5Final (resphash, &md5);
-  cvthex (resphash, sizeof (resphash), response);
-}
-
-
-/**
- * Lookup subvalue off of the HTTP Authorization header.
- *
- * A description of the input format for 'data' is at
- * http://en.wikipedia.org/wiki/Digest_access_authentication
- *
- *
- * @param dest where to store the result (possibly truncated if
- *             the buffer is not big enough).
- * @param size size of dest
- * @param data pointer to the Authorization header
- * @param key key to look up in data
- * @return size of the located value, 0 if otherwise
- */
-static int
-lookup_sub_value (char *dest,
-                 size_t size,
-                 const char *data,
-                 const char *key)
-{
-  size_t keylen;
-  size_t len;
-  const char *ptr;
-  const char *eq;
-  const char *q1;
-  const char *q2;
-  const char *qn;
-
-  if (0 == size)
-    return 0;
-  keylen = strlen (key);
-  ptr = data;
-  while ('\0' != *ptr)
-    {
-      if (NULL == (eq = strchr (ptr, '=')))
-       return 0;
-      q1 = eq + 1;
-      while (' ' == *q1)
-       q1++;      
-      if ('\"' != *q1)
-       {
-         q2 = strchr (q1, ',');
-         qn = q2;
-       }
-      else
-       {
-         q1++;
-         q2 = strchr (q1, '\"');
-         if (NULL == q2)
-           return 0; /* end quote not found */
-         qn = q2 + 1;
-       }      
-      if ( (0 == strncasecmp (ptr,
-                             key,
-                             keylen)) &&
-          (eq == &ptr[keylen]) )
-       {
-         if (NULL == q2)
-           {
-             len = strlen (q1) + 1;
-             if (size > len)
-               size = len;
-             size--;
-             strncpy (dest,
-                      q1,
-                      size);
-             dest[size] = '\0';
-             return size;
-           }
-         else
-           {
-             if (size > (q2 - q1) + 1)
-               size = (q2 - q1) + 1;
-             size--;
-             memcpy (dest, 
-                     q1,
-                     size);
-             dest[size] = '\0';
-             return size;
-           }
-       }
-      if (NULL == qn)
-       return 0;
-      ptr = strchr (qn, ',');
-      if (NULL == ptr)
-       return 0;
-      ptr++;
-      while (' ' == *ptr)
-       ptr++;
-    }
-  return 0;
-}
-
-
-/**
- * Check nonce-nc map array with either new nonce counter
- * or a whole new nonce.
- *
- * @param connection The MHD connection structure
- * @param nonce A pointer that referenced a zero-terminated array of nonce
- * @param nc The nonce counter, zero to add the nonce to the array
- * @return MHD_YES if successful, MHD_NO if invalid (or we have no NC array)
- */
-static int
-check_nonce_nc (struct MHD_Connection *connection,
-               const char *nonce,
-               unsigned long int nc)
-{
-  uint32_t off;
-  uint32_t mod;
-  const char *np;
-
-  mod = connection->daemon->nonce_nc_size;
-  if (0 == mod)
-    return MHD_NO; /* no array! */
-  /* super-fast xor-based "hash" function for HT lookup in nonce array */
-  off = 0;
-  np = nonce;
-  while ('\0' != *np)
-    {
-      off = (off << 8) | (*np ^ (off >> 24));
-      np++;
-    }
-  off = off % mod;
-  /*
-   * Look for the nonce, if it does exist and its corresponding
-   * nonce counter is less than the current nonce counter by 1,
-   * then only increase the nonce counter by one.
-   */
-  
-  pthread_mutex_lock (&connection->daemon->nnc_lock);
-  if (0 == nc)
-    {
-      strcpy(connection->daemon->nnc[off].nonce, 
-            nonce);
-      connection->daemon->nnc[off].nc = 0;  
-      pthread_mutex_unlock (&connection->daemon->nnc_lock);
-      return MHD_YES;
-    }
-  if ( (nc <= connection->daemon->nnc[off].nc) ||
-       (0 != strcmp(connection->daemon->nnc[off].nonce, nonce)) )
-    {
-      pthread_mutex_unlock (&connection->daemon->nnc_lock);
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, 
-               "Stale nonce received.  If this happens a lot, you should 
probably increase the size of the nonce array.\n");
-#endif
-      return MHD_NO;
-    }
-  connection->daemon->nnc[off].nc = nc;
-  pthread_mutex_unlock (&connection->daemon->nnc_lock);
-  return MHD_YES;
-}
-
-
-/**
- * Get the username from the authorization header sent by the client
- *
- * @param connection The MHD connection structure
- * @return NULL if no username could be found, a pointer
- *                     to the username if found
- */
-char *
-MHD_digest_auth_get_username(struct MHD_Connection *connection)
-{
-  size_t len;
-  char user[MAX_USERNAME_LENGTH];
-  const char *header;
-  
-  if (NULL == (header = MHD_lookup_connection_value (connection,
-                                                    MHD_HEADER_KIND, 
-                                                    
MHD_HTTP_HEADER_AUTHORIZATION)))
-    return NULL;
-  if (0 != strncmp (header, _BASE, strlen (_BASE)))
-    return NULL;
-  header += strlen (_BASE);
-  if (0 == (len = lookup_sub_value (user,
-                                   sizeof (user),
-                                   header, 
-                                   "username")))
-    return NULL;
-  return strdup (user);
-}
-
-
-/**
- * Calculate the server nonce so that it mitigates replay attacks
- * The current format of the nonce is ...
- * H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp)
- *
- * @param nonce_time The amount of time in seconds for a nonce to be invalid
- * @param method HTTP method
- * @param rnd A pointer to a character array for the random seed
- * @param rnd_size The size of the random seed array
- * @param uri HTTP URI (in MHD, without the arguments ("?k=v")
- * @param realm A string of characters that describes the realm of auth.
- * @param nonce A pointer to a character array for the nonce to put in
- */
-static void
-calculate_nonce (uint32_t nonce_time,
-                const char *method,
-                const char *rnd,
-                unsigned int rnd_size,
-                const char *uri,
-                const char *realm,
-                char *nonce)
-{
-  struct MD5Context md5;
-  unsigned char timestamp[4];
-  unsigned char tmpnonce[MD5_DIGEST_SIZE];
-  char timestamphex[sizeof(timestamp) * 2 + 1];
-
-  MD5Init (&md5);
-  timestamp[0] = (nonce_time & 0xff000000) >> 0x18;
-  timestamp[1] = (nonce_time & 0x00ff0000) >> 0x10;
-  timestamp[2] = (nonce_time & 0x0000ff00) >> 0x08;
-  timestamp[3] = (nonce_time & 0x000000ff);    
-  MD5Update (&md5, timestamp, 4);
-  MD5Update (&md5, ":", 1);
-  MD5Update (&md5, method, strlen(method));
-  MD5Update (&md5, ":", 1);
-  if (rnd_size > 0)
-    MD5Update (&md5, rnd, rnd_size);
-  MD5Update (&md5, ":", 1);
-  MD5Update (&md5, uri, strlen(uri));
-  MD5Update (&md5, ":", 1);
-  MD5Update (&md5, realm, strlen(realm));
-  MD5Final (tmpnonce, &md5);  
-  cvthex (tmpnonce, sizeof (tmpnonce), nonce);  
-  cvthex (timestamp, 4, timestamphex);
-  strncat (nonce, timestamphex, 8);
-}
-
-
-/**
- * Test if the given key-value pair is in the headers for the
- * given connection.
- *
- * @param connection the connection
- * @param key the key
- * @param value the value, can be NULL
- * @return MHD_YES if the key-value pair is in the headers, 
- *         MHD_NO if not
- */
-static int
-test_header (struct MHD_Connection *connection,
-            const char *key,
-            const char *value)
-{
-  struct MHD_HTTP_Header *pos;
-
-  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
-    {
-      if (MHD_GET_ARGUMENT_KIND != pos->kind)
-       continue;
-      if (0 != strcmp (key, pos->header))
-       continue;
-      if ( (NULL == value) && 
-          (NULL == pos->value) )
-       return MHD_YES;
-      if ( (NULL == value) || 
-          (NULL == pos->value) ||
-          (0 != strcmp (value, pos->value)) )
-       continue;
-      return MHD_YES;      
-    }
-  return MHD_NO;
-}
-
-
-/**
- * Check that the arguments given by the client as part
- * of the authentication header match the arguments we
- * got as part of the HTTP request URI.
- *
- * @param connection connections with headers to compare against
- * @param args argument URI string (after "?" in URI)
- * @return MHD_YES if the arguments match,
- *         MHD_NO if not
- */
-static int
-check_argument_match (struct MHD_Connection *connection,
-                     const char *args)
-{
-  struct MHD_HTTP_Header *pos;
-  size_t slen = strlen (args) + 1;
-  char argb[slen];
-  char *argp;
-  char *equals;
-  char *amper;
-  unsigned int num_headers;
-
-  num_headers = 0;
-  memcpy (argb, args, slen);
-  argp = argb;
-  while ( (NULL != argp) &&
-         ('\0' != argp[0]) )
-    {
-      equals = strchr (argp, '=');
-      if (NULL == equals) 
-       {         
-         /* add with 'value' NULL */
-         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                                connection,
-                                                argp);
-         if (MHD_YES != test_header (connection, argp, NULL))
-           return MHD_NO;
-         num_headers++;
-         break;
-       }
-      equals[0] = '\0';
-      equals++;
-      amper = strchr (equals, '&');
-      if (NULL != amper)
-       {
-         amper[0] = '\0';
-         amper++;
-       }
-      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                            connection,
-                                            argp);
-      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
-                                            connection,
-                                            equals);
-      if (! test_header (connection, argp, equals))
-       return MHD_NO;
-      num_headers++;
-      argp = amper;
-    }
-  
-  /* also check that the number of headers matches */
-  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
-    {
-      if (MHD_GET_ARGUMENT_KIND != pos->kind)
-       continue;
-      num_headers--;
-    }
-  if (0 != num_headers)  
-    return MHD_NO;
-  return MHD_YES;
-}
-
-
-/**
- * Authenticates the authorization header sent by the client
- *
- * @param connection The MHD connection structure
- * @param realm The realm presented to the client
- * @param username The username needs to be authenticated
- * @param password The password used in the authentication
- * @param nonce_timeout The amount of time for a nonce to be
- *                     invalid in seconds
- * @return MHD_YES if authenticated, MHD_NO if not,
- *                     MHD_INVALID_NONCE if nonce is invalid
- */
-int
-MHD_digest_auth_check (struct MHD_Connection *connection,
-                      const char *realm,
-                      const char *username,
-                      const char *password,
-                      unsigned int nonce_timeout)
-{
-  size_t len;
-  const char *header;
-  char *end;
-  char nonce[MAX_NONCE_LENGTH];
-  char cnonce[MAX_NONCE_LENGTH];
-  char qop[15]; /* auth,auth-int */
-  char nc[20];
-  char response[MAX_AUTH_RESPONSE_LENGTH];
-  const char *hentity = NULL; /* "auth-int" is not supported */
-  char ha1[HASH_MD5_HEX_LEN + 1];
-  char respexp[HASH_MD5_HEX_LEN + 1];
-  char noncehashexp[HASH_MD5_HEX_LEN + 9];
-  uint32_t nonce_time;
-  uint32_t t;
-  size_t left; /* number of characters left in 'header' for 'uri' */
-  unsigned long int nci;
-
-  header = MHD_lookup_connection_value (connection,
-                                       MHD_HEADER_KIND,
-                                       MHD_HTTP_HEADER_AUTHORIZATION);  
-  if (NULL == header) 
-    return MHD_NO;
-  if (0 != strncmp(header, _BASE, strlen(_BASE))) 
-    return MHD_NO;
-  header += strlen (_BASE);
-  left = strlen (header);
-
-  {
-    char un[MAX_USERNAME_LENGTH];
-
-    len = lookup_sub_value (un,
-                           sizeof (un),
-                           header, "username");
-    if ( (0 == len) ||
-        (0 != strcmp(username, un)) ) 
-      return MHD_NO;
-    left -= strlen ("username") + len;
-  }
-
-  {
-    char r[MAX_REALM_LENGTH];
-
-    len = lookup_sub_value(r, 
-                          sizeof (r),
-                          header, "realm");  
-    if ( (0 == len) || 
-        (0 != strcmp(realm, r)) )
-      return MHD_NO;
-    left -= strlen ("realm") + len;
-  }
-
-  if (0 == (len = lookup_sub_value (nonce, 
-                                   sizeof (nonce),
-                                   header, "nonce")))
-    return MHD_NO;
-  left -= strlen ("nonce") + len;
-
-  {
-    char uri[left];  
-  
-    if (0 == lookup_sub_value(uri,
-                             sizeof (uri),
-                             header, "uri")) 
-      return MHD_NO;
-      
-    /* 8 = 4 hexadecimal numbers for the timestamp */  
-    nonce_time = strtoul(nonce + len - 8, (char **)NULL, 16);  
-    t = (uint32_t) MHD_monotonic_time();    
-    /*
-     * First level vetting for the nonce validity if the timestamp
-     * attached to the nonce exceeds `nonce_timeout' then the nonce is
-     * invalid.
-     */
-    if ( (t > nonce_time + nonce_timeout) ||
-        (nonce_time + nonce_timeout < nonce_time) )
-      return MHD_INVALID_NONCE;
-    if (0 != strncmp (uri,
-                     connection->url,
-                     strlen (connection->url)))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, 
-               "Authentication failed, URI does not match.\n");
-#endif
-      return MHD_NO;
-    }
-    {
-      const char *args = strchr (uri, '?');
-
-      if (NULL == args)
-       args = "";
-      else
-       args++;
-      if (MHD_YES !=
-         check_argument_match (connection,
-                               args) ) 
-      {
-#if HAVE_MESSAGES
-       MHD_DLOG (connection->daemon, 
-                 "Authentication failed, arguments do not match.\n");
-#endif
-       return MHD_NO;
-      }
-    }
-    calculate_nonce (nonce_time,
-                    connection->method,
-                    connection->daemon->digest_auth_random,
-                    connection->daemon->digest_auth_rand_size,
-                    connection->url,
-                    realm,
-                    noncehashexp);
-    /*
-     * Second level vetting for the nonce validity
-     * if the timestamp attached to the nonce is valid
-     * and possibly fabricated (in case of an attack)
-     * the attacker must also know the random seed to be
-     * able to generate a "sane" nonce, which if he does
-     * not, the nonce fabrication process going to be
-     * very hard to achieve.
-     */
-    
-    if (0 != strcmp (nonce, noncehashexp))
-      return MHD_INVALID_NONCE;
-    if ( (0 == lookup_sub_value (cnonce,
-                                sizeof (cnonce), 
-                                header, "cnonce")) ||
-        (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) ||
-        ( (0 != strcmp (qop, "auth")) && 
-          (0 != strcmp (qop, "")) ) ||
-        (0 == lookup_sub_value (nc, sizeof (nc), header, "nc"))  ||
-        (0 == lookup_sub_value (response, sizeof (response), header, 
"response")) )
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, 
-               "Authentication failed, invalid format.\n");
-#endif
-      return MHD_NO;
-    }
-    nci = strtoul (nc, &end, 16);
-    if ( ('\0' != *end) ||
-        ( (LONG_MAX == nci) && 
-          (ERANGE == errno) ) )
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, 
-               "Authentication failed, invalid format.\n");
-#endif
-      return MHD_NO; /* invalid nonce format */
-    }
-    /*
-     * Checking if that combination of nonce and nc is sound
-     * and not a replay attack attempt. Also adds the nonce
-     * to the nonce-nc map if it does not exist there.
-     */
-    
-    if (MHD_YES != check_nonce_nc (connection, nonce, nci))
-      return MHD_NO;
-    
-    digest_calc_ha1("md5",
-                   username,
-                   realm,
-                   password,
-                   nonce,
-                   cnonce,
-                   ha1);
-    digest_calc_response (ha1,
-                         nonce,
-                         nc,
-                         cnonce,
-                         qop,
-                         connection->method,
-                         uri,
-                         hentity,
-                         respexp);  
-    return (0 == strcmp(response, respexp)) 
-      ? MHD_YES 
-      : MHD_NO;
-  }
-}
-
-
-/**
- * Queues a response to request authentication from the client
- *
- * @param connection The MHD connection structure
- * @param realm the realm presented to the client
- * @param opaque string to user for opaque value
- * @param signal_stale MHD_YES if the nonce is invalid to add
- *                     'stale=true' to the authentication header
- * @return MHD_YES on success, MHD_NO otherwise
- */
-int
-MHD_queue_auth_fail_response (struct MHD_Connection *connection,
-                             const char *realm,
-                             const char *opaque,
-                             struct MHD_Response *response,
-                             int signal_stale)
-{
-  int ret;
-  size_t hlen;
-  char nonce[HASH_MD5_HEX_LEN + 9];
-
-  /* Generating the server nonce */  
-  calculate_nonce ((uint32_t) MHD_monotonic_time(),
-                  connection->method,
-                  connection->daemon->digest_auth_random,
-                  connection->daemon->digest_auth_rand_size,
-                  connection->url,
-                  realm,
-                  nonce);
-  if (MHD_YES != check_nonce_nc (connection, nonce, 0))
-    {
-#if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon, 
-               "Could not register nonce (is the nonce array size zero?).\n");
-#endif
-      return MHD_NO;  
-    }
-  /* Building the authentication header */
-  hlen = snprintf (NULL,
-                  0,
-                  "Digest 
realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
-                  realm, 
-                  nonce,
-                  opaque,
-                  signal_stale 
-                  ? ",stale=\"true\"" 
-                  : "");
-  {
-    char header[hlen + 1];
-
-    snprintf (header,
-             sizeof(header),
-             "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
-             realm, 
-             nonce,
-             opaque,
-             signal_stale 
-             ? ",stale=\"true\"" 
-             : "");
-    ret = MHD_add_response_header(response,
-                                 MHD_HTTP_HEADER_WWW_AUTHENTICATE, 
-                                 header);
-  }
-  if (MHD_YES == ret) 
-    ret = MHD_queue_response(connection, 
-                            MHD_HTTP_UNAUTHORIZED, 
-                            response);  
-  return ret;
-}
-
-
-/* end of digestauth.c */

Copied: libmicrohttpd/src/microhttpd/digestauth.c (from rev 27024, 
libmicrohttpd/src/daemon/digestauth.c)
===================================================================
--- libmicrohttpd/src/microhttpd/digestauth.c                           (rev 0)
+++ libmicrohttpd/src/microhttpd/digestauth.c   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,807 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+*/
+/**
+ * @file digestauth.c
+ * @brief Implements HTTP digest authentication
+ * @author Amr Ali
+ * @author Matthieu Speder
+ */
+#include "platform.h"
+#include <limits.h>
+#include "internal.h"
+#include "md5.h"
+
+#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
+
+/**
+ * Beginning string for any valid Digest authentication header.
+ */
+#define _BASE          "Digest "
+
+/**
+ * Maximum length of a username for digest authentication.
+ */
+#define MAX_USERNAME_LENGTH 128
+
+/**
+ * Maximum length of a realm for digest authentication.
+ */
+#define MAX_REALM_LENGTH 256
+
+/**
+ * Maximum length of the response in digest authentication.
+ */
+#define MAX_AUTH_RESPONSE_LENGTH 128
+
+
+/**
+ * convert bin to hex 
+ *
+ * @param bin binary data
+ * @param len number of bytes in bin
+ * @param hex pointer to len*2+1 bytes
+ */
+static void
+cvthex (const unsigned char *bin,
+       size_t len,
+       char *hex)
+{
+  size_t i;
+  unsigned int j;
+  
+  for (i = 0; i < len; ++i) 
+    {
+      j = (bin[i] >> 4) & 0x0f;      
+      hex[i * 2] = j <= 9 ? (j + '0') : (j + 'a' - 10);    
+      j = bin[i] & 0x0f;    
+      hex[i * 2 + 1] = j <= 9 ? (j + '0') : (j + 'a' - 10);
+    }
+  hex[len * 2] = '\0';
+}
+
+
+/**
+ * calculate H(A1) as per RFC2617 spec and store the
+ * result in 'sessionkey'.
+ *
+ * @param alg The hash algorithm used, can be "md5" or "md5-sess"
+ * @param username A `char *' pointer to the username value
+ * @param realm A `char *' pointer to the realm value
+ * @param password A `char *' pointer to the password value
+ * @param nonce A `char *' pointer to the nonce value
+ * @param cnonce A `char *' pointer to the cnonce value
+ * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
+ */
+static void
+digest_calc_ha1 (const char *alg,
+                const char *username,
+                const char *realm,
+                const char *password,
+                const char *nonce,
+                const char *cnonce,
+                char *sessionkey)
+{
+  struct MD5Context md5;
+  unsigned char ha1[MD5_DIGEST_SIZE];
+  
+  MD5Init (&md5);
+  MD5Update (&md5, username, strlen (username));
+  MD5Update (&md5, ":", 1);
+  MD5Update (&md5, realm, strlen (realm));
+  MD5Update (&md5, ":", 1);
+  MD5Update (&md5, password, strlen (password));
+  MD5Final (ha1, &md5);
+  if (0 == strcasecmp (alg, "md5-sess")) 
+    {
+      MD5Init (&md5);
+      MD5Update (&md5, ha1, sizeof (ha1));
+      MD5Update (&md5, ":", 1);
+      MD5Update (&md5, nonce, strlen (nonce));
+      MD5Update (&md5, ":", 1);
+      MD5Update (&md5, cnonce, strlen (cnonce));
+      MD5Final (ha1, &md5);
+    }
+  cvthex (ha1, sizeof (ha1), sessionkey);
+}
+
+
+/**
+ * Calculate request-digest/response-digest as per RFC2617 spec 
+ * 
+ * @param ha1 H(A1)
+ * @param nonce nonce from server
+ * @param noncecount 8 hex digits
+ * @param cnonce client nonce
+ * @param qop qop-value: "", "auth" or "auth-int"
+ * @param method method from request
+ * @param uri requested URL
+ * @param hentity H(entity body) if qop="auth-int"
+ * @param response request-digest or response-digest
+ */
+static void
+digest_calc_response (const char *ha1,
+                     const char *nonce,
+                     const char *noncecount,
+                     const char *cnonce,
+                     const char *qop,
+                     const char *method,
+                     const char *uri,
+                     const char *hentity,
+                     char *response)
+{
+  struct MD5Context md5;
+  unsigned char ha2[MD5_DIGEST_SIZE];
+  unsigned char resphash[MD5_DIGEST_SIZE];
+  char ha2hex[HASH_MD5_HEX_LEN + 1];
+  
+  MD5Init (&md5);
+  MD5Update (&md5, method, strlen(method));
+  MD5Update (&md5, ":", 1);
+  MD5Update (&md5, uri, strlen(uri)); 
+#if 0
+  if (0 == strcasecmp(qop, "auth-int"))
+    {
+      /* This is dead code since the rest of this module does
+        not support auth-int. */
+      MD5Update (&md5, ":", 1);
+      if (NULL != hentity)
+       MD5Update (&md5, hentity, strlen(hentity));
+    }
+#endif  
+  MD5Final (ha2, &md5);
+  cvthex (ha2, MD5_DIGEST_SIZE, ha2hex);
+  MD5Init (&md5);  
+  /* calculate response */  
+  MD5Update (&md5, ha1, HASH_MD5_HEX_LEN);
+  MD5Update (&md5, ":", 1);
+  MD5Update (&md5, nonce, strlen(nonce));
+  MD5Update (&md5, ":", 1);  
+  if ('\0' != *qop)
+    {
+      MD5Update (&md5, noncecount, strlen(noncecount));
+      MD5Update (&md5, ":", 1);
+      MD5Update (&md5, cnonce, strlen(cnonce));
+      MD5Update (&md5, ":", 1);
+      MD5Update (&md5, qop, strlen(qop));
+      MD5Update (&md5, ":", 1);
+    }  
+  MD5Update (&md5, ha2hex, HASH_MD5_HEX_LEN);
+  MD5Final (resphash, &md5);
+  cvthex (resphash, sizeof (resphash), response);
+}
+
+
+/**
+ * Lookup subvalue off of the HTTP Authorization header.
+ *
+ * A description of the input format for 'data' is at
+ * http://en.wikipedia.org/wiki/Digest_access_authentication
+ *
+ *
+ * @param dest where to store the result (possibly truncated if
+ *             the buffer is not big enough).
+ * @param size size of dest
+ * @param data pointer to the Authorization header
+ * @param key key to look up in data
+ * @return size of the located value, 0 if otherwise
+ */
+static int
+lookup_sub_value (char *dest,
+                 size_t size,
+                 const char *data,
+                 const char *key)
+{
+  size_t keylen;
+  size_t len;
+  const char *ptr;
+  const char *eq;
+  const char *q1;
+  const char *q2;
+  const char *qn;
+
+  if (0 == size)
+    return 0;
+  keylen = strlen (key);
+  ptr = data;
+  while ('\0' != *ptr)
+    {
+      if (NULL == (eq = strchr (ptr, '=')))
+       return 0;
+      q1 = eq + 1;
+      while (' ' == *q1)
+       q1++;      
+      if ('\"' != *q1)
+       {
+         q2 = strchr (q1, ',');
+         qn = q2;
+       }
+      else
+       {
+         q1++;
+         q2 = strchr (q1, '\"');
+         if (NULL == q2)
+           return 0; /* end quote not found */
+         qn = q2 + 1;
+       }      
+      if ( (0 == strncasecmp (ptr,
+                             key,
+                             keylen)) &&
+          (eq == &ptr[keylen]) )
+       {
+         if (NULL == q2)
+           {
+             len = strlen (q1) + 1;
+             if (size > len)
+               size = len;
+             size--;
+             strncpy (dest,
+                      q1,
+                      size);
+             dest[size] = '\0';
+             return size;
+           }
+         else
+           {
+             if (size > (q2 - q1) + 1)
+               size = (q2 - q1) + 1;
+             size--;
+             memcpy (dest, 
+                     q1,
+                     size);
+             dest[size] = '\0';
+             return size;
+           }
+       }
+      if (NULL == qn)
+       return 0;
+      ptr = strchr (qn, ',');
+      if (NULL == ptr)
+       return 0;
+      ptr++;
+      while (' ' == *ptr)
+       ptr++;
+    }
+  return 0;
+}
+
+
+/**
+ * Check nonce-nc map array with either new nonce counter
+ * or a whole new nonce.
+ *
+ * @param connection The MHD connection structure
+ * @param nonce A pointer that referenced a zero-terminated array of nonce
+ * @param nc The nonce counter, zero to add the nonce to the array
+ * @return MHD_YES if successful, MHD_NO if invalid (or we have no NC array)
+ */
+static int
+check_nonce_nc (struct MHD_Connection *connection,
+               const char *nonce,
+               unsigned long int nc)
+{
+  uint32_t off;
+  uint32_t mod;
+  const char *np;
+
+  mod = connection->daemon->nonce_nc_size;
+  if (0 == mod)
+    return MHD_NO; /* no array! */
+  /* super-fast xor-based "hash" function for HT lookup in nonce array */
+  off = 0;
+  np = nonce;
+  while ('\0' != *np)
+    {
+      off = (off << 8) | (*np ^ (off >> 24));
+      np++;
+    }
+  off = off % mod;
+  /*
+   * Look for the nonce, if it does exist and its corresponding
+   * nonce counter is less than the current nonce counter by 1,
+   * then only increase the nonce counter by one.
+   */
+  
+  pthread_mutex_lock (&connection->daemon->nnc_lock);
+  if (0 == nc)
+    {
+      strcpy(connection->daemon->nnc[off].nonce, 
+            nonce);
+      connection->daemon->nnc[off].nc = 0;  
+      pthread_mutex_unlock (&connection->daemon->nnc_lock);
+      return MHD_YES;
+    }
+  if ( (nc <= connection->daemon->nnc[off].nc) ||
+       (0 != strcmp(connection->daemon->nnc[off].nonce, nonce)) )
+    {
+      pthread_mutex_unlock (&connection->daemon->nnc_lock);
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon, 
+               "Stale nonce received.  If this happens a lot, you should 
probably increase the size of the nonce array.\n");
+#endif
+      return MHD_NO;
+    }
+  connection->daemon->nnc[off].nc = nc;
+  pthread_mutex_unlock (&connection->daemon->nnc_lock);
+  return MHD_YES;
+}
+
+
+/**
+ * Get the username from the authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @return NULL if no username could be found, a pointer
+ *                     to the username if found
+ */
+char *
+MHD_digest_auth_get_username(struct MHD_Connection *connection)
+{
+  size_t len;
+  char user[MAX_USERNAME_LENGTH];
+  const char *header;
+  
+  if (NULL == (header = MHD_lookup_connection_value (connection,
+                                                    MHD_HEADER_KIND, 
+                                                    
MHD_HTTP_HEADER_AUTHORIZATION)))
+    return NULL;
+  if (0 != strncmp (header, _BASE, strlen (_BASE)))
+    return NULL;
+  header += strlen (_BASE);
+  if (0 == (len = lookup_sub_value (user,
+                                   sizeof (user),
+                                   header, 
+                                   "username")))
+    return NULL;
+  return strdup (user);
+}
+
+
+/**
+ * Calculate the server nonce so that it mitigates replay attacks
+ * The current format of the nonce is ...
+ * H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp)
+ *
+ * @param nonce_time The amount of time in seconds for a nonce to be invalid
+ * @param method HTTP method
+ * @param rnd A pointer to a character array for the random seed
+ * @param rnd_size The size of the random seed array
+ * @param uri HTTP URI (in MHD, without the arguments ("?k=v")
+ * @param realm A string of characters that describes the realm of auth.
+ * @param nonce A pointer to a character array for the nonce to put in
+ */
+static void
+calculate_nonce (uint32_t nonce_time,
+                const char *method,
+                const char *rnd,
+                unsigned int rnd_size,
+                const char *uri,
+                const char *realm,
+                char *nonce)
+{
+  struct MD5Context md5;
+  unsigned char timestamp[4];
+  unsigned char tmpnonce[MD5_DIGEST_SIZE];
+  char timestamphex[sizeof(timestamp) * 2 + 1];
+
+  MD5Init (&md5);
+  timestamp[0] = (nonce_time & 0xff000000) >> 0x18;
+  timestamp[1] = (nonce_time & 0x00ff0000) >> 0x10;
+  timestamp[2] = (nonce_time & 0x0000ff00) >> 0x08;
+  timestamp[3] = (nonce_time & 0x000000ff);    
+  MD5Update (&md5, timestamp, 4);
+  MD5Update (&md5, ":", 1);
+  MD5Update (&md5, method, strlen(method));
+  MD5Update (&md5, ":", 1);
+  if (rnd_size > 0)
+    MD5Update (&md5, rnd, rnd_size);
+  MD5Update (&md5, ":", 1);
+  MD5Update (&md5, uri, strlen(uri));
+  MD5Update (&md5, ":", 1);
+  MD5Update (&md5, realm, strlen(realm));
+  MD5Final (tmpnonce, &md5);  
+  cvthex (tmpnonce, sizeof (tmpnonce), nonce);  
+  cvthex (timestamp, 4, timestamphex);
+  strncat (nonce, timestamphex, 8);
+}
+
+
+/**
+ * Test if the given key-value pair is in the headers for the
+ * given connection.
+ *
+ * @param connection the connection
+ * @param key the key
+ * @param value the value, can be NULL
+ * @return MHD_YES if the key-value pair is in the headers, 
+ *         MHD_NO if not
+ */
+static int
+test_header (struct MHD_Connection *connection,
+            const char *key,
+            const char *value)
+{
+  struct MHD_HTTP_Header *pos;
+
+  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
+    {
+      if (MHD_GET_ARGUMENT_KIND != pos->kind)
+       continue;
+      if (0 != strcmp (key, pos->header))
+       continue;
+      if ( (NULL == value) && 
+          (NULL == pos->value) )
+       return MHD_YES;
+      if ( (NULL == value) || 
+          (NULL == pos->value) ||
+          (0 != strcmp (value, pos->value)) )
+       continue;
+      return MHD_YES;      
+    }
+  return MHD_NO;
+}
+
+
+/**
+ * Check that the arguments given by the client as part
+ * of the authentication header match the arguments we
+ * got as part of the HTTP request URI.
+ *
+ * @param connection connections with headers to compare against
+ * @param args argument URI string (after "?" in URI)
+ * @return MHD_YES if the arguments match,
+ *         MHD_NO if not
+ */
+static int
+check_argument_match (struct MHD_Connection *connection,
+                     const char *args)
+{
+  struct MHD_HTTP_Header *pos;
+  size_t slen = strlen (args) + 1;
+  char argb[slen];
+  char *argp;
+  char *equals;
+  char *amper;
+  unsigned int num_headers;
+
+  num_headers = 0;
+  memcpy (argb, args, slen);
+  argp = argb;
+  while ( (NULL != argp) &&
+         ('\0' != argp[0]) )
+    {
+      equals = strchr (argp, '=');
+      if (NULL == equals) 
+       {         
+         /* add with 'value' NULL */
+         connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                                connection,
+                                                argp);
+         if (MHD_YES != test_header (connection, argp, NULL))
+           return MHD_NO;
+         num_headers++;
+         break;
+       }
+      equals[0] = '\0';
+      equals++;
+      amper = strchr (equals, '&');
+      if (NULL != amper)
+       {
+         amper[0] = '\0';
+         amper++;
+       }
+      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                            connection,
+                                            argp);
+      connection->daemon->unescape_callback 
(connection->daemon->unescape_callback_cls,
+                                            connection,
+                                            equals);
+      if (! test_header (connection, argp, equals))
+       return MHD_NO;
+      num_headers++;
+      argp = amper;
+    }
+  
+  /* also check that the number of headers matches */
+  for (pos = connection->headers_received; NULL != pos; pos = pos->next)
+    {
+      if (MHD_GET_ARGUMENT_KIND != pos->kind)
+       continue;
+      num_headers--;
+    }
+  if (0 != num_headers)  
+    return MHD_NO;
+  return MHD_YES;
+}
+
+
+/**
+ * Authenticates the authorization header sent by the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm The realm presented to the client
+ * @param username The username needs to be authenticated
+ * @param password The password used in the authentication
+ * @param nonce_timeout The amount of time for a nonce to be
+ *                     invalid in seconds
+ * @return MHD_YES if authenticated, MHD_NO if not,
+ *                     MHD_INVALID_NONCE if nonce is invalid
+ */
+int
+MHD_digest_auth_check (struct MHD_Connection *connection,
+                      const char *realm,
+                      const char *username,
+                      const char *password,
+                      unsigned int nonce_timeout)
+{
+  size_t len;
+  const char *header;
+  char *end;
+  char nonce[MAX_NONCE_LENGTH];
+  char cnonce[MAX_NONCE_LENGTH];
+  char qop[15]; /* auth,auth-int */
+  char nc[20];
+  char response[MAX_AUTH_RESPONSE_LENGTH];
+  const char *hentity = NULL; /* "auth-int" is not supported */
+  char ha1[HASH_MD5_HEX_LEN + 1];
+  char respexp[HASH_MD5_HEX_LEN + 1];
+  char noncehashexp[HASH_MD5_HEX_LEN + 9];
+  uint32_t nonce_time;
+  uint32_t t;
+  size_t left; /* number of characters left in 'header' for 'uri' */
+  unsigned long int nci;
+
+  header = MHD_lookup_connection_value (connection,
+                                       MHD_HEADER_KIND,
+                                       MHD_HTTP_HEADER_AUTHORIZATION);  
+  if (NULL == header) 
+    return MHD_NO;
+  if (0 != strncmp(header, _BASE, strlen(_BASE))) 
+    return MHD_NO;
+  header += strlen (_BASE);
+  left = strlen (header);
+
+  {
+    char un[MAX_USERNAME_LENGTH];
+
+    len = lookup_sub_value (un,
+                           sizeof (un),
+                           header, "username");
+    if ( (0 == len) ||
+        (0 != strcmp(username, un)) ) 
+      return MHD_NO;
+    left -= strlen ("username") + len;
+  }
+
+  {
+    char r[MAX_REALM_LENGTH];
+
+    len = lookup_sub_value(r, 
+                          sizeof (r),
+                          header, "realm");  
+    if ( (0 == len) || 
+        (0 != strcmp(realm, r)) )
+      return MHD_NO;
+    left -= strlen ("realm") + len;
+  }
+
+  if (0 == (len = lookup_sub_value (nonce, 
+                                   sizeof (nonce),
+                                   header, "nonce")))
+    return MHD_NO;
+  left -= strlen ("nonce") + len;
+
+  {
+    char uri[left];  
+  
+    if (0 == lookup_sub_value(uri,
+                             sizeof (uri),
+                             header, "uri")) 
+      return MHD_NO;
+      
+    /* 8 = 4 hexadecimal numbers for the timestamp */  
+    nonce_time = strtoul(nonce + len - 8, (char **)NULL, 16);  
+    t = (uint32_t) MHD_monotonic_time();    
+    /*
+     * First level vetting for the nonce validity if the timestamp
+     * attached to the nonce exceeds `nonce_timeout' then the nonce is
+     * invalid.
+     */
+    if ( (t > nonce_time + nonce_timeout) ||
+        (nonce_time + nonce_timeout < nonce_time) )
+      return MHD_INVALID_NONCE;
+    if (0 != strncmp (uri,
+                     connection->url,
+                     strlen (connection->url)))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon, 
+               "Authentication failed, URI does not match.\n");
+#endif
+      return MHD_NO;
+    }
+    {
+      const char *args = strchr (uri, '?');
+
+      if (NULL == args)
+       args = "";
+      else
+       args++;
+      if (MHD_YES !=
+         check_argument_match (connection,
+                               args) ) 
+      {
+#if HAVE_MESSAGES
+       MHD_DLOG (connection->daemon, 
+                 "Authentication failed, arguments do not match.\n");
+#endif
+       return MHD_NO;
+      }
+    }
+    calculate_nonce (nonce_time,
+                    connection->method,
+                    connection->daemon->digest_auth_random,
+                    connection->daemon->digest_auth_rand_size,
+                    connection->url,
+                    realm,
+                    noncehashexp);
+    /*
+     * Second level vetting for the nonce validity
+     * if the timestamp attached to the nonce is valid
+     * and possibly fabricated (in case of an attack)
+     * the attacker must also know the random seed to be
+     * able to generate a "sane" nonce, which if he does
+     * not, the nonce fabrication process going to be
+     * very hard to achieve.
+     */
+    
+    if (0 != strcmp (nonce, noncehashexp))
+      return MHD_INVALID_NONCE;
+    if ( (0 == lookup_sub_value (cnonce,
+                                sizeof (cnonce), 
+                                header, "cnonce")) ||
+        (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) ||
+        ( (0 != strcmp (qop, "auth")) && 
+          (0 != strcmp (qop, "")) ) ||
+        (0 == lookup_sub_value (nc, sizeof (nc), header, "nc"))  ||
+        (0 == lookup_sub_value (response, sizeof (response), header, 
"response")) )
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon, 
+               "Authentication failed, invalid format.\n");
+#endif
+      return MHD_NO;
+    }
+    nci = strtoul (nc, &end, 16);
+    if ( ('\0' != *end) ||
+        ( (LONG_MAX == nci) && 
+          (ERANGE == errno) ) )
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon, 
+               "Authentication failed, invalid format.\n");
+#endif
+      return MHD_NO; /* invalid nonce format */
+    }
+    /*
+     * Checking if that combination of nonce and nc is sound
+     * and not a replay attack attempt. Also adds the nonce
+     * to the nonce-nc map if it does not exist there.
+     */
+    
+    if (MHD_YES != check_nonce_nc (connection, nonce, nci))
+      return MHD_NO;
+    
+    digest_calc_ha1("md5",
+                   username,
+                   realm,
+                   password,
+                   nonce,
+                   cnonce,
+                   ha1);
+    digest_calc_response (ha1,
+                         nonce,
+                         nc,
+                         cnonce,
+                         qop,
+                         connection->method,
+                         uri,
+                         hentity,
+                         respexp);  
+    return (0 == strcmp(response, respexp)) 
+      ? MHD_YES 
+      : MHD_NO;
+  }
+}
+
+
+/**
+ * Queues a response to request authentication from the client
+ *
+ * @param connection The MHD connection structure
+ * @param realm the realm presented to the client
+ * @param opaque string to user for opaque value
+ * @param response reply to send; should contain the "access denied"
+ *        body; note that this function will set the "WWW Authenticate"
+ *        header and that the caller should not do this
+ * @param signal_stale MHD_YES if the nonce is invalid to add
+ *                     'stale=true' to the authentication header
+ * @return MHD_YES on success, MHD_NO otherwise
+ */
+int
+MHD_queue_auth_fail_response (struct MHD_Connection *connection,
+                             const char *realm,
+                             const char *opaque,
+                             struct MHD_Response *response,
+                             int signal_stale)
+{
+  int ret;
+  size_t hlen;
+  char nonce[HASH_MD5_HEX_LEN + 9];
+
+  /* Generating the server nonce */  
+  calculate_nonce ((uint32_t) MHD_monotonic_time(),
+                  connection->method,
+                  connection->daemon->digest_auth_random,
+                  connection->daemon->digest_auth_rand_size,
+                  connection->url,
+                  realm,
+                  nonce);
+  if (MHD_YES != check_nonce_nc (connection, nonce, 0))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (connection->daemon, 
+               "Could not register nonce (is the nonce array size zero?).\n");
+#endif
+      return MHD_NO;  
+    }
+  /* Building the authentication header */
+  hlen = snprintf (NULL,
+                  0,
+                  "Digest 
realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
+                  realm, 
+                  nonce,
+                  opaque,
+                  signal_stale 
+                  ? ",stale=\"true\"" 
+                  : "");
+  {
+    char header[hlen + 1];
+
+    snprintf (header,
+             sizeof(header),
+             "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s",
+             realm, 
+             nonce,
+             opaque,
+             signal_stale 
+             ? ",stale=\"true\"" 
+             : "");
+    ret = MHD_add_response_header(response,
+                                 MHD_HTTP_HEADER_WWW_AUTHENTICATE, 
+                                 header);
+  }
+  if (MHD_YES == ret) 
+    ret = MHD_queue_response(connection, 
+                            MHD_HTTP_UNAUTHORIZED, 
+                            response);  
+  return ret;
+}
+
+
+/* end of digestauth.c */

Deleted: libmicrohttpd/src/microhttpd/internal.c
===================================================================
--- libmicrohttpd/src/daemon/internal.c 2013-05-05 12:01:06 UTC (rev 27023)
+++ libmicrohttpd/src/microhttpd/internal.c     2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,170 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2007 Daniel Pittman and Christian Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-*/
-
-/**
- * @file internal.h
- * @brief  internal shared structures
- * @author Daniel Pittman
- * @author Christian Grothoff
- */
-
-#include "internal.h"
-
-#if HAVE_MESSAGES
-#if DEBUG_STATES
-/**
- * State to string dictionary.
- */
-const char *
-MHD_state_to_string (enum MHD_CONNECTION_STATE state)
-{
-  switch (state)
-    {
-    case MHD_CONNECTION_INIT:
-      return "connection init";
-    case MHD_CONNECTION_URL_RECEIVED:
-      return "connection url received";
-    case MHD_CONNECTION_HEADER_PART_RECEIVED:
-      return "header partially received";
-    case MHD_CONNECTION_HEADERS_RECEIVED:
-      return "headers received";
-    case MHD_CONNECTION_HEADERS_PROCESSED:
-      return "headers processed";
-    case MHD_CONNECTION_CONTINUE_SENDING:
-      return "continue sending";
-    case MHD_CONNECTION_CONTINUE_SENT:
-      return "continue sent";
-    case MHD_CONNECTION_BODY_RECEIVED:
-      return "body received";
-    case MHD_CONNECTION_FOOTER_PART_RECEIVED:
-      return "footer partially received";
-    case MHD_CONNECTION_FOOTERS_RECEIVED:
-      return "footers received";
-    case MHD_CONNECTION_HEADERS_SENDING:
-      return "headers sending";
-    case MHD_CONNECTION_HEADERS_SENT:
-      return "headers sent";
-    case MHD_CONNECTION_NORMAL_BODY_READY:
-      return "normal body ready";
-    case MHD_CONNECTION_NORMAL_BODY_UNREADY:
-      return "normal body unready";
-    case MHD_CONNECTION_CHUNKED_BODY_READY:
-      return "chunked body ready";
-    case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
-      return "chunked body unready";
-    case MHD_CONNECTION_BODY_SENT:
-      return "body sent";
-    case MHD_CONNECTION_FOOTERS_SENDING:
-      return "footers sending";
-    case MHD_CONNECTION_FOOTERS_SENT:
-      return "footers sent";
-    case MHD_CONNECTION_CLOSED:
-      return "closed";
-    case MHD_TLS_CONNECTION_INIT:
-      return "secure connection init";
-    default:
-      return "unrecognized connection state";
-    }
-}
-#endif
-#endif
-
-#if HAVE_MESSAGES
-/**
- * fprintf-like helper function for logging debug
- * messages.
- */
-void
-MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...)
-{
-  va_list va;
-
-  if ((daemon->options & MHD_USE_DEBUG) == 0)
-    return;
-  va_start (va, format);
-  daemon->custom_error_log (daemon->custom_error_log_cls, format, va);
-  va_end (va);
-}
-#endif
-
-
-/**
- * Process escape sequences ('+'=space, %HH) Updates val in place; the
- * result should be UTF-8 encoded and cannot be larger than the input.
- * The result must also still be 0-terminated.
- *
- * @param cls closure (use NULL)
- * @param connection handle to connection, not used
- * @return length of the resulting val (strlen(val) maybe
- *  shorter afterwards due to elimination of escape sequences)
- */
-size_t
-MHD_http_unescape (void *cls,
-                  struct MHD_Connection *connection,
-                  char *val)
-{
-  char *rpos = val;
-  char *wpos = val;
-  char *end;
-  unsigned int num;
-  char buf3[3];
-
-  while ('\0' != *rpos)
-    {
-      switch (*rpos)
-       {
-       case '+':
-         *wpos = ' ';
-         wpos++;
-         rpos++;
-         break;
-       case '%':
-         buf3[0] = rpos[1];
-         buf3[1] = rpos[2];
-         buf3[2] = '\0';
-         num = strtoul (buf3, &end, 16);
-         if ('\0' == *end)
-           {
-             *wpos = (unsigned char) num;
-             wpos++;
-             rpos += 3;
-             break;
-           }
-         /* intentional fall through! */
-       default:
-         *wpos = *rpos;
-         wpos++;
-         rpos++;
-       }
-    }
-  *wpos = '\0'; /* add 0-terminator */
-  return wpos - val; /* = strlen(val) */
-}
-
-time_t MHD_monotonic_time(void)
-{
-#ifdef HAVE_CLOCK_GETTIME
-    struct timespec ts;
-    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
-       return ts.tv_sec;
-#endif
-    return time(NULL);
-}
-
-/* end of internal.c */

Copied: libmicrohttpd/src/microhttpd/internal.c (from rev 27024, 
libmicrohttpd/src/daemon/internal.c)
===================================================================
--- libmicrohttpd/src/microhttpd/internal.c                             (rev 0)
+++ libmicrohttpd/src/microhttpd/internal.c     2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,171 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007 Daniel Pittman and Christian Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+*/
+
+/**
+ * @file internal.h
+ * @brief  internal shared structures
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ */
+
+#include "internal.h"
+
+#if HAVE_MESSAGES
+#if DEBUG_STATES
+/**
+ * State to string dictionary.
+ */
+const char *
+MHD_state_to_string (enum MHD_CONNECTION_STATE state)
+{
+  switch (state)
+    {
+    case MHD_CONNECTION_INIT:
+      return "connection init";
+    case MHD_CONNECTION_URL_RECEIVED:
+      return "connection url received";
+    case MHD_CONNECTION_HEADER_PART_RECEIVED:
+      return "header partially received";
+    case MHD_CONNECTION_HEADERS_RECEIVED:
+      return "headers received";
+    case MHD_CONNECTION_HEADERS_PROCESSED:
+      return "headers processed";
+    case MHD_CONNECTION_CONTINUE_SENDING:
+      return "continue sending";
+    case MHD_CONNECTION_CONTINUE_SENT:
+      return "continue sent";
+    case MHD_CONNECTION_BODY_RECEIVED:
+      return "body received";
+    case MHD_CONNECTION_FOOTER_PART_RECEIVED:
+      return "footer partially received";
+    case MHD_CONNECTION_FOOTERS_RECEIVED:
+      return "footers received";
+    case MHD_CONNECTION_HEADERS_SENDING:
+      return "headers sending";
+    case MHD_CONNECTION_HEADERS_SENT:
+      return "headers sent";
+    case MHD_CONNECTION_NORMAL_BODY_READY:
+      return "normal body ready";
+    case MHD_CONNECTION_NORMAL_BODY_UNREADY:
+      return "normal body unready";
+    case MHD_CONNECTION_CHUNKED_BODY_READY:
+      return "chunked body ready";
+    case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
+      return "chunked body unready";
+    case MHD_CONNECTION_BODY_SENT:
+      return "body sent";
+    case MHD_CONNECTION_FOOTERS_SENDING:
+      return "footers sending";
+    case MHD_CONNECTION_FOOTERS_SENT:
+      return "footers sent";
+    case MHD_CONNECTION_CLOSED:
+      return "closed";
+    case MHD_TLS_CONNECTION_INIT:
+      return "secure connection init";
+    default:
+      return "unrecognized connection state";
+    }
+}
+#endif
+#endif
+
+#if HAVE_MESSAGES
+/**
+ * fprintf-like helper function for logging debug
+ * messages.
+ */
+void
+MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...)
+{
+  va_list va;
+
+  if ((daemon->options & MHD_USE_DEBUG) == 0)
+    return;
+  va_start (va, format);
+  daemon->custom_error_log (daemon->custom_error_log_cls, format, va);
+  va_end (va);
+}
+#endif
+
+
+/**
+ * Process escape sequences ('+'=space, %HH) Updates val in place; the
+ * result should be UTF-8 encoded and cannot be larger than the input.
+ * The result must also still be 0-terminated.
+ *
+ * @param cls closure (use NULL)
+ * @param connection handle to connection, not used
+ * @param val value to unescape (modified in the process)
+ * @return length of the resulting val (strlen(val) maybe
+ *  shorter afterwards due to elimination of escape sequences)
+ */
+size_t
+MHD_http_unescape (void *cls,
+                  struct MHD_Connection *connection,
+                  char *val)
+{
+  char *rpos = val;
+  char *wpos = val;
+  char *end;
+  unsigned int num;
+  char buf3[3];
+
+  while ('\0' != *rpos)
+    {
+      switch (*rpos)
+       {
+       case '+':
+         *wpos = ' ';
+         wpos++;
+         rpos++;
+         break;
+       case '%':
+         buf3[0] = rpos[1];
+         buf3[1] = rpos[2];
+         buf3[2] = '\0';
+         num = strtoul (buf3, &end, 16);
+         if ('\0' == *end)
+           {
+             *wpos = (unsigned char) num;
+             wpos++;
+             rpos += 3;
+             break;
+           }
+         /* intentional fall through! */
+       default:
+         *wpos = *rpos;
+         wpos++;
+         rpos++;
+       }
+    }
+  *wpos = '\0'; /* add 0-terminator */
+  return wpos - val; /* = strlen(val) */
+}
+
+time_t MHD_monotonic_time(void)
+{
+#ifdef HAVE_CLOCK_GETTIME
+    struct timespec ts;
+    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+       return ts.tv_sec;
+#endif
+    return time(NULL);
+}
+
+/* end of internal.c */

Deleted: libmicrohttpd/src/microhttpd/internal.h
===================================================================
--- libmicrohttpd/src/daemon/internal.h 2013-05-05 12:01:06 UTC (rev 27023)
+++ libmicrohttpd/src/microhttpd/internal.h     2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,1092 +0,0 @@
-/*
-  This file is part of libmicrohttpd
-  (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
-  
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Lesser General Public
-  License as published by the Free Software Foundation; either
-  version 2.1 of the License, or (at your option) any later version.
-  
-  This library 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
-  Lesser General Public License for more details.
-  
-  You should have received a copy of the GNU Lesser General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
-*/
-
-/**
- * @file internal.h
- * @brief  internal shared structures
- * @author Daniel Pittman
- * @author Christian Grothoff
- */
-
-#ifndef INTERNAL_H
-#define INTERNAL_H
-
-#include "platform.h"
-#include "microhttpd.h"
-#if HTTPS_SUPPORT
-#include <gnutls/gnutls.h>
-#endif
-
-/**
- * Should we perform additional sanity checks at runtime (on our internal
- * invariants)?  This may lead to aborts, but can be useful for debugging.
- */
-#define EXTRA_CHECKS MHD_NO
-
-#define MHD_MAX(a,b) ((a)<(b)) ? (b) : (a)
-#define MHD_MIN(a,b) ((a)<(b)) ? (a) : (b)
-
-
-/**
- * Handler for fatal errors.
- */
-extern MHD_PanicCallback mhd_panic;
-
-/**
- * Closure argument for "mhd_panic".
- */
-extern void *mhd_panic_cls;
-
-#if HAVE_MESSAGES
-/**
- * Trigger 'panic' action based on fatal errors.
- * 
- * @param error message (const char *)
- */
-#define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, msg)
-#else
-/**
- * Trigger 'panic' action based on fatal errors.
- * 
- * @param error message (const char *)
- */
-#define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL)
-#endif
-
-/**
- * Events we care about with respect to poll/select
- * for file descriptors.
- */
-enum MHD_PollActions
-  {
-    /**
-     * No event interests us.
-     */
-    MHD_POLL_ACTION_NOTHING = 0,
-
-    /**
-     * We would like to read.
-     */
-    MHD_POLL_ACTION_IN = 1,
-
-    /**
-     * We would like to write.
-     */ 
-    MHD_POLL_ACTION_OUT = 2
-  };
-
-
-/**
- * Socket descriptor and events we care about.
- */
-struct MHD_Pollfd 
-{
-  /**
-   * Socket descriptor.
-   */
-  int fd;
-
-  /**
-   * Which events do we care about for this socket?
-   */
-  enum MHD_PollActions events;
-};
-
-
-/**
- * Maximum length of a nonce in digest authentication.  32(MD5 Hex) +
- * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera
- * (already) takes more (see Mantis #1633), so we've increased the
- * value to support something longer...
- */
-#define MAX_NONCE_LENGTH 129
-
-
-/**
- * A structure representing the internal holder of the
- * nonce-nc map.
- */
-struct MHD_NonceNc 
-{
-  
-  /**
-   * Nonce counter, a value that increases for each subsequent
-   * request for the same nonce.
-   */
-  unsigned long int nc;
-
-  /**
-   * Nonce value: 
-   */
-  char nonce[MAX_NONCE_LENGTH];
-
-};
-
-#if HAVE_MESSAGES
-/**
- * fprintf-like helper function for logging debug
- * messages.
- */
-void 
-MHD_DLOG (const struct MHD_Daemon *daemon, 
-         const char *format, ...);
-
-#endif
-
-/**
- * Process escape sequences ('+'=space, %HH) Updates val in place; the
- * result should be UTF-8 encoded and cannot be larger than the input.
- * The result must also still be 0-terminated.
- *
- * @param cls closure (use NULL)
- * @param connection handle to connection, not used
- * @return length of the resulting val (strlen(val) maybe
- *  shorter afterwards due to elimination of escape sequences)
- */
-size_t 
-MHD_http_unescape (void *cls,
-                  struct MHD_Connection *connection,
-                  char *val);
-
-
-/**
- * Header or cookie in HTTP request or response.
- */
-struct MHD_HTTP_Header
-{
-  /**
-   * Headers are kept in a linked list.
-   */
-  struct MHD_HTTP_Header *next;
-
-  /**
-   * The name of the header (key), without
-   * the colon.
-   */
-  char *header;
-
-  /**
-   * The value of the header.
-   */
-  char *value;
-
-  /**
-   * Type of the header (where in the HTTP
-   * protocol is this header from).
-   */
-  enum MHD_ValueKind kind;
-
-};
-
-
-/**
- * Representation of a response.
- */
-struct MHD_Response
-{
-
-  /**
-   * Headers to send for the response.  Initially
-   * the linked list is created in inverse order;
-   * the order should be inverted before sending!
-   */
-  struct MHD_HTTP_Header *first_header;
-
-  /**
-   * Buffer pointing to data that we are supposed
-   * to send as a response.
-   */
-  char *data;
-
-  /**
-   * Closure to give to the content reader
-   * free callback.
-   */
-  void *crc_cls;
-
-  /**
-   * How do we get more data?  NULL if we are
-   * given all of the data up front.
-   */
-  MHD_ContentReaderCallback crc;
-
-  /**
-   * NULL if data must not be freed, otherwise
-   * either user-specified callback or "&free".
-   */
-  MHD_ContentReaderFreeCallback crfc;
-
-  /**
-   * Mutex to synchronize access to data/size and
-   * reference counts.
-   */
-  pthread_mutex_t mutex;
-
-  /**
-   * Set to MHD_SIZE_UNKNOWN if size is not known.
-   */
-  uint64_t total_size;
-
-  /**
-   * At what offset in the stream is the
-   * beginning of data located?
-   */
-  uint64_t data_start;
-
-  /**
-   * Offset to start reading from when using 'fd'.
-   */
-  off_t fd_off;
-
-  /**
-   * Size of data.
-   */
-  size_t data_size;
-
-  /**
-   * Size of the data buffer.
-   */
-  size_t data_buffer_size;
-
-  /**
-   * Reference count for this response.  Free
-   * once the counter hits zero.
-   */
-  unsigned int reference_count;
-
-  /**
-   * File-descriptor if this response is FD-backed.
-   */
-  int fd;
-
-};
-
-
-/**
- * States in a state machine for a connection.
- *
- * Transitions are any-state to CLOSED, any state to state+1,
- * FOOTERS_SENT to INIT.  CLOSED is the terminal state and
- * INIT the initial state.
- *
- * Note that transitions for *reading* happen only after
- * the input has been processed; transitions for
- * *writing* happen after the respective data has been
- * put into the write buffer (the write does not have
- * to be completed yet).  A transition to CLOSED or INIT
- * requires the write to be complete.
- */
-enum MHD_CONNECTION_STATE
-{
-  /**
-   * Connection just started (no headers received).
-   * Waiting for the line with the request type, URL and version.
-   */
-  MHD_CONNECTION_INIT = 0,
-
-  /**
-   * 1: We got the URL (and request type and version).  Wait for a header line.
-   */
-  MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1,
-
-  /**
-   * 2: We got part of a multi-line request header.  Wait for the rest.
-   */
-  MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1,
-
-  /**
-   * 3: We got the request headers.  Process them.
-   */
-  MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1,
-
-  /**
-   * 4: We have processed the request headers.  Send 100 continue.
-   */
-  MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
-
-  /**
-   * 5: We have processed the headers and need to send 100 CONTINUE.
-   */
-  MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
-
-  /**
-   * 6: We have sent 100 CONTINUE (or do not need to).  Read the message body.
-   */
-  MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1,
-
-  /**
-   * 7: We got the request body.  Wait for a line of the footer.
-   */
-  MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1,
-
-  /**
-   * 8: We got part of a line of the footer.  Wait for the
-   * rest.
-   */
-  MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1,
-
-  /**
-   * 9: We received the entire footer.  Wait for a response to be queued
-   * and prepare the response headers.
-   */
-  MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1,
-
-  /**
-   * 10: We have prepared the response headers in the writ buffer.
-   * Send the response headers.
-   */
-  MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
-
-  /**
-   * 11: We have sent the response headers.  Get ready to send the body.
-   */
-  MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
-
-  /**
-   * 12: We are ready to send a part of a non-chunked body.  Send it.
-   */
-  MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1,
-
-  /**
-   * 13: We are waiting for the client to provide more
-   * data of a non-chunked body.
-   */
-  MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
-
-  /**
-   * 14: We are ready to send a chunk.
-   */
-  MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
-
-  /**
-   * 15: We are waiting for the client to provide a chunk of the body.
-   */
-  MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
-
-  /**
-   * 16: We have sent the response body. Prepare the footers.
-   */
-  MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
-
-  /**
-   * 17: We have prepared the response footer.  Send it.
-   */
-  MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1,
-
-  /**
-   * 18: We have sent the response footer.  Shutdown or restart.
-   */
-  MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
-
-  /**
-   * 19: This connection is to be closed.
-   */
-  MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1,
-
-  /**
-   * 20: This connection is finished (only to be freed)
-   */
-  MHD_CONNECTION_IN_CLEANUP = MHD_CONNECTION_CLOSED + 1,
-
-  /*
-   *  SSL/TLS connection states
-   */
-
-  /**
-   * The initial connection state for all secure connectoins
-   * Handshake messages will be processed in this state & while
-   * in the 'MHD_TLS_HELLO_REQUEST' state
-   */
-  MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_CLOSED + 1
-
-};
-
-/**
- * Should all state transitions be printed to stderr?
- */
-#define DEBUG_STATES MHD_NO
-
-
-#if HAVE_MESSAGES
-#if DEBUG_STATES
-const char *
-MHD_state_to_string (enum MHD_CONNECTION_STATE state);
-#endif
-#endif
-
-/**
- * Function to receive plaintext data.
- *
- * @param conn the connection struct
- * @param write_to where to write received data
- * @param max_bytes maximum number of bytes to receive
- * @return number of bytes written to write_to
- */
-typedef ssize_t (*ReceiveCallback) (struct MHD_Connection * conn,
-                                    void *write_to, size_t max_bytes);
-
-
-/**
- * Function to transmit plaintext data.
- *
- * @param conn the connection struct
- * @param read_from where to read data to transmit
- * @param max_bytes maximum number of bytes to transmit
- * @return number of bytes transmitted
- */
-typedef ssize_t (*TransmitCallback) (struct MHD_Connection * conn,
-                                     const void *write_to, size_t max_bytes);
-
-
-/**
- * State kept for each HTTP request.
- */
-struct MHD_Connection
-{
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct MHD_Connection *next;
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct MHD_Connection *prev;
-
-  /**
-   * Reference to the MHD_Daemon struct.
-   */
-  struct MHD_Daemon *daemon;
-
-  /**
-   * Linked list of parsed headers.
-   */
-  struct MHD_HTTP_Header *headers_received;
-
-  /**
-   * Tail of linked list of parsed headers.
-   */
-  struct MHD_HTTP_Header *headers_received_tail;
-
-  /**
-   * Response to transmit (initially NULL).
-   */
-  struct MHD_Response *response;
-
-  /**
-   * The memory pool is created whenever we first read
-   * from the TCP stream and destroyed at the end of
-   * each request (and re-created for the next request).
-   * In the meantime, this pointer is NULL.  The
-   * pool is used for all connection-related data
-   * except for the response (which maybe shared between
-   * connections) and the IP address (which persists
-   * across individual requests).
-   */
-  struct MemoryPool *pool;
-
-  /**
-   * We allow the main application to associate some
-   * pointer with the connection.  Here is where we
-   * store it.  (MHD does not know or care what it
-   * is).
-   */
-  void *client_context;
-
-  /**
-   * Request method.  Should be GET/POST/etc.  Allocated
-   * in pool.
-   */
-  char *method;
-
-  /**
-   * Requested URL (everything after "GET" only).  Allocated
-   * in pool.
-   */
-  char *url;
-
-  /**
-   * HTTP version string (i.e. http/1.1).  Allocated
-   * in pool.
-   */
-  char *version;
-
-  /**
-   * Buffer for reading requests.   Allocated
-   * in pool.  Actually one byte larger than
-   * read_buffer_size (if non-NULL) to allow for
-   * 0-termination.
-   */
-  char *read_buffer;
-
-  /**
-   * Buffer for writing response (headers only).  Allocated
-   * in pool.
-   */
-  char *write_buffer;
-
-  /**
-   * Last incomplete header line during parsing of headers.
-   * Allocated in pool.  Only valid if state is
-   * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
-   */
-  char *last;
-
-  /**
-   * Position after the colon on the last incomplete header
-   * line during parsing of headers.
-   * Allocated in pool.  Only valid if state is
-   * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
-   */
-  char *colon;
-
-  /**
-   * Foreign address (of length addr_len).  MALLOCED (not
-   * in pool!).
-   */
-  struct sockaddr *addr;
-
-  /**
-   * Thread for this connection (if we are using
-   * one thread per connection).
-   */
-  pthread_t pid;
-
-  /**
-   * 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;
-
-  /**
-   * Size of write_buffer (in bytes).
-   */
-  size_t write_buffer_size;
-
-  /**
-   * Offset where we are with sending from write_buffer.
-   */
-  size_t write_buffer_send_offset;
-
-  /**
-   * Last valid location in write_buffer (where do we
-   * append and up to where is it safe to send?)
-   */
-  size_t write_buffer_append_offset;
-
-  /**
-   * How many more bytes of the body do we expect
-   * to read? "-1" for unknown.
-   */
-  uint64_t remaining_upload_size;
-
-  /**
-   * Current write position in the actual response
-   * (excluding headers, content only; should be 0
-   * while sending headers).
-   */
-  uint64_t response_write_position;
-
-  /**
-   * Position in the 100 CONTINUE message that
-   * we need to send when receiving http 1.1 requests.
-   */
-  size_t continue_message_write_offset;
-
-  /**
-   * Length of the foreign address.
-   */
-  socklen_t addr_len;
-
-  /**
-   * Last time this connection had any activity
-   * (reading or writing).
-   */
-  time_t last_activity;
-
-  /**
-   * After how many seconds of inactivity should
-   * this connection time out?  Zero for no timeout.
-   */
-  unsigned int connection_timeout;
-
-  /**
-   * Did we ever call the "default_handler" on this connection?
-   * (this flag will determine if we call the 'notify_completed'
-   * handler when the connection closes down).
-   */
-  int client_aware;
-
-  /**
-   * Socket for this connection.  Set to -1 if
-   * this connection has died (daemon should clean
-   * up in that case).
-   */
-  int socket_fd;
-
-  /**
-   * 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).
-   */
-  int read_closed;
-
-  /**
-   * Set to MHD_YES if the thread has been joined.
-   */
-  int thread_joined;
-
-  /**
-   * State in the FSM for this connection.
-   */
-  enum MHD_CONNECTION_STATE state;
-
-  /**
-   * HTTP response code.  Only valid if response object
-   * is already set.
-   */
-  unsigned int responseCode;
-
-  /**
-   * Set to MHD_YES if the response's content reader
-   * callback failed to provide data the last time
-   * we tried to read from it.  In that case, the
-   * write socket should be marked as unready until
-   * the CRC call succeeds.
-   */
-  int response_unready;
-
-  /**
-   * Are we receiving with chunked encoding?  This will be set to
-   * MHD_YES after we parse the headers and are processing the body
-   * with chunks.  After we are done with the body and we are
-   * processing the footers; once the footers are also done, this will
-   * be set to MHD_NO again (before the final call to the handler).
-   */
-  int have_chunked_upload;
-
-  /**
-   * If we are receiving with chunked encoding, where are we right
-   * now?  Set to 0 if we are waiting to receive the chunk size;
-   * otherwise, this is the size of the current chunk.  A value of
-   * zero is also used when we're at the end of the chunks.
-   */
-  unsigned int current_chunk_size;
-
-  /**
-   * If we are receiving with chunked encoding, where are we currently
-   * with respect to the current chunk (at what offset / position)?
-   */
-  unsigned int current_chunk_offset;
-
-  /**
-   * Handler used for processing read connection operations
-   */
-  int (*read_handler) (struct MHD_Connection * connection);
-
-  /**
-   * Handler used for processing write connection operations
-   */
-  int (*write_handler) (struct MHD_Connection * connection);
-
-  /**
-   * Handler used for processing idle connection operations
-   */
-  int (*idle_handler) (struct MHD_Connection * connection);
-
-  /**
-   * Function used for reading HTTP request stream.
-   */
-  ReceiveCallback recv_cls;
-
-  /**
-   * Function used for writing HTTP response stream.
-   */
-  TransmitCallback send_cls;
-
-#if HTTPS_SUPPORT
-  /**
-   * State required for HTTPS/SSL/TLS support.
-   */
-  gnutls_session_t tls_session;
-
-  /**
-   * Memory location to return for protocol session info.
-   */
-  int protocol;
-
-  /**
-   * Memory location to return for protocol session info.
-   */
-  int cipher;
-
-  /**
-   * Could it be that we are ready to read due to TLS buffers
-   * even though the socket is not?
-   */
-  int tls_read_ready;
-
-#endif
-};
-
-/**
- * Signature of function called to log URI accesses.
- *
- * @param cls closure
- * @param uri uri being accessed
- * @return new closure
- */
-typedef void * (*LogCallback)(void * cls, const char * uri);
-
-/**
- * Signature of function called to unescape URIs.  See also
- * MHD_http_unescape.
- *
- * @param cls closure
- * @param conn connection handle
- * @param uri 0-terminated string to unescape (should be updated)
- * @return length of the resulting string
- */
-typedef size_t (*UnescapeCallback)(void *cls,
-                                  struct MHD_Connection *conn,
-                                  char *uri);
-
-
-/**
- * State kept for each MHD daemon.
- */
-struct MHD_Daemon
-{
-
-  /**
-   * Callback function for all requests.
-   */
-  MHD_AccessHandlerCallback default_handler;
-
-  /**
-   * Closure argument to default_handler.
-   */
-  void *default_handler_cls;
-
-  /**
-   * Tail of doubly-linked list of our current, active connections.
-   */
-  struct MHD_Connection *connections_head;
-
-  /**
-   * Tail of doubly-linked list of our current, active connections.
-   */
-  struct MHD_Connection *connections_tail;
-
-  /**
-   * Tail of doubly-linked list of connections to clean up.
-   */
-  struct MHD_Connection *cleanup_head;
-
-  /**
-   * Tail of doubly-linked list of connections to clean up.
-   */
-  struct MHD_Connection *cleanup_tail;
-
-  /**
-   * Function to call to check if we should
-   * accept or reject an incoming request.
-   * May be NULL.
-   */
-  MHD_AcceptPolicyCallback apc;
-
-  /**
-   * Closure argument to apc.
-   */
-  void *apc_cls;
-
-  /**
-   * Function to call when we are done processing
-   * a particular request.  May be NULL.
-   */
-  MHD_RequestCompletedCallback notify_completed;
-
-  /**
-   * Closure argument to notify_completed.
-   */
-  void *notify_completed_cls;
-
-  /**
-   * Function to call with the full URI at the
-   * beginning of request processing.  May be NULL.
-   * <p>
-   * Returns the initial pointer to internal state
-   * kept by the client for the request.
-   */
-  LogCallback uri_log_callback;
-
-  /**
-   * Closure argument to uri_log_callback.
-   */
-  void *uri_log_callback_cls;
-
-  /**
-   * Function to call when we unescape escape sequences.
-   */
-  UnescapeCallback unescape_callback;
-
-  /**
-   * Closure for unescape callback.
-   */
-  void *unescape_callback_cls;
-
-#if HAVE_MESSAGES
-  /**
-   * Function for logging error messages (if we
-   * support error reporting).
-   */
-  void (*custom_error_log) (void *cls, const char *fmt, va_list va);
-
-  /**
-   * Closure argument to custom_error_log.
-   */
-  void *custom_error_log_cls;
-#endif
-
-  /**
-   * Pointer to master daemon (NULL if this is the master)
-   */
-  struct MHD_Daemon *master;
-
-  /**
-   * Worker daemons (one per thread)
-   */
-  struct MHD_Daemon *worker_pool;
-
-  /**
-   * Table storing number of connections per IP
-   */
-  void *per_ip_connection_count;
-
-  /**
-   * Size of the per-connection memory pools.
-   */
-  size_t pool_size;
-
-  /**
-   * Size of threads created by MHD.
-   */
-  size_t thread_stack_size;
-
-  /**
-   * Number of worker daemons
-   */
-  unsigned int worker_pool_size;
-
-  /**
-   * PID of the select thread (if we have internal select)
-   */
-  pthread_t pid;
-
-  /**
-   * Mutex for per-IP connection counts.
-   */
-  pthread_mutex_t per_ip_connection_mutex;
-
-  /**
-   * Mutex for (modifying) access to the "cleanup" connection DLL.
-   */
-  pthread_mutex_t cleanup_connection_mutex;
-
-  /**
-   * Listen socket.
-   */
-  int socket_fd;
-
-  /**
-   * Pipe we use to signal shutdown, unless
-   * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen
-   * socket (which we can then 'shutdown' to stop listening).
-   */
-  int wpipe[2];
-
-  /**
-   * Are we shutting down?
-   */
-  int shutdown;
-
-  /**
-   * Limit on the number of parallel connections.
-   */
-  unsigned int max_connections;
-
-  /**
-   * After how many seconds of inactivity should
-   * connections time out?  Zero for no timeout.
-   */
-  unsigned int connection_timeout;
-
-  /**
-   * Maximum number of connections per IP, or 0 for
-   * unlimited.
-   */
-  unsigned int per_ip_connection_limit;
-
-  /**
-   * Daemon's options.
-   */
-  enum MHD_OPTION options;
-
-  /**
-   * Listen port.
-   */
-  uint16_t port;
-
-#if HTTPS_SUPPORT
-  /**
-   * Desired cipher algorithms.
-   */
-  gnutls_priority_t priority_cache;
-
-  /**
-   * What kind of credentials are we offering
-   * for SSL/TLS?
-   */
-  gnutls_credentials_type_t cred_type;
-
-  /**
-   * Server x509 credentials
-   */
-  gnutls_certificate_credentials_t x509_cred;
-
-  /**
-   * Diffie-Hellman parameters
-   */
-  gnutls_dh_params_t dh_params;
-
-  /**
-   * Pointer to our SSL/TLS key (in ASCII) in memory.
-   */
-  const char *https_mem_key;
-
-  /**
-   * Pointer to our SSL/TLS certificate (in ASCII) in memory.
-   */
-  const char *https_mem_cert;
-
-  /**
-   * Pointer to our SSL/TLS certificate authority (in ASCII) in memory.
-   */
-  const char *https_mem_trust;
-
-#endif
-
-#ifdef DAUTH_SUPPORT
-
-  /**
-   * Character array of random values.
-   */
-  const char *digest_auth_random;
-
-  /**
-   * An array that contains the map nonce-nc.
-   */
-  struct MHD_NonceNc *nnc;
-
-  /**
-   * A rw-lock for synchronizing access to `nnc'.
-   */
-  pthread_mutex_t nnc_lock;
-
-  /**
-   * Size of `digest_auth_random.
-   */
-  unsigned int digest_auth_rand_size;
-
-  /**
-   * Size of the nonce-nc array.
-   */
-  unsigned int nonce_nc_size;
-
-#endif
-
-};
-
-
-#if EXTRA_CHECKS
-#define EXTRA_CHECK(a) if (!(a)) abort();
-#else
-#define EXTRA_CHECK(a)
-#endif
-
-
-/**
- * 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
- * @param tail pointer to the tail of the DLL
- * @param element element to insert
- */
-#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
- * @param tail pointer to the tail of the DLL
- * @param element element to remove
- */
-#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)
-
-
-/**
- * Equivalent to time(NULL) but tries to use some sort of monotonic
- * clock that isn't affected by someone setting the system real time
- * clock.
- */
-time_t MHD_monotonic_time(void);
-
-#endif

Copied: libmicrohttpd/src/microhttpd/internal.h (from rev 27024, 
libmicrohttpd/src/daemon/internal.h)
===================================================================
--- libmicrohttpd/src/microhttpd/internal.h                             (rev 0)
+++ libmicrohttpd/src/microhttpd/internal.h     2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,1093 @@
+/*
+  This file is part of libmicrohttpd
+  (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
+  
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+  
+  This library 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
+  Lesser General Public License for more details.
+  
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+*/
+
+/**
+ * @file internal.h
+ * @brief  internal shared structures
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ */
+
+#ifndef INTERNAL_H
+#define INTERNAL_H
+
+#include "platform.h"
+#include "microhttpd.h"
+#if HTTPS_SUPPORT
+#include <gnutls/gnutls.h>
+#endif
+
+/**
+ * Should we perform additional sanity checks at runtime (on our internal
+ * invariants)?  This may lead to aborts, but can be useful for debugging.
+ */
+#define EXTRA_CHECKS MHD_NO
+
+#define MHD_MAX(a,b) ((a)<(b)) ? (b) : (a)
+#define MHD_MIN(a,b) ((a)<(b)) ? (a) : (b)
+
+
+/**
+ * Handler for fatal errors.
+ */
+extern MHD_PanicCallback mhd_panic;
+
+/**
+ * Closure argument for "mhd_panic".
+ */
+extern void *mhd_panic_cls;
+
+#if HAVE_MESSAGES
+/**
+ * Trigger 'panic' action based on fatal errors.
+ * 
+ * @param msg error message (const char *)
+ */
+#define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, msg)
+#else
+/**
+ * Trigger 'panic' action based on fatal errors.
+ * 
+ * @param msg error message (const char *)
+ */
+#define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL)
+#endif
+
+/**
+ * Events we care about with respect to poll/select
+ * for file descriptors.
+ */
+enum MHD_PollActions
+  {
+    /**
+     * No event interests us.
+     */
+    MHD_POLL_ACTION_NOTHING = 0,
+
+    /**
+     * We would like to read.
+     */
+    MHD_POLL_ACTION_IN = 1,
+
+    /**
+     * We would like to write.
+     */ 
+    MHD_POLL_ACTION_OUT = 2
+  };
+
+
+/**
+ * Socket descriptor and events we care about.
+ */
+struct MHD_Pollfd 
+{
+  /**
+   * Socket descriptor.
+   */
+  int fd;
+
+  /**
+   * Which events do we care about for this socket?
+   */
+  enum MHD_PollActions events;
+};
+
+
+/**
+ * Maximum length of a nonce in digest authentication.  32(MD5 Hex) +
+ * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera
+ * (already) takes more (see Mantis #1633), so we've increased the
+ * value to support something longer...
+ */
+#define MAX_NONCE_LENGTH 129
+
+
+/**
+ * A structure representing the internal holder of the
+ * nonce-nc map.
+ */
+struct MHD_NonceNc 
+{
+  
+  /**
+   * Nonce counter, a value that increases for each subsequent
+   * request for the same nonce.
+   */
+  unsigned long int nc;
+
+  /**
+   * Nonce value: 
+   */
+  char nonce[MAX_NONCE_LENGTH];
+
+};
+
+#if HAVE_MESSAGES
+/**
+ * fprintf-like helper function for logging debug
+ * messages.
+ */
+void 
+MHD_DLOG (const struct MHD_Daemon *daemon, 
+         const char *format, ...);
+
+#endif
+
+/**
+ * Process escape sequences ('+'=space, %HH) Updates val in place; the
+ * result should be UTF-8 encoded and cannot be larger than the input.
+ * The result must also still be 0-terminated.
+ *
+ * @param cls closure (use NULL)
+ * @param connection handle to connection, not used
+ * @param val value to unescape (modified in the process)
+ * @return length of the resulting val (strlen(val) maybe
+ *  shorter afterwards due to elimination of escape sequences)
+ */
+size_t 
+MHD_http_unescape (void *cls,
+                  struct MHD_Connection *connection,
+                  char *val);
+
+
+/**
+ * Header or cookie in HTTP request or response.
+ */
+struct MHD_HTTP_Header
+{
+  /**
+   * Headers are kept in a linked list.
+   */
+  struct MHD_HTTP_Header *next;
+
+  /**
+   * The name of the header (key), without
+   * the colon.
+   */
+  char *header;
+
+  /**
+   * The value of the header.
+   */
+  char *value;
+
+  /**
+   * Type of the header (where in the HTTP
+   * protocol is this header from).
+   */
+  enum MHD_ValueKind kind;
+
+};
+
+
+/**
+ * Representation of a response.
+ */
+struct MHD_Response
+{
+
+  /**
+   * Headers to send for the response.  Initially
+   * the linked list is created in inverse order;
+   * the order should be inverted before sending!
+   */
+  struct MHD_HTTP_Header *first_header;
+
+  /**
+   * Buffer pointing to data that we are supposed
+   * to send as a response.
+   */
+  char *data;
+
+  /**
+   * Closure to give to the content reader
+   * free callback.
+   */
+  void *crc_cls;
+
+  /**
+   * How do we get more data?  NULL if we are
+   * given all of the data up front.
+   */
+  MHD_ContentReaderCallback crc;
+
+  /**
+   * NULL if data must not be freed, otherwise
+   * either user-specified callback or "&free".
+   */
+  MHD_ContentReaderFreeCallback crfc;
+
+  /**
+   * Mutex to synchronize access to data/size and
+   * reference counts.
+   */
+  pthread_mutex_t mutex;
+
+  /**
+   * Set to MHD_SIZE_UNKNOWN if size is not known.
+   */
+  uint64_t total_size;
+
+  /**
+   * At what offset in the stream is the
+   * beginning of data located?
+   */
+  uint64_t data_start;
+
+  /**
+   * Offset to start reading from when using 'fd'.
+   */
+  off_t fd_off;
+
+  /**
+   * Size of data.
+   */
+  size_t data_size;
+
+  /**
+   * Size of the data buffer.
+   */
+  size_t data_buffer_size;
+
+  /**
+   * Reference count for this response.  Free
+   * once the counter hits zero.
+   */
+  unsigned int reference_count;
+
+  /**
+   * File-descriptor if this response is FD-backed.
+   */
+  int fd;
+
+};
+
+
+/**
+ * States in a state machine for a connection.
+ *
+ * Transitions are any-state to CLOSED, any state to state+1,
+ * FOOTERS_SENT to INIT.  CLOSED is the terminal state and
+ * INIT the initial state.
+ *
+ * Note that transitions for *reading* happen only after
+ * the input has been processed; transitions for
+ * *writing* happen after the respective data has been
+ * put into the write buffer (the write does not have
+ * to be completed yet).  A transition to CLOSED or INIT
+ * requires the write to be complete.
+ */
+enum MHD_CONNECTION_STATE
+{
+  /**
+   * Connection just started (no headers received).
+   * Waiting for the line with the request type, URL and version.
+   */
+  MHD_CONNECTION_INIT = 0,
+
+  /**
+   * 1: We got the URL (and request type and version).  Wait for a header line.
+   */
+  MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1,
+
+  /**
+   * 2: We got part of a multi-line request header.  Wait for the rest.
+   */
+  MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1,
+
+  /**
+   * 3: We got the request headers.  Process them.
+   */
+  MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1,
+
+  /**
+   * 4: We have processed the request headers.  Send 100 continue.
+   */
+  MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1,
+
+  /**
+   * 5: We have processed the headers and need to send 100 CONTINUE.
+   */
+  MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1,
+
+  /**
+   * 6: We have sent 100 CONTINUE (or do not need to).  Read the message body.
+   */
+  MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1,
+
+  /**
+   * 7: We got the request body.  Wait for a line of the footer.
+   */
+  MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1,
+
+  /**
+   * 8: We got part of a line of the footer.  Wait for the
+   * rest.
+   */
+  MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1,
+
+  /**
+   * 9: We received the entire footer.  Wait for a response to be queued
+   * and prepare the response headers.
+   */
+  MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1,
+
+  /**
+   * 10: We have prepared the response headers in the writ buffer.
+   * Send the response headers.
+   */
+  MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1,
+
+  /**
+   * 11: We have sent the response headers.  Get ready to send the body.
+   */
+  MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1,
+
+  /**
+   * 12: We are ready to send a part of a non-chunked body.  Send it.
+   */
+  MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1,
+
+  /**
+   * 13: We are waiting for the client to provide more
+   * data of a non-chunked body.
+   */
+  MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1,
+
+  /**
+   * 14: We are ready to send a chunk.
+   */
+  MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1,
+
+  /**
+   * 15: We are waiting for the client to provide a chunk of the body.
+   */
+  MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1,
+
+  /**
+   * 16: We have sent the response body. Prepare the footers.
+   */
+  MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1,
+
+  /**
+   * 17: We have prepared the response footer.  Send it.
+   */
+  MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1,
+
+  /**
+   * 18: We have sent the response footer.  Shutdown or restart.
+   */
+  MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1,
+
+  /**
+   * 19: This connection is to be closed.
+   */
+  MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1,
+
+  /**
+   * 20: This connection is finished (only to be freed)
+   */
+  MHD_CONNECTION_IN_CLEANUP = MHD_CONNECTION_CLOSED + 1,
+
+  /*
+   *  SSL/TLS connection states
+   */
+
+  /**
+   * The initial connection state for all secure connectoins
+   * Handshake messages will be processed in this state & while
+   * in the 'MHD_TLS_HELLO_REQUEST' state
+   */
+  MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_CLOSED + 1
+
+};
+
+/**
+ * Should all state transitions be printed to stderr?
+ */
+#define DEBUG_STATES MHD_NO
+
+
+#if HAVE_MESSAGES
+#if DEBUG_STATES
+const char *
+MHD_state_to_string (enum MHD_CONNECTION_STATE state);
+#endif
+#endif
+
+/**
+ * Function to receive plaintext data.
+ *
+ * @param conn the connection struct
+ * @param write_to where to write received data
+ * @param max_bytes maximum number of bytes to receive
+ * @return number of bytes written to write_to
+ */
+typedef ssize_t (*ReceiveCallback) (struct MHD_Connection * conn,
+                                    void *write_to, size_t max_bytes);
+
+
+/**
+ * Function to transmit plaintext data.
+ *
+ * @param conn the connection struct
+ * @param read_from where to read data to transmit
+ * @param max_bytes maximum number of bytes to transmit
+ * @return number of bytes transmitted
+ */
+typedef ssize_t (*TransmitCallback) (struct MHD_Connection * conn,
+                                     const void *write_to, size_t max_bytes);
+
+
+/**
+ * State kept for each HTTP request.
+ */
+struct MHD_Connection
+{
+
+  /**
+   * This is a doubly-linked list.
+   */
+  struct MHD_Connection *next;
+
+  /**
+   * This is a doubly-linked list.
+   */
+  struct MHD_Connection *prev;
+
+  /**
+   * Reference to the MHD_Daemon struct.
+   */
+  struct MHD_Daemon *daemon;
+
+  /**
+   * Linked list of parsed headers.
+   */
+  struct MHD_HTTP_Header *headers_received;
+
+  /**
+   * Tail of linked list of parsed headers.
+   */
+  struct MHD_HTTP_Header *headers_received_tail;
+
+  /**
+   * Response to transmit (initially NULL).
+   */
+  struct MHD_Response *response;
+
+  /**
+   * The memory pool is created whenever we first read
+   * from the TCP stream and destroyed at the end of
+   * each request (and re-created for the next request).
+   * In the meantime, this pointer is NULL.  The
+   * pool is used for all connection-related data
+   * except for the response (which maybe shared between
+   * connections) and the IP address (which persists
+   * across individual requests).
+   */
+  struct MemoryPool *pool;
+
+  /**
+   * We allow the main application to associate some
+   * pointer with the connection.  Here is where we
+   * store it.  (MHD does not know or care what it
+   * is).
+   */
+  void *client_context;
+
+  /**
+   * Request method.  Should be GET/POST/etc.  Allocated
+   * in pool.
+   */
+  char *method;
+
+  /**
+   * Requested URL (everything after "GET" only).  Allocated
+   * in pool.
+   */
+  char *url;
+
+  /**
+   * HTTP version string (i.e. http/1.1).  Allocated
+   * in pool.
+   */
+  char *version;
+
+  /**
+   * Buffer for reading requests.   Allocated
+   * in pool.  Actually one byte larger than
+   * read_buffer_size (if non-NULL) to allow for
+   * 0-termination.
+   */
+  char *read_buffer;
+
+  /**
+   * Buffer for writing response (headers only).  Allocated
+   * in pool.
+   */
+  char *write_buffer;
+
+  /**
+   * Last incomplete header line during parsing of headers.
+   * Allocated in pool.  Only valid if state is
+   * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
+   */
+  char *last;
+
+  /**
+   * Position after the colon on the last incomplete header
+   * line during parsing of headers.
+   * Allocated in pool.  Only valid if state is
+   * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED.
+   */
+  char *colon;
+
+  /**
+   * Foreign address (of length addr_len).  MALLOCED (not
+   * in pool!).
+   */
+  struct sockaddr *addr;
+
+  /**
+   * Thread for this connection (if we are using
+   * one thread per connection).
+   */
+  pthread_t pid;
+
+  /**
+   * 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;
+
+  /**
+   * Size of write_buffer (in bytes).
+   */
+  size_t write_buffer_size;
+
+  /**
+   * Offset where we are with sending from write_buffer.
+   */
+  size_t write_buffer_send_offset;
+
+  /**
+   * Last valid location in write_buffer (where do we
+   * append and up to where is it safe to send?)
+   */
+  size_t write_buffer_append_offset;
+
+  /**
+   * How many more bytes of the body do we expect
+   * to read? "-1" for unknown.
+   */
+  uint64_t remaining_upload_size;
+
+  /**
+   * Current write position in the actual response
+   * (excluding headers, content only; should be 0
+   * while sending headers).
+   */
+  uint64_t response_write_position;
+
+  /**
+   * Position in the 100 CONTINUE message that
+   * we need to send when receiving http 1.1 requests.
+   */
+  size_t continue_message_write_offset;
+
+  /**
+   * Length of the foreign address.
+   */
+  socklen_t addr_len;
+
+  /**
+   * Last time this connection had any activity
+   * (reading or writing).
+   */
+  time_t last_activity;
+
+  /**
+   * After how many seconds of inactivity should
+   * this connection time out?  Zero for no timeout.
+   */
+  unsigned int connection_timeout;
+
+  /**
+   * Did we ever call the "default_handler" on this connection?
+   * (this flag will determine if we call the 'notify_completed'
+   * handler when the connection closes down).
+   */
+  int client_aware;
+
+  /**
+   * Socket for this connection.  Set to -1 if
+   * this connection has died (daemon should clean
+   * up in that case).
+   */
+  int socket_fd;
+
+  /**
+   * 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).
+   */
+  int read_closed;
+
+  /**
+   * Set to MHD_YES if the thread has been joined.
+   */
+  int thread_joined;
+
+  /**
+   * State in the FSM for this connection.
+   */
+  enum MHD_CONNECTION_STATE state;
+
+  /**
+   * HTTP response code.  Only valid if response object
+   * is already set.
+   */
+  unsigned int responseCode;
+
+  /**
+   * Set to MHD_YES if the response's content reader
+   * callback failed to provide data the last time
+   * we tried to read from it.  In that case, the
+   * write socket should be marked as unready until
+   * the CRC call succeeds.
+   */
+  int response_unready;
+
+  /**
+   * Are we receiving with chunked encoding?  This will be set to
+   * MHD_YES after we parse the headers and are processing the body
+   * with chunks.  After we are done with the body and we are
+   * processing the footers; once the footers are also done, this will
+   * be set to MHD_NO again (before the final call to the handler).
+   */
+  int have_chunked_upload;
+
+  /**
+   * If we are receiving with chunked encoding, where are we right
+   * now?  Set to 0 if we are waiting to receive the chunk size;
+   * otherwise, this is the size of the current chunk.  A value of
+   * zero is also used when we're at the end of the chunks.
+   */
+  unsigned int current_chunk_size;
+
+  /**
+   * If we are receiving with chunked encoding, where are we currently
+   * with respect to the current chunk (at what offset / position)?
+   */
+  unsigned int current_chunk_offset;
+
+  /**
+   * Handler used for processing read connection operations
+   */
+  int (*read_handler) (struct MHD_Connection * connection);
+
+  /**
+   * Handler used for processing write connection operations
+   */
+  int (*write_handler) (struct MHD_Connection * connection);
+
+  /**
+   * Handler used for processing idle connection operations
+   */
+  int (*idle_handler) (struct MHD_Connection * connection);
+
+  /**
+   * Function used for reading HTTP request stream.
+   */
+  ReceiveCallback recv_cls;
+
+  /**
+   * Function used for writing HTTP response stream.
+   */
+  TransmitCallback send_cls;
+
+#if HTTPS_SUPPORT
+  /**
+   * State required for HTTPS/SSL/TLS support.
+   */
+  gnutls_session_t tls_session;
+
+  /**
+   * Memory location to return for protocol session info.
+   */
+  int protocol;
+
+  /**
+   * Memory location to return for protocol session info.
+   */
+  int cipher;
+
+  /**
+   * Could it be that we are ready to read due to TLS buffers
+   * even though the socket is not?
+   */
+  int tls_read_ready;
+
+#endif
+};
+
+/**
+ * Signature of function called to log URI accesses.
+ *
+ * @param cls closure
+ * @param uri uri being accessed
+ * @return new closure
+ */
+typedef void * (*LogCallback)(void * cls, const char * uri);
+
+/**
+ * Signature of function called to unescape URIs.  See also
+ * MHD_http_unescape.
+ *
+ * @param cls closure
+ * @param conn connection handle
+ * @param uri 0-terminated string to unescape (should be updated)
+ * @return length of the resulting string
+ */
+typedef size_t (*UnescapeCallback)(void *cls,
+                                  struct MHD_Connection *conn,
+                                  char *uri);
+
+
+/**
+ * State kept for each MHD daemon.
+ */
+struct MHD_Daemon
+{
+
+  /**
+   * Callback function for all requests.
+   */
+  MHD_AccessHandlerCallback default_handler;
+
+  /**
+   * Closure argument to default_handler.
+   */
+  void *default_handler_cls;
+
+  /**
+   * Tail of doubly-linked list of our current, active connections.
+   */
+  struct MHD_Connection *connections_head;
+
+  /**
+   * Tail of doubly-linked list of our current, active connections.
+   */
+  struct MHD_Connection *connections_tail;
+
+  /**
+   * Tail of doubly-linked list of connections to clean up.
+   */
+  struct MHD_Connection *cleanup_head;
+
+  /**
+   * Tail of doubly-linked list of connections to clean up.
+   */
+  struct MHD_Connection *cleanup_tail;
+
+  /**
+   * Function to call to check if we should
+   * accept or reject an incoming request.
+   * May be NULL.
+   */
+  MHD_AcceptPolicyCallback apc;
+
+  /**
+   * Closure argument to apc.
+   */
+  void *apc_cls;
+
+  /**
+   * Function to call when we are done processing
+   * a particular request.  May be NULL.
+   */
+  MHD_RequestCompletedCallback notify_completed;
+
+  /**
+   * Closure argument to notify_completed.
+   */
+  void *notify_completed_cls;
+
+  /**
+   * Function to call with the full URI at the
+   * beginning of request processing.  May be NULL.
+   * <p>
+   * Returns the initial pointer to internal state
+   * kept by the client for the request.
+   */
+  LogCallback uri_log_callback;
+
+  /**
+   * Closure argument to uri_log_callback.
+   */
+  void *uri_log_callback_cls;
+
+  /**
+   * Function to call when we unescape escape sequences.
+   */
+  UnescapeCallback unescape_callback;
+
+  /**
+   * Closure for unescape callback.
+   */
+  void *unescape_callback_cls;
+
+#if HAVE_MESSAGES
+  /**
+   * Function for logging error messages (if we
+   * support error reporting).
+   */
+  void (*custom_error_log) (void *cls, const char *fmt, va_list va);
+
+  /**
+   * Closure argument to custom_error_log.
+   */
+  void *custom_error_log_cls;
+#endif
+
+  /**
+   * Pointer to master daemon (NULL if this is the master)
+   */
+  struct MHD_Daemon *master;
+
+  /**
+   * Worker daemons (one per thread)
+   */
+  struct MHD_Daemon *worker_pool;
+
+  /**
+   * Table storing number of connections per IP
+   */
+  void *per_ip_connection_count;
+
+  /**
+   * Size of the per-connection memory pools.
+   */
+  size_t pool_size;
+
+  /**
+   * Size of threads created by MHD.
+   */
+  size_t thread_stack_size;
+
+  /**
+   * Number of worker daemons
+   */
+  unsigned int worker_pool_size;
+
+  /**
+   * PID of the select thread (if we have internal select)
+   */
+  pthread_t pid;
+
+  /**
+   * Mutex for per-IP connection counts.
+   */
+  pthread_mutex_t per_ip_connection_mutex;
+
+  /**
+   * Mutex for (modifying) access to the "cleanup" connection DLL.
+   */
+  pthread_mutex_t cleanup_connection_mutex;
+
+  /**
+   * Listen socket.
+   */
+  int socket_fd;
+
+  /**
+   * Pipe we use to signal shutdown, unless
+   * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen
+   * socket (which we can then 'shutdown' to stop listening).
+   */
+  int wpipe[2];
+
+  /**
+   * Are we shutting down?
+   */
+  int shutdown;
+
+  /**
+   * Limit on the number of parallel connections.
+   */
+  unsigned int max_connections;
+
+  /**
+   * After how many seconds of inactivity should
+   * connections time out?  Zero for no timeout.
+   */
+  unsigned int connection_timeout;
+
+  /**
+   * Maximum number of connections per IP, or 0 for
+   * unlimited.
+   */
+  unsigned int per_ip_connection_limit;
+
+  /**
+   * Daemon's options.
+   */
+  enum MHD_OPTION options;
+
+  /**
+   * Listen port.
+   */
+  uint16_t port;
+
+#if HTTPS_SUPPORT
+  /**
+   * Desired cipher algorithms.
+   */
+  gnutls_priority_t priority_cache;
+
+  /**
+   * What kind of credentials are we offering
+   * for SSL/TLS?
+   */
+  gnutls_credentials_type_t cred_type;
+
+  /**
+   * Server x509 credentials
+   */
+  gnutls_certificate_credentials_t x509_cred;
+
+  /**
+   * Diffie-Hellman parameters
+   */
+  gnutls_dh_params_t dh_params;
+
+  /**
+   * Pointer to our SSL/TLS key (in ASCII) in memory.
+   */
+  const char *https_mem_key;
+
+  /**
+   * Pointer to our SSL/TLS certificate (in ASCII) in memory.
+   */
+  const char *https_mem_cert;
+
+  /**
+   * Pointer to our SSL/TLS certificate authority (in ASCII) in memory.
+   */
+  const char *https_mem_trust;
+
+#endif
+
+#ifdef DAUTH_SUPPORT
+
+  /**
+   * Character array of random values.
+   */
+  const char *digest_auth_random;
+
+  /**
+   * An array that contains the map nonce-nc.
+   */
+  struct MHD_NonceNc *nnc;
+
+  /**
+   * A rw-lock for synchronizing access to `nnc'.
+   */
+  pthread_mutex_t nnc_lock;
+
+  /**
+   * Size of `digest_auth_random.
+   */
+  unsigned int digest_auth_rand_size;
+
+  /**
+   * Size of the nonce-nc array.
+   */
+  unsigned int nonce_nc_size;
+
+#endif
+
+};
+
+
+#if EXTRA_CHECKS
+#define EXTRA_CHECK(a) if (!(a)) abort();
+#else
+#define EXTRA_CHECK(a)
+#endif
+
+
+/**
+ * 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
+ * @param tail pointer to the tail of the DLL
+ * @param element element to insert
+ */
+#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
+ * @param tail pointer to the tail of the DLL
+ * @param element element to remove
+ */
+#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)
+
+
+/**
+ * Equivalent to time(NULL) but tries to use some sort of monotonic
+ * clock that isn't affected by someone setting the system real time
+ * clock.
+ */
+time_t MHD_monotonic_time(void);
+
+#endif

Deleted: libmicrohttpd/src/microhttpd/memorypool.c
===================================================================
--- libmicrohttpd/src/daemon/memorypool.c       2013-05-05 12:01:06 UTC (rev 
27023)
+++ libmicrohttpd/src/microhttpd/memorypool.c   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,250 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-*/
-
-/**
- * @file memorypool.c
- * @brief memory pool
- * @author Christian Grothoff
- */
-#include "memorypool.h"
-
-/* define MAP_ANONYMOUS for Mac OS X */
-#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void*)-1)
-#endif
-
-/**
- * Align to 2x word size (as GNU libc does).
- */
-#define ALIGN_SIZE (2 * sizeof(void*))
-
-/**
- * Round up 'n' to a multiple of ALIGN_SIZE.
- */
-#define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1)))
-
-
-/**
- * Handle for a memory pool.  Pools are not reentrant and must not be
- * used by multiple threads.
- */
-struct MemoryPool
-{
-
-  /**
-   * Pointer to the pool's memory
-   */
-  char *memory;
-
-  /**
-   * Size of the pool.
-   */
-  size_t size;
-
-  /**
-   * Offset of the first unallocated byte.
-   */
-  size_t pos;
-
-  /**
-   * Offset of the last unallocated byte.
-   */
-  size_t end;
-
-  /**
-   * MHD_NO if pool was malloc'ed, MHD_YES if mmapped.
-   */
-  int is_mmap;
-};
-
-
-/**
- * Create a memory pool.
- *
- * @param max maximum size of the pool
- */
-struct MemoryPool *
-MHD_pool_create (size_t max)
-{
-  struct MemoryPool *pool;
-
-  pool = malloc (sizeof (struct MemoryPool));
-  if (pool == NULL)
-    return NULL;
-#ifdef MAP_ANONYMOUS
-  pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE,
-                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#else
-  pool->memory = MAP_FAILED;
-#endif
-  if ((pool->memory == MAP_FAILED) || (pool->memory == NULL))
-    {
-      pool->memory = malloc (max);
-      if (pool->memory == NULL)
-        {
-          free (pool);
-          return NULL;
-        }
-      pool->is_mmap = MHD_NO;
-    }
-  else
-    {
-      pool->is_mmap = MHD_YES;
-    }
-  pool->pos = 0;
-  pool->end = max;
-  pool->size = max;
-  return pool;
-}
-
-
-/**
- * Destroy a memory pool.
- */
-void
-MHD_pool_destroy (struct MemoryPool *pool)
-{
-  if (pool == NULL)
-    return;
-  if (pool->is_mmap == MHD_NO)
-    free (pool->memory);
-  else
-    MUNMAP (pool->memory, pool->size);
-  free (pool);
-}
-
-
-/**
- * Allocate size bytes from the pool.
- * @return NULL if the pool cannot support size more
- *         bytes
- */
-void *
-MHD_pool_allocate (struct MemoryPool *pool, 
-                  size_t size, int from_end)
-{
-  void *ret;
-
-  size = ROUND_TO_ALIGN (size);
-  if ((pool->pos + size > pool->end) || (pool->pos + size < pool->pos))
-    return NULL;
-  if (from_end == MHD_YES)
-    {
-      ret = &pool->memory[pool->end - size];
-      pool->end -= size;
-    }
-  else
-    {
-      ret = &pool->memory[pool->pos];
-      pool->pos += size;
-    }
-  return ret;
-}
-
-
-/**
- * Reallocate a block of memory obtained from the pool.
- * This is particularly efficient when growing or
- * shrinking the block that was last (re)allocated.
- * If the given block is not the most recenlty
- * (re)allocated block, the memory of the previous
- * allocation may be leaked until the pool is
- * destroyed (and copying the data maybe required).
- *
- * @param old the existing block
- * @param old_size the size of the existing block
- * @param new_size the new size of the block
- * @return new address of the block, or
- *         NULL if the pool cannot support new_size
- *         bytes (old continues to be valid for old_size)
- */
-void *
-MHD_pool_reallocate (struct MemoryPool *pool,
-                     void *old, 
-                    size_t old_size, 
-                    size_t new_size)
-{
-  void *ret;
-
-  new_size = ROUND_TO_ALIGN (new_size);
-  if ((pool->end < old_size) || (pool->end < new_size))
-    return NULL;                /* unsatisfiable or bogus request */
-
-  if ((pool->pos >= old_size) && (&pool->memory[pool->pos - old_size] == old))
-    {
-      /* was the previous allocation - optimize! */
-      if (pool->pos + new_size - old_size <= pool->end)
-        {
-          /* fits */
-          pool->pos += new_size - old_size;
-          if (new_size < old_size)      /* shrinking - zero again! */
-            memset (&pool->memory[pool->pos], 0, old_size - new_size);
-          return old;
-        }
-      /* does not fit */
-      return NULL;
-    }
-  if (new_size <= old_size)
-    return old;                 /* cannot shrink, no need to move */
-  if ((pool->pos + new_size >= pool->pos) &&
-      (pool->pos + new_size <= pool->end))
-    {
-      /* fits */
-      ret = &pool->memory[pool->pos];
-      memcpy (ret, old, old_size);
-      pool->pos += new_size;
-      return ret;
-    }
-  /* does not fit */
-  return NULL;
-}
-
-
-/**
- * Clear all entries from the memory pool except
- * for "keep" of the given "size".
- *
- * @param keep pointer to the entry to keep (maybe NULL)
- * @param size how many bytes need to be kept at this address
- * @return addr new address of "keep" (if it had to change)
- */
-void *
-MHD_pool_reset (struct MemoryPool *pool, 
-               void *keep, 
-               size_t size)
-{
-  size = ROUND_TO_ALIGN (size);
-  if (keep != NULL)
-    {
-      if (keep != pool->memory)
-        {
-          memmove (pool->memory, keep, size);
-          keep = pool->memory;
-        }
-      pool->pos = size;
-    }
-  pool->end = pool->size;
-  return keep;
-}
-
-
-/* end of memorypool.c */

Copied: libmicrohttpd/src/microhttpd/memorypool.c (from rev 27024, 
libmicrohttpd/src/daemon/memorypool.c)
===================================================================
--- libmicrohttpd/src/microhttpd/memorypool.c                           (rev 0)
+++ libmicrohttpd/src/microhttpd/memorypool.c   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,261 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+*/
+
+/**
+ * @file memorypool.c
+ * @brief memory pool
+ * @author Christian Grothoff
+ */
+#include "memorypool.h"
+
+/* define MAP_ANONYMOUS for Mac OS X */
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void*)-1)
+#endif
+
+/**
+ * Align to 2x word size (as GNU libc does).
+ */
+#define ALIGN_SIZE (2 * sizeof(void*))
+
+/**
+ * Round up 'n' to a multiple of ALIGN_SIZE.
+ */
+#define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1)))
+
+
+/**
+ * Handle for a memory pool.  Pools are not reentrant and must not be
+ * used by multiple threads.
+ */
+struct MemoryPool
+{
+
+  /**
+   * Pointer to the pool's memory
+   */
+  char *memory;
+
+  /**
+   * Size of the pool.
+   */
+  size_t size;
+
+  /**
+   * Offset of the first unallocated byte.
+   */
+  size_t pos;
+
+  /**
+   * Offset of the last unallocated byte.
+   */
+  size_t end;
+
+  /**
+   * MHD_NO if pool was malloc'ed, MHD_YES if mmapped.
+   */
+  int is_mmap;
+};
+
+
+/**
+ * Create a memory pool.
+ *
+ * @param max maximum size of the pool
+ * @return NULL on error
+ */
+struct MemoryPool *
+MHD_pool_create (size_t max)
+{
+  struct MemoryPool *pool;
+
+  pool = malloc (sizeof (struct MemoryPool));
+  if (pool == NULL)
+    return NULL;
+#ifdef MAP_ANONYMOUS
+  pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+#else
+  pool->memory = MAP_FAILED;
+#endif
+  if ((pool->memory == MAP_FAILED) || (pool->memory == NULL))
+    {
+      pool->memory = malloc (max);
+      if (pool->memory == NULL)
+        {
+          free (pool);
+          return NULL;
+        }
+      pool->is_mmap = MHD_NO;
+    }
+  else
+    {
+      pool->is_mmap = MHD_YES;
+    }
+  pool->pos = 0;
+  pool->end = max;
+  pool->size = max;
+  return pool;
+}
+
+
+/**
+ * Destroy a memory pool.
+ *
+ * @param pool memory pool to destroy
+ */
+void
+MHD_pool_destroy (struct MemoryPool *pool)
+{
+  if (pool == NULL)
+    return;
+  if (pool->is_mmap == MHD_NO)
+    free (pool->memory);
+  else
+    MUNMAP (pool->memory, pool->size);
+  free (pool);
+}
+
+
+/**
+ * Allocate size bytes from the pool.
+ *
+ * @param pool memory pool to use for the operation
+ * @param size number of bytes to allocate
+ * @param from_end allocate from end of pool (set to MHD_YES);
+ *        use this for small, persistent allocations that
+ *        will never be reallocated
+ * @return NULL if the pool cannot support size more
+ *         bytes
+ */
+void *
+MHD_pool_allocate (struct MemoryPool *pool, 
+                  size_t size, int from_end)
+{
+  void *ret;
+
+  size = ROUND_TO_ALIGN (size);
+  if ((pool->pos + size > pool->end) || (pool->pos + size < pool->pos))
+    return NULL;
+  if (from_end == MHD_YES)
+    {
+      ret = &pool->memory[pool->end - size];
+      pool->end -= size;
+    }
+  else
+    {
+      ret = &pool->memory[pool->pos];
+      pool->pos += size;
+    }
+  return ret;
+}
+
+
+/**
+ * Reallocate a block of memory obtained from the pool.
+ * This is particularly efficient when growing or
+ * shrinking the block that was last (re)allocated.
+ * If the given block is not the most recenlty
+ * (re)allocated block, the memory of the previous
+ * allocation may be leaked until the pool is
+ * destroyed (and copying the data maybe required).
+ *
+ * @param pool memory pool to use for the operation
+ * @param old the existing block
+ * @param old_size the size of the existing block
+ * @param new_size the new size of the block
+ * @return new address of the block, or
+ *         NULL if the pool cannot support new_size
+ *         bytes (old continues to be valid for old_size)
+ */
+void *
+MHD_pool_reallocate (struct MemoryPool *pool,
+                     void *old, 
+                    size_t old_size, 
+                    size_t new_size)
+{
+  void *ret;
+
+  new_size = ROUND_TO_ALIGN (new_size);
+  if ((pool->end < old_size) || (pool->end < new_size))
+    return NULL;                /* unsatisfiable or bogus request */
+
+  if ((pool->pos >= old_size) && (&pool->memory[pool->pos - old_size] == old))
+    {
+      /* was the previous allocation - optimize! */
+      if (pool->pos + new_size - old_size <= pool->end)
+        {
+          /* fits */
+          pool->pos += new_size - old_size;
+          if (new_size < old_size)      /* shrinking - zero again! */
+            memset (&pool->memory[pool->pos], 0, old_size - new_size);
+          return old;
+        }
+      /* does not fit */
+      return NULL;
+    }
+  if (new_size <= old_size)
+    return old;                 /* cannot shrink, no need to move */
+  if ((pool->pos + new_size >= pool->pos) &&
+      (pool->pos + new_size <= pool->end))
+    {
+      /* fits */
+      ret = &pool->memory[pool->pos];
+      memcpy (ret, old, old_size);
+      pool->pos += new_size;
+      return ret;
+    }
+  /* does not fit */
+  return NULL;
+}
+
+
+/**
+ * Clear all entries from the memory pool except
+ * for "keep" of the given "size".
+ *
+ * @param pool memory pool to use for the operation
+ * @param keep pointer to the entry to keep (maybe NULL)
+ * @param size how many bytes need to be kept at this address
+ * @return addr new address of "keep" (if it had to change)
+ */
+void *
+MHD_pool_reset (struct MemoryPool *pool, 
+               void *keep, 
+               size_t size)
+{
+  size = ROUND_TO_ALIGN (size);
+  if (keep != NULL)
+    {
+      if (keep != pool->memory)
+        {
+          memmove (pool->memory, keep, size);
+          keep = pool->memory;
+        }
+      pool->pos = size;
+    }
+  pool->end = pool->size;
+  return keep;
+}
+
+
+/* end of memorypool.c */

Deleted: libmicrohttpd/src/microhttpd/memorypool.h
===================================================================
--- libmicrohttpd/src/daemon/memorypool.h       2013-05-05 12:01:06 UTC (rev 
27023)
+++ libmicrohttpd/src/microhttpd/memorypool.h   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,107 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2007, 2009 Daniel Pittman and Christian Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-*/
-
-/**
- * @file memorypool.h
- * @brief memory pool; mostly used for efficient (de)allocation
- *        for each connection and bounding memory use for each
- *        request
- * @author Christian Grothoff
- */
-
-#ifndef MEMORYPOOL_H
-#define MEMORYPOOL_H
-
-#include "internal.h"
-
-/**
- * Opaque handle for a memory pool.
- * Pools are not reentrant and must not be used
- * by multiple threads.
- */
-struct MemoryPool;
-
-
-/**
- * Create a memory pool.
- *
- * @param max maximum size of the pool
- */
-struct MemoryPool *
-MHD_pool_create (size_t max);
-
-
-/**
- * Destroy a memory pool.
- */
-void 
-MHD_pool_destroy (struct MemoryPool *pool);
-
-
-/**
- * Allocate size bytes from the pool.
- *
- * @param from_end allocate from end of pool (set to MHD_YES);
- *        use this for small, persistent allocations that
- *        will never be reallocated
- * @return NULL if the pool cannot support size more
- *         bytes
- */
-void *
-MHD_pool_allocate (struct MemoryPool *pool,
-                  size_t size, int from_end);
-
-
-/**
- * Reallocate a block of memory obtained from the pool.
- * This is particularly efficient when growing or
- * shrinking the block that was last (re)allocated.
- * If the given block is not the most recenlty
- * (re)allocated block, the memory of the previous
- * allocation may be leaked until the pool is
- * destroyed (and copying the data maybe required).
- *
- * @param old the existing block
- * @param old_size the size of the existing block
- * @param new_size the new size of the block
- * @return new address of the block, or
- *         NULL if the pool cannot support new_size
- *         bytes (old continues to be valid for old_size)
- */
-void *
-MHD_pool_reallocate (struct MemoryPool *pool,
-                    void *old,
-                    size_t old_size, 
-                    size_t new_size);
-
-
-/**
- * Clear all entries from the memory pool except
- * for "keep" of the given "size".
- *
- * @param keep pointer to the entry to keep (maybe NULL)
- * @param size how many bytes need to be kept at this address
- * @return addr new address of "keep" (if it had to change)
- */
-void *
-MHD_pool_reset (struct MemoryPool *pool,
-               void *keep, 
-               size_t size);
-
-#endif

Copied: libmicrohttpd/src/microhttpd/memorypool.h (from rev 27024, 
libmicrohttpd/src/daemon/memorypool.h)
===================================================================
--- libmicrohttpd/src/microhttpd/memorypool.h                           (rev 0)
+++ libmicrohttpd/src/microhttpd/memorypool.h   2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,114 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007, 2009 Daniel Pittman and Christian Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+*/
+
+/**
+ * @file memorypool.h
+ * @brief memory pool; mostly used for efficient (de)allocation
+ *        for each connection and bounding memory use for each
+ *        request
+ * @author Christian Grothoff
+ */
+
+#ifndef MEMORYPOOL_H
+#define MEMORYPOOL_H
+
+#include "internal.h"
+
+/**
+ * Opaque handle for a memory pool.
+ * Pools are not reentrant and must not be used
+ * by multiple threads.
+ */
+struct MemoryPool;
+
+
+/**
+ * Create a memory pool.
+ *
+ * @param max maximum size of the pool
+ * @return NULL on error
+ */
+struct MemoryPool *
+MHD_pool_create (size_t max);
+
+
+/**
+ * Destroy a memory pool.
+ *
+ * @param pool memory pool to destroy
+ */
+void 
+MHD_pool_destroy (struct MemoryPool *pool);
+
+
+/**
+ * Allocate size bytes from the pool.
+ *
+ * @param pool memory pool to use for the operation
+ * @param size number of bytes to allocate
+ * @param from_end allocate from end of pool (set to MHD_YES);
+ *        use this for small, persistent allocations that
+ *        will never be reallocated
+ * @return NULL if the pool cannot support size more
+ *         bytes
+ */
+void *
+MHD_pool_allocate (struct MemoryPool *pool,
+                  size_t size, int from_end);
+
+
+/**
+ * Reallocate a block of memory obtained from the pool.
+ * This is particularly efficient when growing or
+ * shrinking the block that was last (re)allocated.
+ * If the given block is not the most recenlty
+ * (re)allocated block, the memory of the previous
+ * allocation may be leaked until the pool is
+ * destroyed (and copying the data maybe required).
+ *
+ * @param pool memory pool to use for the operation
+ * @param old the existing block
+ * @param old_size the size of the existing block
+ * @param new_size the new size of the block
+ * @return new address of the block, or
+ *         NULL if the pool cannot support new_size
+ *         bytes (old continues to be valid for old_size)
+ */
+void *
+MHD_pool_reallocate (struct MemoryPool *pool,
+                    void *old,
+                    size_t old_size, 
+                    size_t new_size);
+
+
+/**
+ * Clear all entries from the memory pool except
+ * for "keep" of the given "size".
+ *
+ * @param pool memory pool to use for the operation
+ * @param keep pointer to the entry to keep (maybe NULL)
+ * @param size how many bytes need to be kept at this address
+ * @return addr new address of "keep" (if it had to change)
+ */
+void *
+MHD_pool_reset (struct MemoryPool *pool,
+               void *keep, 
+               size_t size);
+
+#endif

Deleted: libmicrohttpd/src/microhttpd/postprocessor.c
===================================================================
--- libmicrohttpd/src/daemon/postprocessor.c    2013-05-05 12:01:06 UTC (rev 
27023)
+++ libmicrohttpd/src/microhttpd/postprocessor.c        2013-05-05 18:07:33 UTC 
(rev 27025)
@@ -1,1143 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2007, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-*/
-
-/**
- * @file postprocessor.c
- * @brief  Methods for parsing POST data
- * @author Christian Grothoff
- */
-
-#include "internal.h"
-
-/**
- * Size of on-stack buffer that we use for un-escaping of the value.
- * We use a pretty small value to be nice to the stack on embedded
- * systems.
- */
-#define XBUF_SIZE 512
-
-/**
- * States in the PP parser's state machine.
- */
-enum PP_State
-{
-  /* general states */
-  PP_Error,
-  PP_Done,
-  PP_Init,
-  PP_NextBoundary,
-
-  /* url encoding-states */
-  PP_ProcessValue,
-  PP_ExpectNewLine,
-
-  /* post encoding-states  */
-  PP_ProcessEntryHeaders,
-  PP_PerformCheckMultipart,
-  PP_ProcessValueToBoundary,
-  PP_PerformCleanup,
-
-  /* nested post-encoding states */
-  PP_Nested_Init,
-  PP_Nested_PerformMarking,
-  PP_Nested_ProcessEntryHeaders,
-  PP_Nested_ProcessValueToBoundary,
-  PP_Nested_PerformCleanup
-
-};
-
-
-enum RN_State
-{
-  /**
-   * No RN-preprocessing in this state.
-   */
-  RN_Inactive = 0,
-
-  /**
-   * If the next character is '\n', skip it.  Otherwise,
-   * just go inactive.
-   */
-  RN_OptN = 1,
-
-  /**
-   * Expect '\r\n' (and only '\r\n').  As always, we also
-   * expect only '\r' or only '\n'.
-   */
-  RN_Full = 2,
-
-  /**
-   * Expect either '\r\n' or '--\r\n'.  If '--\r\n', transition into dash-state
-   * for the main state machine
-   */
-  RN_Dash = 3,
-
-  /**
-   * Got a single dash, expect second dash.
-   */
-  RN_Dash2 = 4
-};
-
-
-/**
- * Bits for the globally known fields that
- * should not be deleted when we exit the
- * nested state.
- */
-enum NE_State
-{
-  NE_none = 0,
-  NE_content_name = 1,
-  NE_content_type = 2,
-  NE_content_filename = 4,
-  NE_content_transfer_encoding = 8
-};
-
-
-/**
- * Internal state of the post-processor.  Note that the fields
- * are sorted by type to enable optimal packing by the compiler.
- */
-struct MHD_PostProcessor
-{
-
-  /**
-   * The connection for which we are doing
-   * POST processing.
-   */
-  struct MHD_Connection *connection;
-
-  /**
-   * Function to call with POST data.
-   */
-  MHD_PostDataIterator ikvi;
-
-  /**
-   * Extra argument to ikvi.
-   */
-  void *cls;
-
-  /**
-   * Encoding as given by the headers of the
-   * connection.
-   */
-  const char *encoding;
-
-  /**
-   * Primary boundary (points into encoding string)
-   */
-  const char *boundary;
-
-  /**
-   * Nested boundary (if we have multipart/mixed encoding).
-   */
-  char *nested_boundary;
-
-  /**
-   * Pointer to the name given in disposition.
-   */
-  char *content_name;
-
-  /**
-   * Pointer to the (current) content type.
-   */
-  char *content_type;
-
-  /**
-   * Pointer to the (current) filename.
-   */
-  char *content_filename;
-
-  /**
-   * Pointer to the (current) encoding.
-   */
-  char *content_transfer_encoding;
-
-  /**
-   * Unprocessed value bytes due to escape
-   * sequences (URL-encoding only).
-   */
-  char xbuf[8];
-
-  /**
-   * Size of our buffer for the key.
-   */
-  size_t buffer_size;
-
-  /**
-   * Current position in the key buffer.
-   */
-  size_t buffer_pos;
-
-  /**
-   * Current position in xbuf.
-   */
-  size_t xbuf_pos;
-
-  /**
-   * Current offset in the value being processed.
-   */
-  uint64_t value_offset;
-
-  /**
-   * strlen(boundary) -- if boundary != NULL.
-   */
-  size_t blen;
-
-  /**
-   * strlen(nested_boundary) -- if nested_boundary != NULL.
-   */
-  size_t nlen;
-
-  /**
-   * Do we have to call the 'ikvi' callback when processing the
-   * multipart post body even if the size of the payload is zero?
-   * Set to MHD_YES whenever we parse a new multiparty entry header,
-   * and to MHD_NO the first time we call the 'ikvi' callback.
-   * Used to ensure that we do always call 'ikvi' even if the
-   * payload is empty (but not more than once).
-   */
-  int must_ikvi;
-
-  /**
-   * State of the parser.
-   */
-  enum PP_State state;
-
-  /**
-   * Side-state-machine: skip '\r\n' (or just '\n').
-   * Set to 0 if we are not in skip mode.  Set to 2
-   * if a '\r\n' is expected, set to 1 if a '\n' should
-   * be skipped if it is the next character.
-   */
-  enum RN_State skip_rn;
-
-  /**
-   * If we are in skip_rn with "dash" mode and
-   * do find 2 dashes, what state do we go into?
-   */
-  enum PP_State dash_state;
-
-  /**
-   * Which headers are global? (used to tell which
-   * headers were only valid for the nested multipart).
-   */
-  enum NE_State have;
-
-};
-
-
-/**
- * Create a PostProcessor.
- *
- * A PostProcessor can be used to (incrementally)
- * parse the data portion of a POST request.
- *
- * @param connection the connection on which the POST is
- *        happening (used to determine the POST format)
- * @param buffer_size maximum number of bytes to use for
- *        internal buffering (used only for the parsing,
- *        specifically the parsing of the keys).  A
- *        tiny value (256-1024) should be sufficient.
- *        Do NOT use 0.
- * @param ikvi iterator to be called with the parsed data
- * @param cls first argument to ikvi
- * @return NULL on error (out of memory, unsupported encoding),
- *         otherwise a PP handle
- */
-struct MHD_PostProcessor *
-MHD_create_post_processor (struct MHD_Connection *connection,
-                           size_t buffer_size,
-                           MHD_PostDataIterator ikvi, void *cls)
-{
-  struct MHD_PostProcessor *ret;
-  const char *encoding;
-  const char *boundary;
-  size_t blen;
-
-  if ((buffer_size < 256) || (connection == NULL) || (ikvi == NULL))
-    mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
-  encoding = MHD_lookup_connection_value (connection,
-                                          MHD_HEADER_KIND,
-                                          MHD_HTTP_HEADER_CONTENT_TYPE);
-  if (encoding == NULL)
-    return NULL;
-  boundary = NULL;
-  if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding,
-                        strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
-    {
-      if (0 !=
-          strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
-                       strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
-        return NULL;
-      boundary =
-        &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
-      /* Q: should this be "strcasestr"? */
-      boundary = strstr (boundary, "boundary=");
-      if (NULL == boundary)
-       return NULL; /* failed to determine boundary */
-      boundary += strlen ("boundary=");
-      blen = strlen (boundary);
-      if ((blen == 0) || (blen * 2 + 2 > buffer_size))
-        return NULL;            /* (will be) out of memory or invalid boundary 
*/
-      if ( (boundary[0] == '"') && (boundary[blen - 1] == '"') )
-       {
-         /* remove enclosing quotes */
-         ++boundary;
-         blen -= 2;
-       } 
-    }
-  else
-    blen = 0;
-  buffer_size += 4; /* round up to get nice block sizes despite boundary 
search */
-
-  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
-  if (NULL == (ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 
1)))
-    return NULL;
-  memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
-  ret->connection = connection;
-  ret->ikvi = ikvi;
-  ret->cls = cls;
-  ret->encoding = encoding;
-  ret->buffer_size = buffer_size;
-  ret->state = PP_Init;
-  ret->blen = blen;
-  ret->boundary = boundary;
-  ret->skip_rn = RN_Inactive;
-  return ret;
-}
-
-
-/**
- * Process url-encoded POST data.
- *
- * @param pp post processor context
- * @param post_data upload data
- * @param post_data_len number of bytes in upload_data
- * @return MHD_YES on success, MHD_NO if there was an error processing the data
- */
-static int
-post_process_urlencoded (struct MHD_PostProcessor *pp,
-                         const char *post_data,
-                        size_t post_data_len)
-{
-  size_t equals;
-  size_t amper;
-  size_t poff;
-  size_t xoff;
-  size_t delta;
-  int end_of_value_found;
-  char *buf;
-  char xbuf[XBUF_SIZE + 1];
-
-  buf = (char *) &pp[1];
-  poff = 0;
-  while (poff < post_data_len)
-    {
-      switch (pp->state)
-        {
-        case PP_Error:
-          return MHD_NO;
-        case PP_Done:
-          /* did not expect to receive more data */
-          pp->state = PP_Error;
-          return MHD_NO;
-        case PP_Init:
-          equals = 0;
-          while ((equals + poff < post_data_len) &&
-                 (post_data[equals + poff] != '='))
-            equals++;
-          if (equals + pp->buffer_pos > pp->buffer_size)
-            {
-              pp->state = PP_Error;     /* out of memory */
-              return MHD_NO;
-            }
-          memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
-          pp->buffer_pos += equals;
-          if (equals + poff == post_data_len)
-            return MHD_YES;     /* no '=' yet */
-          buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
-          pp->buffer_pos = 0;   /* reset for next key */
-          MHD_http_unescape (NULL, NULL, buf);
-          poff += equals + 1;
-          pp->state = PP_ProcessValue;
-          pp->value_offset = 0;
-          break;
-        case PP_ProcessValue:
-          /* obtain rest of value from previous iteration */
-          memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
-          xoff = pp->xbuf_pos;
-          pp->xbuf_pos = 0;
-
-          /* find last position in input buffer that is part of the value */
-          amper = 0;
-          while ((amper + poff < post_data_len) &&
-                 (amper < XBUF_SIZE) &&
-                 (post_data[amper + poff] != '&') &&
-                 (post_data[amper + poff] != '\n') &&
-                 (post_data[amper + poff] != '\r'))
-            amper++;
-          end_of_value_found = ((amper + poff < post_data_len) &&
-                                ((post_data[amper + poff] == '&') ||
-                                 (post_data[amper + poff] == '\n') ||
-                                 (post_data[amper + poff] == '\r')));
-          /* compute delta, the maximum number of bytes that we will be able to
-             process right now (either amper-limited of xbuf-size limited) */
-          delta = amper;
-          if (delta > XBUF_SIZE - xoff)
-            delta = XBUF_SIZE - xoff;
-
-          /* move input into processing buffer */
-          memcpy (&xbuf[xoff], &post_data[poff], delta);
-          xoff += delta;
-          poff += delta;
-
-          /* find if escape sequence is at the end of the processing buffer;
-             if so, exclude those from processing (reduce delta to point at
-             end of processed region) */
-          delta = xoff;
-          if ((delta > 0) && (xbuf[delta - 1] == '%'))
-            delta--;
-          else if ((delta > 1) && (xbuf[delta - 2] == '%'))
-            delta -= 2;
-
-          /* if we have an incomplete escape sequence, save it to
-             pp->xbuf for later */
-          if (delta < xoff)
-            {
-              memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
-              pp->xbuf_pos = xoff - delta;
-              xoff = delta;
-            }
-
-          /* If we have nothing to do (delta == 0) and
-             not just because the value is empty (are
-             waiting for more data), go for next iteration */
-          if ((xoff == 0) && (poff == post_data_len))
-            continue;
-
-          /* unescape */
-          xbuf[xoff] = '\0';    /* 0-terminate in preparation */
-          xoff = MHD_http_unescape (NULL, NULL, xbuf);
-          /* finally: call application! */
-         pp->must_ikvi = MHD_NO;
-          if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) 
&pp[1],    /* key */
-                                  NULL, NULL, NULL, xbuf, pp->value_offset,
-                                  xoff))
-            {
-              pp->state = PP_Error;
-              return MHD_NO;
-            }
-          pp->value_offset += xoff;
-
-          /* are we done with the value? */
-          if (end_of_value_found)
-            {
-              /* we found the end of the value! */
-              if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
-                {
-                  pp->state = PP_ExpectNewLine;
-                }
-              else if (post_data[poff] == '&')
-                {
-                  poff++;       /* skip '&' */
-                  pp->state = PP_Init;
-                }
-            }
-          break;
-        case PP_ExpectNewLine:
-          if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
-            {
-              poff++;
-              /* we are done, report error if we receive any more... */
-              pp->state = PP_Done;
-              return MHD_YES;
-            }
-          return MHD_NO;
-        default:
-          mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* 
should never happen! */
-        }
-    }
-  return MHD_YES;
-}
-
-
-/**
- * If the given line matches the prefix, strdup the
- * rest of the line into the suffix ptr.
- *
- * @param prefix prefix to match
- * @param line line to match prefix in
- * @param suffix set to a copy of the rest of the line, starting at the end of 
the match
- * @return MHD_YES if there was a match, MHD_NO if not
- */
-static int
-try_match_header (const char *prefix, char *line, char **suffix)
-{
-  if (NULL != *suffix)
-    return MHD_NO;
-  while (*line != 0)
-    {
-      if (0 == strncasecmp (prefix, line, strlen (prefix)))
-        {
-          *suffix = strdup (&line[strlen (prefix)]);
-          return MHD_YES;
-        }
-      ++line;
-    }
-  return MHD_NO;
-}
-
-
-/**
- *
- * @param pp post processor context
- */
-static int
-find_boundary (struct MHD_PostProcessor *pp,
-               const char *boundary,
-               size_t blen,
-               size_t *ioffptr,
-               enum PP_State next_state, enum PP_State next_dash_state)
-{
-  char *buf = (char *) &pp[1];
-
-  if (pp->buffer_pos < 2 + blen)
-    {
-      if (pp->buffer_pos == pp->buffer_size)
-        pp->state = PP_Error;   /* out of memory */
-      ++(*ioffptr);
-      return MHD_NO;            /* not enough data */
-    }
-  if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
-    {
-      if (pp->state != PP_Init)
-        pp->state = PP_Error;
-      return MHD_NO;            /* expected boundary */
-    }
-  /* remove boundary from buffer */
-  (*ioffptr) += 2 + blen;
-  /* next: start with headers */
-  pp->skip_rn = RN_Dash;
-  pp->state = next_state;
-  pp->dash_state = next_dash_state;
-  return MHD_YES;
-}
-
-
-/**
- * In buf, there maybe an expression '$key="$value"'.  If that is the
- * case, copy a copy of $value to destination.
- *
- * If destination is already non-NULL,
- * do nothing.
- */
-static void
-try_get_value (const char *buf, 
-              const char *key, 
-              char **destination)
-{
-  const char *spos;
-  const char *bpos;
-  const char *endv;
-  size_t klen;
-  size_t vlen;
-
-  if (NULL != *destination)
-    return;
-  bpos = buf;
-  klen = strlen (key);
-  while (NULL != (spos = strstr (bpos, key)))
-    {
-      if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' ')))
-        {
-          /* no match */
-          bpos = spos + 1;
-          continue;
-        }
-      if (spos[klen + 1] != '"')
-        return;                 /* not quoted */
-      if (NULL == (endv = strchr (&spos[klen + 2], '\"')))
-        return;                 /* no end-quote */
-      vlen = endv - spos - klen - 1;
-      *destination = malloc (vlen);
-      if (NULL == *destination)
-        return;                 /* out of memory */
-      (*destination)[vlen - 1] = '\0';
-      memcpy (*destination, &spos[klen + 2], vlen - 1);
-      return;                   /* success */
-    }
-}
-
-
-/**
- * Go over the headers of the part and update
- * the fields in "pp" according to what we find.
- * If we are at the end of the headers (as indicated
- * by an empty line), transition into next_state.
- *
- * @param pp post processor context
- * @param ioffptr set to how many bytes have been
- *                processed
- * @return MHD_YES if we can continue processing,
- *         MHD_NO on error or if we do not have
- *                enough data yet
- */
-static int
-process_multipart_headers (struct MHD_PostProcessor *pp,
-                           size_t *ioffptr, enum PP_State next_state)
-{
-  char *buf = (char *) &pp[1];
-  size_t newline;
-
-  newline = 0;
-  while ((newline < pp->buffer_pos) &&
-         (buf[newline] != '\r') && (buf[newline] != '\n'))
-    newline++;
-  if (newline == pp->buffer_size)
-    {
-      pp->state = PP_Error;
-      return MHD_NO;            /* out of memory */
-    }
-  if (newline == pp->buffer_pos)
-    return MHD_NO;              /* will need more data */
-  if (newline == 0)
-    {
-      /* empty line - end of headers */
-      pp->skip_rn = RN_Full;
-      pp->state = next_state;
-      return MHD_YES;
-    }
-  /* got an actual header */
-  if (buf[newline] == '\r')
-    pp->skip_rn = RN_OptN;
-  buf[newline] = '\0';
-  if (0 == strncasecmp ("Content-disposition: ",
-                        buf, strlen ("Content-disposition: ")))
-    {
-      try_get_value (&buf[strlen ("Content-disposition: ")],
-                     "name", &pp->content_name);
-      try_get_value (&buf[strlen ("Content-disposition: ")],
-                     "filename", &pp->content_filename);
-    }
-  else
-    {
-      try_match_header ("Content-type: ", buf, &pp->content_type);
-      try_match_header ("Content-Transfer-Encoding: ",
-                        buf, &pp->content_transfer_encoding);
-    }
-  (*ioffptr) += newline + 1;
-  return MHD_YES;
-}
-
-
-/**
- * We have the value until we hit the given boundary;
- * process accordingly.
- *
- * @param pp post processor context
- * @param boundary the boundary to look for
- * @param blen strlen(boundary)
- * @param next_state what state to go into after the
- *        boundary was found
- * @param next_dash_state state to go into if the next
- *        boundary ends with "--"
- * @return MHD_YES if we can continue processing,
- *         MHD_NO on error or if we do not have
- *                enough data yet
- */
-static int
-process_value_to_boundary (struct MHD_PostProcessor *pp,
-                           size_t *ioffptr,
-                           const char *boundary,
-                           size_t blen,
-                           enum PP_State next_state,
-                           enum PP_State next_dash_state)
-{
-  char *buf = (char *) &pp[1];
-  size_t newline;
-
-  /* all data in buf until the boundary
-     (\r\n--+boundary) is part of the value */
-  newline = 0;
-  while (1)
-    {
-      while ((newline + 4 < pp->buffer_pos) &&
-             (0 != memcmp ("\r\n--", &buf[newline], 4)))
-        newline++;
-      if (newline + pp->blen + 4 <= pp->buffer_pos)
-        {
-          /* can check boundary */
-          if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
-            {
-              /* no boundary, "\r\n--" is part of content, skip */
-              newline += 4;
-              continue;
-            }
-          else
-            {
-              /* boundary found, process until newline then
-                 skip boundary and go back to init */
-              pp->skip_rn = RN_Dash;
-              pp->state = next_state;
-              pp->dash_state = next_dash_state;
-              (*ioffptr) += pp->blen + 4;       /* skip boundary as well */
-              buf[newline] = '\0';
-              break;
-            }
-        }
-      else
-        {
-          /* cannot check for boundary, process content that
-             we have and check again later; except, if we have
-             no content, abort (out of memory) */
-          if ((newline == 0) && (pp->buffer_pos == pp->buffer_size))
-            {
-              pp->state = PP_Error;
-              return MHD_NO;
-            }
-          break;
-        }
-    }
-  /* newline is either at beginning of boundary or
-     at least at the last character that we are sure
-     is not part of the boundary */
-  if ( ( (MHD_YES == pp->must_ikvi) ||
-        (0 != newline) ) &&
-       (MHD_NO == pp->ikvi (pp->cls,
-                           MHD_POSTDATA_KIND,
-                           pp->content_name,
-                           pp->content_filename,
-                           pp->content_type,
-                           pp->content_transfer_encoding,
-                           buf, pp->value_offset, newline)) )
-    {
-      pp->state = PP_Error;
-      return MHD_NO;
-    }
-  pp->must_ikvi = MHD_NO;
-  pp->value_offset += newline;
-  (*ioffptr) += newline;
-  return MHD_YES;
-}
-
-
-/**
- *
- * @param pp post processor context
- */
-static void
-free_unmarked (struct MHD_PostProcessor *pp)
-{
-  if ((pp->content_name != NULL) && (0 == (pp->have & NE_content_name)))
-    {
-      free (pp->content_name);
-      pp->content_name = NULL;
-    }
-  if ((pp->content_type != NULL) && (0 == (pp->have & NE_content_type)))
-    {
-      free (pp->content_type);
-      pp->content_type = NULL;
-    }
-  if ((pp->content_filename != NULL) &&
-      (0 == (pp->have & NE_content_filename)))
-    {
-      free (pp->content_filename);
-      pp->content_filename = NULL;
-    }
-  if ((pp->content_transfer_encoding != NULL) &&
-      (0 == (pp->have & NE_content_transfer_encoding)))
-    {
-      free (pp->content_transfer_encoding);
-      pp->content_transfer_encoding = NULL;
-    }
-}
-
-
-/**
- * Decode multipart POST data.
- *
- * @param pp post processor context
- */
-static int
-post_process_multipart (struct MHD_PostProcessor *pp,
-                        const char *post_data,
-                       size_t post_data_len)
-{
-  char *buf;
-  size_t max;
-  size_t ioff;
-  size_t poff;
-  int state_changed;
-
-  buf = (char *) &pp[1];
-  ioff = 0;
-  poff = 0;
-  state_changed = 1;
-  while ((poff < post_data_len) ||
-         ((pp->buffer_pos > 0) && (state_changed != 0)))
-    {
-      /* first, move as much input data
-         as possible to our internal buffer */
-      max = pp->buffer_size - pp->buffer_pos;
-      if (max > post_data_len - poff)
-        max = post_data_len - poff;
-      memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
-      poff += max;
-      pp->buffer_pos += max;
-      if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
-        {
-          pp->state = PP_Error;
-          return MHD_NO;        /* out of memory */
-        }
-      state_changed = 0;
-
-      /* first state machine for '\r'-'\n' and '--' handling */
-      switch (pp->skip_rn)
-        {
-        case RN_Inactive:
-          break;
-        case RN_OptN:
-          if (buf[0] == '\n')
-            {
-              ioff++;
-              pp->skip_rn = RN_Inactive;
-              goto AGAIN;
-            }
-          /* fall-through! */
-        case RN_Dash:
-          if (buf[0] == '-')
-            {
-              ioff++;
-              pp->skip_rn = RN_Dash2;
-              goto AGAIN;
-            }
-          pp->skip_rn = RN_Full;
-          /* fall-through! */
-        case RN_Full:
-          if (buf[0] == '\r')
-            {
-              if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
-                {
-                  pp->skip_rn = RN_Inactive;
-                  ioff += 2;
-                }
-              else
-                {
-                  pp->skip_rn = RN_OptN;
-                  ioff++;
-                }
-              goto AGAIN;
-            }
-          if (buf[0] == '\n')
-            {
-              ioff++;
-              pp->skip_rn = RN_Inactive;
-              goto AGAIN;
-            }
-          pp->skip_rn = RN_Inactive;
-          pp->state = PP_Error;
-          return MHD_NO;        /* no '\r\n' */
-        case RN_Dash2:
-          if (buf[0] == '-')
-            {
-              ioff++;
-              pp->skip_rn = RN_Full;
-              pp->state = pp->dash_state;
-              goto AGAIN;
-            }
-          pp->state = PP_Error;
-          break;
-        }
-
-      /* main state engine */
-      switch (pp->state)
-        {
-        case PP_Error:
-          return MHD_NO;
-        case PP_Done:
-          /* did not expect to receive more data */
-          pp->state = PP_Error;
-          return MHD_NO;
-        case PP_Init:
-          /**
-           * Per RFC2046 5.1.1 NOTE TO IMPLEMENTORS, consume anything
-           * prior to the first multipart boundary:
-           *
-           * > There appears to be room for additional information prior
-           * > to the first boundary delimiter line and following the
-           * > final boundary delimiter line.  These areas should
-           * > generally be left blank, and implementations must ignore
-           * > anything that appears before the first boundary delimiter
-           * > line or after the last one.
-           */
-          (void) find_boundary (pp,
-                               pp->boundary,
-                               pp->blen,
-                               &ioff,
-                               PP_ProcessEntryHeaders, PP_Done);
-          break;
-        case PP_NextBoundary:
-          if (MHD_NO == find_boundary (pp,
-                                       pp->boundary,
-                                       pp->blen,
-                                       &ioff,
-                                       PP_ProcessEntryHeaders, PP_Done))
-            {
-              if (pp->state == PP_Error)
-                return MHD_NO;
-              goto END;
-            }
-          break;
-        case PP_ProcessEntryHeaders:
-         pp->must_ikvi = MHD_YES;
-          if (MHD_NO ==
-              process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
-            {
-              if (pp->state == PP_Error)
-                return MHD_NO;
-              else
-                goto END;
-            }
-          state_changed = 1;
-          break;
-        case PP_PerformCheckMultipart:
-          if ((pp->content_type != NULL) &&
-              (0 == strncasecmp (pp->content_type,
-                                 "multipart/mixed",
-                                 strlen ("multipart/mixed"))))
-            {
-              pp->nested_boundary = strstr (pp->content_type, "boundary=");
-              if (pp->nested_boundary == NULL)
-                {
-                  pp->state = PP_Error;
-                  return MHD_NO;
-                }
-              pp->nested_boundary =
-                strdup (&pp->nested_boundary[strlen ("boundary=")]);
-              if (pp->nested_boundary == NULL)
-                {
-                  /* out of memory */
-                  pp->state = PP_Error;
-                  return MHD_NO;
-                }
-              /* free old content type, we will need that field
-                 for the content type of the nested elements */
-              free (pp->content_type);
-              pp->content_type = NULL;
-              pp->nlen = strlen (pp->nested_boundary);
-              pp->state = PP_Nested_Init;
-              state_changed = 1;
-              break;
-            }
-          pp->state = PP_ProcessValueToBoundary;
-          pp->value_offset = 0;
-          state_changed = 1;
-          break;
-        case PP_ProcessValueToBoundary:
-          if (MHD_NO == process_value_to_boundary (pp,
-                                                   &ioff,
-                                                   pp->boundary,
-                                                   pp->blen,
-                                                   PP_PerformCleanup,
-                                                   PP_Done))
-            {
-              if (pp->state == PP_Error)
-                return MHD_NO;
-              break;
-            }
-          break;
-        case PP_PerformCleanup:
-          /* clean up state of one multipart form-data element! */
-          pp->have = NE_none;
-          free_unmarked (pp);
-          if (pp->nested_boundary != NULL)
-            {
-              free (pp->nested_boundary);
-              pp->nested_boundary = NULL;
-            }
-          pp->state = PP_ProcessEntryHeaders;
-          state_changed = 1;
-          break;
-        case PP_Nested_Init:
-          if (pp->nested_boundary == NULL)
-            {
-              pp->state = PP_Error;
-              return MHD_NO;
-            }
-          if (MHD_NO == find_boundary (pp,
-                                       pp->nested_boundary,
-                                       pp->nlen,
-                                       &ioff,
-                                       PP_Nested_PerformMarking,
-                                       PP_NextBoundary /* or PP_Error? */ ))
-            {
-              if (pp->state == PP_Error)
-                return MHD_NO;
-              goto END;
-            }
-          break;
-        case PP_Nested_PerformMarking:
-          /* remember what headers were given
-             globally */
-          pp->have = NE_none;
-          if (pp->content_name != NULL)
-            pp->have |= NE_content_name;
-          if (pp->content_type != NULL)
-            pp->have |= NE_content_type;
-          if (pp->content_filename != NULL)
-            pp->have |= NE_content_filename;
-          if (pp->content_transfer_encoding != NULL)
-            pp->have |= NE_content_transfer_encoding;
-          pp->state = PP_Nested_ProcessEntryHeaders;
-          state_changed = 1;
-          break;
-        case PP_Nested_ProcessEntryHeaders:
-          pp->value_offset = 0;
-          if (MHD_NO ==
-              process_multipart_headers (pp, &ioff,
-                                         PP_Nested_ProcessValueToBoundary))
-            {
-              if (pp->state == PP_Error)
-                return MHD_NO;
-              else
-                goto END;
-            }
-          state_changed = 1;
-          break;
-        case PP_Nested_ProcessValueToBoundary:
-          if (MHD_NO == process_value_to_boundary (pp,
-                                                   &ioff,
-                                                   pp->nested_boundary,
-                                                   pp->nlen,
-                                                   PP_Nested_PerformCleanup,
-                                                   PP_NextBoundary))
-            {
-              if (pp->state == PP_Error)
-                return MHD_NO;
-              break;
-            }
-          break;
-        case PP_Nested_PerformCleanup:
-          free_unmarked (pp);
-          pp->state = PP_Nested_ProcessEntryHeaders;
-          state_changed = 1;
-          break;
-        default:
-          mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* 
should never happen! */
-        }
-    AGAIN:
-      if (ioff > 0)
-        {
-          memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
-          pp->buffer_pos -= ioff;
-          ioff = 0;
-          state_changed = 1;
-        }
-    }
-END:
-  if (ioff != 0)
-    {
-      memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
-      pp->buffer_pos -= ioff;
-    }
-  if (poff < post_data_len)
-    {
-      pp->state = PP_Error;
-      return MHD_NO;            /* serious error */
-    }
-  return MHD_YES;
-}
-
-
-/**
- * Parse and process POST data.
- * Call this function when POST data is available
- * (usually during an MHD_AccessHandlerCallback)
- * with the upload_data and upload_data_size.
- * Whenever possible, this will then cause calls
- * to the MHD_IncrementalKeyValueIterator.
- *
- * @param pp the post processor
- * @param post_data post_data_len bytes of POST data
- * @param post_data_len length of post_data
- * @return MHD_YES on success, MHD_NO on error
- *         (out-of-memory, iterator aborted, parse error)
- */
-int
-MHD_post_process (struct MHD_PostProcessor *pp,
-                  const char *post_data, size_t post_data_len)
-{
-  if (post_data_len == 0)
-    return MHD_YES;
-  if (pp == NULL)
-    return MHD_NO;
-  if (0 == strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding,
-                         strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
-    return post_process_urlencoded (pp, post_data, post_data_len);
-  if (0 ==
-      strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
-                   strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
-    return post_process_multipart (pp, post_data, post_data_len);
-  /* this should never be reached */
-  return MHD_NO;
-}
-
-
-/**
- * Release PostProcessor resources.
- *
- * @param pp post processor context to destroy
- * @return MHD_YES if processing completed nicely,
- *         MHD_NO if there were spurious characters / formatting
- *                problems; it is common to ignore the return
- *                value of this function
- */
-int
-MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
-{
-  int ret;
-
-  if (NULL == pp)
-    return MHD_YES;
-  if (PP_ProcessValue == pp->state)
-  {
-    /* key without terminated value left at the end of the
-       buffer; fake receiving a termination character to
-       ensure it is also processed */
-    post_process_urlencoded (pp, "\n", 1);
-  }
-  /* These internal strings need cleaning up since
-     the post-processing may have been interrupted
-     at any stage */
-  if ((pp->xbuf_pos > 0) || 
-      ( (pp->state != PP_Done) &&
-       (pp->state != PP_ExpectNewLine)))
-    ret = MHD_NO;
-  else
-    ret = MHD_YES;
-  pp->have = NE_none;
-  free_unmarked (pp);
-  if (pp->nested_boundary != NULL)
-    free (pp->nested_boundary);
-  free (pp);
-  return ret;
-}
-
-/* end of postprocessor.c */

Copied: libmicrohttpd/src/microhttpd/postprocessor.c (from rev 27024, 
libmicrohttpd/src/daemon/postprocessor.c)
===================================================================
--- libmicrohttpd/src/microhttpd/postprocessor.c                                
(rev 0)
+++ libmicrohttpd/src/microhttpd/postprocessor.c        2013-05-05 18:07:33 UTC 
(rev 27025)
@@ -0,0 +1,1158 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+*/
+
+/**
+ * @file postprocessor.c
+ * @brief  Methods for parsing POST data
+ * @author Christian Grothoff
+ */
+
+#include "internal.h"
+
+/**
+ * Size of on-stack buffer that we use for un-escaping of the value.
+ * We use a pretty small value to be nice to the stack on embedded
+ * systems.
+ */
+#define XBUF_SIZE 512
+
+/**
+ * States in the PP parser's state machine.
+ */
+enum PP_State
+{
+  /* general states */
+  PP_Error,
+  PP_Done,
+  PP_Init,
+  PP_NextBoundary,
+
+  /* url encoding-states */
+  PP_ProcessValue,
+  PP_ExpectNewLine,
+
+  /* post encoding-states  */
+  PP_ProcessEntryHeaders,
+  PP_PerformCheckMultipart,
+  PP_ProcessValueToBoundary,
+  PP_PerformCleanup,
+
+  /* nested post-encoding states */
+  PP_Nested_Init,
+  PP_Nested_PerformMarking,
+  PP_Nested_ProcessEntryHeaders,
+  PP_Nested_ProcessValueToBoundary,
+  PP_Nested_PerformCleanup
+
+};
+
+
+enum RN_State
+{
+  /**
+   * No RN-preprocessing in this state.
+   */
+  RN_Inactive = 0,
+
+  /**
+   * If the next character is CR, skip it.  Otherwise,
+   * just go inactive.
+   */
+  RN_OptN = 1,
+
+  /**
+   * Expect LFCR (and only LFCR).  As always, we also
+   * expect only LF or only CR.
+   */
+  RN_Full = 2,
+
+  /**
+   * Expect either LFCR or '--'LFCR.  If '--'LFCR, transition into dash-state
+   * for the main state machine
+   */
+  RN_Dash = 3,
+
+  /**
+   * Got a single dash, expect second dash.
+   */
+  RN_Dash2 = 4
+};
+
+
+/**
+ * Bits for the globally known fields that
+ * should not be deleted when we exit the
+ * nested state.
+ */
+enum NE_State
+{
+  NE_none = 0,
+  NE_content_name = 1,
+  NE_content_type = 2,
+  NE_content_filename = 4,
+  NE_content_transfer_encoding = 8
+};
+
+
+/**
+ * Internal state of the post-processor.  Note that the fields
+ * are sorted by type to enable optimal packing by the compiler.
+ */
+struct MHD_PostProcessor
+{
+
+  /**
+   * The connection for which we are doing
+   * POST processing.
+   */
+  struct MHD_Connection *connection;
+
+  /**
+   * Function to call with POST data.
+   */
+  MHD_PostDataIterator ikvi;
+
+  /**
+   * Extra argument to ikvi.
+   */
+  void *cls;
+
+  /**
+   * Encoding as given by the headers of the
+   * connection.
+   */
+  const char *encoding;
+
+  /**
+   * Primary boundary (points into encoding string)
+   */
+  const char *boundary;
+
+  /**
+   * Nested boundary (if we have multipart/mixed encoding).
+   */
+  char *nested_boundary;
+
+  /**
+   * Pointer to the name given in disposition.
+   */
+  char *content_name;
+
+  /**
+   * Pointer to the (current) content type.
+   */
+  char *content_type;
+
+  /**
+   * Pointer to the (current) filename.
+   */
+  char *content_filename;
+
+  /**
+   * Pointer to the (current) encoding.
+   */
+  char *content_transfer_encoding;
+
+  /**
+   * Unprocessed value bytes due to escape
+   * sequences (URL-encoding only).
+   */
+  char xbuf[8];
+
+  /**
+   * Size of our buffer for the key.
+   */
+  size_t buffer_size;
+
+  /**
+   * Current position in the key buffer.
+   */
+  size_t buffer_pos;
+
+  /**
+   * Current position in xbuf.
+   */
+  size_t xbuf_pos;
+
+  /**
+   * Current offset in the value being processed.
+   */
+  uint64_t value_offset;
+
+  /**
+   * strlen(boundary) -- if boundary != NULL.
+   */
+  size_t blen;
+
+  /**
+   * strlen(nested_boundary) -- if nested_boundary != NULL.
+   */
+  size_t nlen;
+
+  /**
+   * Do we have to call the 'ikvi' callback when processing the
+   * multipart post body even if the size of the payload is zero?
+   * Set to MHD_YES whenever we parse a new multiparty entry header,
+   * and to MHD_NO the first time we call the 'ikvi' callback.
+   * Used to ensure that we do always call 'ikvi' even if the
+   * payload is empty (but not more than once).
+   */
+  int must_ikvi;
+
+  /**
+   * State of the parser.
+   */
+  enum PP_State state;
+
+  /**
+   * Side-state-machine: skip LRCR (or just LF).
+   * Set to 0 if we are not in skip mode.  Set to 2
+   * if a LFCR is expected, set to 1 if a CR should
+   * be skipped if it is the next character.
+   */
+  enum RN_State skip_rn;
+
+  /**
+   * If we are in skip_rn with "dash" mode and
+   * do find 2 dashes, what state do we go into?
+   */
+  enum PP_State dash_state;
+
+  /**
+   * Which headers are global? (used to tell which
+   * headers were only valid for the nested multipart).
+   */
+  enum NE_State have;
+
+};
+
+
+/**
+ * Create a PostProcessor.
+ *
+ * A PostProcessor can be used to (incrementally)
+ * parse the data portion of a POST request.
+ *
+ * @param connection the connection on which the POST is
+ *        happening (used to determine the POST format)
+ * @param buffer_size maximum number of bytes to use for
+ *        internal buffering (used only for the parsing,
+ *        specifically the parsing of the keys).  A
+ *        tiny value (256-1024) should be sufficient.
+ *        Do NOT use 0.
+ * @param iter iterator to be called with the parsed data
+ * @param iter_cls first argument to iter
+ * @return NULL on error (out of memory, unsupported encoding),
+ *         otherwise a PP handle
+ */
+struct MHD_PostProcessor *
+MHD_create_post_processor (struct MHD_Connection *connection,
+                           size_t buffer_size,
+                           MHD_PostDataIterator iter, void *iter_cls)
+{
+  struct MHD_PostProcessor *ret;
+  const char *encoding;
+  const char *boundary;
+  size_t blen;
+
+  if ((buffer_size < 256) || (connection == NULL) || (iter == NULL))
+    mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
+  encoding = MHD_lookup_connection_value (connection,
+                                          MHD_HEADER_KIND,
+                                          MHD_HTTP_HEADER_CONTENT_TYPE);
+  if (encoding == NULL)
+    return NULL;
+  boundary = NULL;
+  if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding,
+                        strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
+    {
+      if (0 !=
+          strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding,
+                       strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
+        return NULL;
+      boundary =
+        &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)];
+      /* Q: should this be "strcasestr"? */
+      boundary = strstr (boundary, "boundary=");
+      if (NULL == boundary)
+       return NULL; /* failed to determine boundary */
+      boundary += strlen ("boundary=");
+      blen = strlen (boundary);
+      if ((blen == 0) || (blen * 2 + 2 > buffer_size))
+        return NULL;            /* (will be) out of memory or invalid boundary 
*/
+      if ( (boundary[0] == '"') && (boundary[blen - 1] == '"') )
+       {
+         /* remove enclosing quotes */
+         ++boundary;
+         blen -= 2;
+       } 
+    }
+  else
+    blen = 0;
+  buffer_size += 4; /* round up to get nice block sizes despite boundary 
search */
+
+  /* add +1 to ensure we ALWAYS have a zero-termination at the end */
+  if (NULL == (ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 
1)))
+    return NULL;
+  memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1);
+  ret->connection = connection;
+  ret->ikvi = iter;
+  ret->cls = iter_cls;
+  ret->encoding = encoding;
+  ret->buffer_size = buffer_size;
+  ret->state = PP_Init;
+  ret->blen = blen;
+  ret->boundary = boundary;
+  ret->skip_rn = RN_Inactive;
+  return ret;
+}
+
+
+/**
+ * Process url-encoded POST data.
+ *
+ * @param pp post processor context
+ * @param post_data upload data
+ * @param post_data_len number of bytes in upload_data
+ * @return MHD_YES on success, MHD_NO if there was an error processing the data
+ */
+static int
+post_process_urlencoded (struct MHD_PostProcessor *pp,
+                         const char *post_data,
+                        size_t post_data_len)
+{
+  size_t equals;
+  size_t amper;
+  size_t poff;
+  size_t xoff;
+  size_t delta;
+  int end_of_value_found;
+  char *buf;
+  char xbuf[XBUF_SIZE + 1];
+
+  buf = (char *) &pp[1];
+  poff = 0;
+  while (poff < post_data_len)
+    {
+      switch (pp->state)
+        {
+        case PP_Error:
+          return MHD_NO;
+        case PP_Done:
+          /* did not expect to receive more data */
+          pp->state = PP_Error;
+          return MHD_NO;
+        case PP_Init:
+          equals = 0;
+          while ((equals + poff < post_data_len) &&
+                 (post_data[equals + poff] != '='))
+            equals++;
+          if (equals + pp->buffer_pos > pp->buffer_size)
+            {
+              pp->state = PP_Error;     /* out of memory */
+              return MHD_NO;
+            }
+          memcpy (&buf[pp->buffer_pos], &post_data[poff], equals);
+          pp->buffer_pos += equals;
+          if (equals + poff == post_data_len)
+            return MHD_YES;     /* no '=' yet */
+          buf[pp->buffer_pos] = '\0';   /* 0-terminate key */
+          pp->buffer_pos = 0;   /* reset for next key */
+          MHD_http_unescape (NULL, NULL, buf);
+          poff += equals + 1;
+          pp->state = PP_ProcessValue;
+          pp->value_offset = 0;
+          break;
+        case PP_ProcessValue:
+          /* obtain rest of value from previous iteration */
+          memcpy (xbuf, pp->xbuf, pp->xbuf_pos);
+          xoff = pp->xbuf_pos;
+          pp->xbuf_pos = 0;
+
+          /* find last position in input buffer that is part of the value */
+          amper = 0;
+          while ((amper + poff < post_data_len) &&
+                 (amper < XBUF_SIZE) &&
+                 (post_data[amper + poff] != '&') &&
+                 (post_data[amper + poff] != '\n') &&
+                 (post_data[amper + poff] != '\r'))
+            amper++;
+          end_of_value_found = ((amper + poff < post_data_len) &&
+                                ((post_data[amper + poff] == '&') ||
+                                 (post_data[amper + poff] == '\n') ||
+                                 (post_data[amper + poff] == '\r')));
+          /* compute delta, the maximum number of bytes that we will be able to
+             process right now (either amper-limited of xbuf-size limited) */
+          delta = amper;
+          if (delta > XBUF_SIZE - xoff)
+            delta = XBUF_SIZE - xoff;
+
+          /* move input into processing buffer */
+          memcpy (&xbuf[xoff], &post_data[poff], delta);
+          xoff += delta;
+          poff += delta;
+
+          /* find if escape sequence is at the end of the processing buffer;
+             if so, exclude those from processing (reduce delta to point at
+             end of processed region) */
+          delta = xoff;
+          if ((delta > 0) && (xbuf[delta - 1] == '%'))
+            delta--;
+          else if ((delta > 1) && (xbuf[delta - 2] == '%'))
+            delta -= 2;
+
+          /* if we have an incomplete escape sequence, save it to
+             pp->xbuf for later */
+          if (delta < xoff)
+            {
+              memcpy (pp->xbuf, &xbuf[delta], xoff - delta);
+              pp->xbuf_pos = xoff - delta;
+              xoff = delta;
+            }
+
+          /* If we have nothing to do (delta == 0) and
+             not just because the value is empty (are
+             waiting for more data), go for next iteration */
+          if ((xoff == 0) && (poff == post_data_len))
+            continue;
+
+          /* unescape */
+          xbuf[xoff] = '\0';    /* 0-terminate in preparation */
+          xoff = MHD_http_unescape (NULL, NULL, xbuf);
+          /* finally: call application! */
+         pp->must_ikvi = MHD_NO;
+          if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) 
&pp[1],    /* key */
+                                  NULL, NULL, NULL, xbuf, pp->value_offset,
+                                  xoff))
+            {
+              pp->state = PP_Error;
+              return MHD_NO;
+            }
+          pp->value_offset += xoff;
+
+          /* are we done with the value? */
+          if (end_of_value_found)
+            {
+              /* we found the end of the value! */
+              if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
+                {
+                  pp->state = PP_ExpectNewLine;
+                }
+              else if (post_data[poff] == '&')
+                {
+                  poff++;       /* skip '&' */
+                  pp->state = PP_Init;
+                }
+            }
+          break;
+        case PP_ExpectNewLine:
+          if ((post_data[poff] == '\n') || (post_data[poff] == '\r'))
+            {
+              poff++;
+              /* we are done, report error if we receive any more... */
+              pp->state = PP_Done;
+              return MHD_YES;
+            }
+          return MHD_NO;
+        default:
+          mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* 
should never happen! */
+        }
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * If the given line matches the prefix, strdup the
+ * rest of the line into the suffix ptr.
+ *
+ * @param prefix prefix to match
+ * @param line line to match prefix in
+ * @param suffix set to a copy of the rest of the line, starting at the end of 
the match
+ * @return MHD_YES if there was a match, MHD_NO if not
+ */
+static int
+try_match_header (const char *prefix, char *line, char **suffix)
+{
+  if (NULL != *suffix)
+    return MHD_NO;
+  while (*line != 0)
+    {
+      if (0 == strncasecmp (prefix, line, strlen (prefix)))
+        {
+          *suffix = strdup (&line[strlen (prefix)]);
+          return MHD_YES;
+        }
+      ++line;
+    }
+  return MHD_NO;
+}
+
+
+/**
+ *
+ * @param pp post processor context
+ * @param boundary boundary to look for
+ * @param blen number of bytes in boundary
+ * @param ioffptr set to the end of the boundary if found,
+ *                otherwise incremented by one (FIXME: quirky API!)
+ * @param next_state state to which we should advance the post processor
+ *                   if the boundary is found
+ * @param next_dash_state dash_state to which we should advance the
+ *                   post processor if the boundary is found
+ * @return MHD_NO if the boundary is not found, MHD_YES if we did find it
+ */
+static int
+find_boundary (struct MHD_PostProcessor *pp,
+               const char *boundary,
+               size_t blen,
+               size_t *ioffptr,
+               enum PP_State next_state, enum PP_State next_dash_state)
+{
+  char *buf = (char *) &pp[1];
+
+  if (pp->buffer_pos < 2 + blen)
+    {
+      if (pp->buffer_pos == pp->buffer_size)
+        pp->state = PP_Error;   /* out of memory */
+      ++(*ioffptr);
+      return MHD_NO;            /* not enough data */
+    }
+  if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen)))
+    {
+      if (pp->state != PP_Init)
+        pp->state = PP_Error;
+      return MHD_NO;            /* expected boundary */
+    }
+  /* remove boundary from buffer */
+  (*ioffptr) += 2 + blen;
+  /* next: start with headers */
+  pp->skip_rn = RN_Dash;
+  pp->state = next_state;
+  pp->dash_state = next_dash_state;
+  return MHD_YES;
+}
+
+
+/**
+ * In buf, there maybe an expression '$key="$value"'.  If that is the
+ * case, copy a copy of $value to destination.
+ *
+ * If destination is already non-NULL,
+ * do nothing.
+ */
+static void
+try_get_value (const char *buf, 
+              const char *key, 
+              char **destination)
+{
+  const char *spos;
+  const char *bpos;
+  const char *endv;
+  size_t klen;
+  size_t vlen;
+
+  if (NULL != *destination)
+    return;
+  bpos = buf;
+  klen = strlen (key);
+  while (NULL != (spos = strstr (bpos, key)))
+    {
+      if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' ')))
+        {
+          /* no match */
+          bpos = spos + 1;
+          continue;
+        }
+      if (spos[klen + 1] != '"')
+        return;                 /* not quoted */
+      if (NULL == (endv = strchr (&spos[klen + 2], '\"')))
+        return;                 /* no end-quote */
+      vlen = endv - spos - klen - 1;
+      *destination = malloc (vlen);
+      if (NULL == *destination)
+        return;                 /* out of memory */
+      (*destination)[vlen - 1] = '\0';
+      memcpy (*destination, &spos[klen + 2], vlen - 1);
+      return;                   /* success */
+    }
+}
+
+
+/**
+ * Go over the headers of the part and update
+ * the fields in "pp" according to what we find.
+ * If we are at the end of the headers (as indicated
+ * by an empty line), transition into next_state.
+ *
+ * @param pp post processor context
+ * @param ioffptr set to how many bytes have been
+ *                processed
+ * @param next_state state to which the post processor should
+ *                be advanced if we find the end of the headers
+ * @return MHD_YES if we can continue processing,
+ *         MHD_NO on error or if we do not have
+ *                enough data yet
+ */
+static int
+process_multipart_headers (struct MHD_PostProcessor *pp,
+                           size_t *ioffptr, enum PP_State next_state)
+{
+  char *buf = (char *) &pp[1];
+  size_t newline;
+
+  newline = 0;
+  while ((newline < pp->buffer_pos) &&
+         (buf[newline] != '\r') && (buf[newline] != '\n'))
+    newline++;
+  if (newline == pp->buffer_size)
+    {
+      pp->state = PP_Error;
+      return MHD_NO;            /* out of memory */
+    }
+  if (newline == pp->buffer_pos)
+    return MHD_NO;              /* will need more data */
+  if (0 == newline)
+    {
+      /* empty line - end of headers */
+      pp->skip_rn = RN_Full;
+      pp->state = next_state;
+      return MHD_YES;
+    }
+  /* got an actual header */
+  if (buf[newline] == '\r')
+    pp->skip_rn = RN_OptN;
+  buf[newline] = '\0';
+  if (0 == strncasecmp ("Content-disposition: ",
+                        buf, strlen ("Content-disposition: ")))
+    {
+      try_get_value (&buf[strlen ("Content-disposition: ")],
+                     "name", &pp->content_name);
+      try_get_value (&buf[strlen ("Content-disposition: ")],
+                     "filename", &pp->content_filename);
+    }
+  else
+    {
+      try_match_header ("Content-type: ", buf, &pp->content_type);
+      try_match_header ("Content-Transfer-Encoding: ",
+                        buf, &pp->content_transfer_encoding);
+    }
+  (*ioffptr) += newline + 1;
+  return MHD_YES;
+}
+
+
+/**
+ * We have the value until we hit the given boundary;
+ * process accordingly.
+ *
+ * @param pp post processor context
+ * @param ioffptr incremented based on the number of bytes processed
+ * @param boundary the boundary to look for
+ * @param blen strlen(boundary)
+ * @param next_state what state to go into after the
+ *        boundary was found
+ * @param next_dash_state state to go into if the next
+ *        boundary ends with "--"
+ * @return MHD_YES if we can continue processing,
+ *         MHD_NO on error or if we do not have
+ *                enough data yet
+ */
+static int
+process_value_to_boundary (struct MHD_PostProcessor *pp,
+                           size_t *ioffptr,
+                           const char *boundary,
+                           size_t blen,
+                           enum PP_State next_state,
+                           enum PP_State next_dash_state)
+{
+  char *buf = (char *) &pp[1];
+  size_t newline;
+
+  /* all data in buf until the boundary
+     (\r\n--+boundary) is part of the value */
+  newline = 0;
+  while (1)
+    {
+      while ((newline + 4 < pp->buffer_pos) &&
+             (0 != memcmp ("\r\n--", &buf[newline], 4)))
+        newline++;
+      if (newline + pp->blen + 4 <= pp->buffer_pos)
+        {
+          /* can check boundary */
+          if (0 != memcmp (&buf[newline + 4], boundary, pp->blen))
+            {
+              /* no boundary, "\r\n--" is part of content, skip */
+              newline += 4;
+              continue;
+            }
+          else
+            {
+              /* boundary found, process until newline then
+                 skip boundary and go back to init */
+              pp->skip_rn = RN_Dash;
+              pp->state = next_state;
+              pp->dash_state = next_dash_state;
+              (*ioffptr) += pp->blen + 4;       /* skip boundary as well */
+              buf[newline] = '\0';
+              break;
+            }
+        }
+      else
+        {
+          /* cannot check for boundary, process content that
+             we have and check again later; except, if we have
+             no content, abort (out of memory) */
+          if ((0 == newline) && (pp->buffer_pos == pp->buffer_size))
+            {
+              pp->state = PP_Error;
+              return MHD_NO;
+            }
+          break;
+        }
+    }
+  /* newline is either at beginning of boundary or
+     at least at the last character that we are sure
+     is not part of the boundary */
+  if ( ( (MHD_YES == pp->must_ikvi) ||
+        (0 != newline) ) &&
+       (MHD_NO == pp->ikvi (pp->cls,
+                           MHD_POSTDATA_KIND,
+                           pp->content_name,
+                           pp->content_filename,
+                           pp->content_type,
+                           pp->content_transfer_encoding,
+                           buf, pp->value_offset, newline)) )
+    {
+      pp->state = PP_Error;
+      return MHD_NO;
+    }
+  pp->must_ikvi = MHD_NO;
+  pp->value_offset += newline;
+  (*ioffptr) += newline;
+  return MHD_YES;
+}
+
+
+/**
+ *
+ * @param pp post processor context
+ */
+static void
+free_unmarked (struct MHD_PostProcessor *pp)
+{
+  if ((NULL != pp->content_name) && (0 == (pp->have & NE_content_name)))
+    {
+      free (pp->content_name);
+      pp->content_name = NULL;
+    }
+  if ((NULL != pp->content_type) && (0 == (pp->have & NE_content_type)))
+    {
+      free (pp->content_type);
+      pp->content_type = NULL;
+    }
+  if ((NULL != pp->content_filename) &&
+      (0 == (pp->have & NE_content_filename)))
+    {
+      free (pp->content_filename);
+      pp->content_filename = NULL;
+    }
+  if ((NULL != pp->content_transfer_encoding) &&
+      (0 == (pp->have & NE_content_transfer_encoding)))
+    {
+      free (pp->content_transfer_encoding);
+      pp->content_transfer_encoding = NULL;
+    }
+}
+
+
+/**
+ * Decode multipart POST data.
+ *
+ * @param pp post processor context
+ * @param post_data data to decode
+ * @param post_data_len number of bytes in 'post_data'
+ * @return MHD_NO on error, 
+ */
+static int
+post_process_multipart (struct MHD_PostProcessor *pp,
+                        const char *post_data,
+                       size_t post_data_len)
+{
+  char *buf;
+  size_t max;
+  size_t ioff;
+  size_t poff;
+  int state_changed;
+
+  buf = (char *) &pp[1];
+  ioff = 0;
+  poff = 0;
+  state_changed = 1;
+  while ((poff < post_data_len) ||
+         ((pp->buffer_pos > 0) && (state_changed != 0)))
+    {
+      /* first, move as much input data
+         as possible to our internal buffer */
+      max = pp->buffer_size - pp->buffer_pos;
+      if (max > post_data_len - poff)
+        max = post_data_len - poff;
+      memcpy (&buf[pp->buffer_pos], &post_data[poff], max);
+      poff += max;
+      pp->buffer_pos += max;
+      if ((max == 0) && (state_changed == 0) && (poff < post_data_len))
+        {
+          pp->state = PP_Error;
+          return MHD_NO;        /* out of memory */
+        }
+      state_changed = 0;
+
+      /* first state machine for '\r'-'\n' and '--' handling */
+      switch (pp->skip_rn)
+        {
+        case RN_Inactive:
+          break;
+        case RN_OptN:
+          if (buf[0] == '\n')
+            {
+              ioff++;
+              pp->skip_rn = RN_Inactive;
+              goto AGAIN;
+            }
+          /* fall-through! */
+        case RN_Dash:
+          if (buf[0] == '-')
+            {
+              ioff++;
+              pp->skip_rn = RN_Dash2;
+              goto AGAIN;
+            }
+          pp->skip_rn = RN_Full;
+          /* fall-through! */
+        case RN_Full:
+          if (buf[0] == '\r')
+            {
+              if ((pp->buffer_pos > 1) && (buf[1] == '\n'))
+                {
+                  pp->skip_rn = RN_Inactive;
+                  ioff += 2;
+                }
+              else
+                {
+                  pp->skip_rn = RN_OptN;
+                  ioff++;
+                }
+              goto AGAIN;
+            }
+          if (buf[0] == '\n')
+            {
+              ioff++;
+              pp->skip_rn = RN_Inactive;
+              goto AGAIN;
+            }
+          pp->skip_rn = RN_Inactive;
+          pp->state = PP_Error;
+          return MHD_NO;        /* no '\r\n' */
+        case RN_Dash2:
+          if (buf[0] == '-')
+            {
+              ioff++;
+              pp->skip_rn = RN_Full;
+              pp->state = pp->dash_state;
+              goto AGAIN;
+            }
+          pp->state = PP_Error;
+          break;
+        }
+
+      /* main state engine */
+      switch (pp->state)
+        {
+        case PP_Error:
+          return MHD_NO;
+        case PP_Done:
+          /* did not expect to receive more data */
+          pp->state = PP_Error;
+          return MHD_NO;
+        case PP_Init:
+          /**
+           * Per RFC2046 5.1.1 NOTE TO IMPLEMENTORS, consume anything
+           * prior to the first multipart boundary:
+           *
+           * > There appears to be room for additional information prior
+           * > to the first boundary delimiter line and following the
+           * > final boundary delimiter line.  These areas should
+           * > generally be left blank, and implementations must ignore
+           * > anything that appears before the first boundary delimiter
+           * > line or after the last one.
+           */
+          (void) find_boundary (pp,
+                               pp->boundary,
+                               pp->blen,
+                               &ioff,
+                               PP_ProcessEntryHeaders, PP_Done);
+          break;
+        case PP_NextBoundary:
+          if (MHD_NO == find_boundary (pp,
+                                       pp->boundary,
+                                       pp->blen,
+                                       &ioff,
+                                       PP_ProcessEntryHeaders, PP_Done))
+            {
+              if (pp->state == PP_Error)
+                return MHD_NO;
+              goto END;
+            }
+          break;
+        case PP_ProcessEntryHeaders:
+         pp->must_ikvi = MHD_YES;
+          if (MHD_NO ==
+              process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart))
+            {
+              if (pp->state == PP_Error)
+                return MHD_NO;
+              else
+                goto END;
+            }
+          state_changed = 1;
+          break;
+        case PP_PerformCheckMultipart:
+          if ((pp->content_type != NULL) &&
+              (0 == strncasecmp (pp->content_type,
+                                 "multipart/mixed",
+                                 strlen ("multipart/mixed"))))
+            {
+              pp->nested_boundary = strstr (pp->content_type, "boundary=");
+              if (pp->nested_boundary == NULL)
+                {
+                  pp->state = PP_Error;
+                  return MHD_NO;
+                }
+              pp->nested_boundary =
+                strdup (&pp->nested_boundary[strlen ("boundary=")]);
+              if (pp->nested_boundary == NULL)
+                {
+                  /* out of memory */
+                  pp->state = PP_Error;
+                  return MHD_NO;
+                }
+              /* free old content type, we will need that field
+                 for the content type of the nested elements */
+              free (pp->content_type);
+              pp->content_type = NULL;
+              pp->nlen = strlen (pp->nested_boundary);
+              pp->state = PP_Nested_Init;
+              state_changed = 1;
+              break;
+            }
+          pp->state = PP_ProcessValueToBoundary;
+          pp->value_offset = 0;
+          state_changed = 1;
+          break;
+        case PP_ProcessValueToBoundary:
+          if (MHD_NO == process_value_to_boundary (pp,
+                                                   &ioff,
+                                                   pp->boundary,
+                                                   pp->blen,
+                                                   PP_PerformCleanup,
+                                                   PP_Done))
+            {
+              if (pp->state == PP_Error)
+                return MHD_NO;
+              break;
+            }
+          break;
+        case PP_PerformCleanup:
+          /* clean up state of one multipart form-data element! */
+          pp->have = NE_none;
+          free_unmarked (pp);
+          if (pp->nested_boundary != NULL)
+            {
+              free (pp->nested_boundary);
+              pp->nested_boundary = NULL;
+            }
+          pp->state = PP_ProcessEntryHeaders;
+          state_changed = 1;
+          break;
+        case PP_Nested_Init:
+          if (pp->nested_boundary == NULL)
+            {
+              pp->state = PP_Error;
+              return MHD_NO;
+            }
+          if (MHD_NO == find_boundary (pp,
+                                       pp->nested_boundary,
+                                       pp->nlen,
+                                       &ioff,
+                                       PP_Nested_PerformMarking,
+                                       PP_NextBoundary /* or PP_Error? */ ))
+            {
+              if (pp->state == PP_Error)
+                return MHD_NO;
+              goto END;
+            }
+          break;
+        case PP_Nested_PerformMarking:
+          /* remember what headers were given
+             globally */
+          pp->have = NE_none;
+          if (pp->content_name != NULL)
+            pp->have |= NE_content_name;
+          if (pp->content_type != NULL)
+            pp->have |= NE_content_type;
+          if (pp->content_filename != NULL)
+            pp->have |= NE_content_filename;
+          if (pp->content_transfer_encoding != NULL)
+            pp->have |= NE_content_transfer_encoding;
+          pp->state = PP_Nested_ProcessEntryHeaders;
+          state_changed = 1;
+          break;
+        case PP_Nested_ProcessEntryHeaders:
+          pp->value_offset = 0;
+          if (MHD_NO ==
+              process_multipart_headers (pp, &ioff,
+                                         PP_Nested_ProcessValueToBoundary))
+            {
+              if (pp->state == PP_Error)
+                return MHD_NO;
+              else
+                goto END;
+            }
+          state_changed = 1;
+          break;
+        case PP_Nested_ProcessValueToBoundary:
+          if (MHD_NO == process_value_to_boundary (pp,
+                                                   &ioff,
+                                                   pp->nested_boundary,
+                                                   pp->nlen,
+                                                   PP_Nested_PerformCleanup,
+                                                   PP_NextBoundary))
+            {
+              if (pp->state == PP_Error)
+                return MHD_NO;
+              break;
+            }
+          break;
+        case PP_Nested_PerformCleanup:
+          free_unmarked (pp);
+          pp->state = PP_Nested_ProcessEntryHeaders;
+          state_changed = 1;
+          break;
+        default:
+          mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);          /* 
should never happen! */
+        }
+    AGAIN:
+      if (ioff > 0)
+        {
+          memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
+          pp->buffer_pos -= ioff;
+          ioff = 0;
+          state_changed = 1;
+        }
+    }
+END:
+  if (ioff != 0)
+    {
+      memmove (buf, &buf[ioff], pp->buffer_pos - ioff);
+      pp->buffer_pos -= ioff;
+    }
+  if (poff < post_data_len)
+    {
+      pp->state = PP_Error;
+      return MHD_NO;            /* serious error */
+    }
+  return MHD_YES;
+}
+
+
+/**
+ * Parse and process POST data.
+ * Call this function when POST data is available
+ * (usually during an MHD_AccessHandlerCallback)
+ * with the upload_data and upload_data_size.
+ * Whenever possible, this will then cause calls
+ * to the MHD_IncrementalKeyValueIterator.
+ *
+ * @param pp the post processor
+ * @param post_data post_data_len bytes of POST data
+ * @param post_data_len length of post_data
+ * @return MHD_YES on success, MHD_NO on error
+ *         (out-of-memory, iterator aborted, parse error)
+ */
+int
+MHD_post_process (struct MHD_PostProcessor *pp,
+                  const char *post_data, size_t post_data_len)
+{
+  if (post_data_len == 0)
+    return MHD_YES;
+  if (pp == NULL)
+    return MHD_NO;
+  if (0 == strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding,
+                         strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED)))
+    return post_process_urlencoded (pp, post_data, post_data_len);
+  if (0 ==
+      strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding,
+                   strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)))
+    return post_process_multipart (pp, post_data, post_data_len);
+  /* this should never be reached */
+  return MHD_NO;
+}
+
+
+/**
+ * Release PostProcessor resources.
+ *
+ * @param pp post processor context to destroy
+ * @return MHD_YES if processing completed nicely,
+ *         MHD_NO if there were spurious characters / formatting
+ *                problems; it is common to ignore the return
+ *                value of this function
+ */
+int
+MHD_destroy_post_processor (struct MHD_PostProcessor *pp)
+{
+  int ret;
+
+  if (NULL == pp)
+    return MHD_YES;
+  if (PP_ProcessValue == pp->state)
+  {
+    /* key without terminated value left at the end of the
+       buffer; fake receiving a termination character to
+       ensure it is also processed */
+    post_process_urlencoded (pp, "\n", 1);
+  }
+  /* These internal strings need cleaning up since
+     the post-processing may have been interrupted
+     at any stage */
+  if ((pp->xbuf_pos > 0) || 
+      ( (pp->state != PP_Done) &&
+       (pp->state != PP_ExpectNewLine)))
+    ret = MHD_NO;
+  else
+    ret = MHD_YES;
+  pp->have = NE_none;
+  free_unmarked (pp);
+  if (pp->nested_boundary != NULL)
+    free (pp->nested_boundary);
+  free (pp);
+  return ret;
+}
+
+/* end of postprocessor.c */

Deleted: libmicrohttpd/src/microhttpd/response.c
===================================================================
--- libmicrohttpd/src/daemon/response.c 2013-05-05 12:01:06 UTC (rev 27023)
+++ libmicrohttpd/src/microhttpd/response.c     2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,456 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
-
-     This library is free software; you can redistribute it and/or
-     modify it under the terms of the GNU Lesser General Public
-     License as published by the Free Software Foundation; either
-     version 2.1 of the License, or (at your option) any later version.
-
-     This library 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
-     Lesser General Public License for more details.
-
-     You should have received a copy of the GNU Lesser General Public
-     License along with this library; if not, write to the Free Software
-     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
-*/
-
-/**
- * @file response.c
- * @brief  Methods for managing response objects
- * @author Daniel Pittman
- * @author Christian Grothoff
- */
-
-#include "internal.h"
-#include "response.h"
-
-
-/**
- * Add a header or footer line to the response.
- *
- * @param response response to add a header to
- * @param kind header or footer
- * @param header the header to add
- * @param content value to add
- * @return MHD_NO on error (i.e. invalid header or content format).
- */
-static int
-add_response_entry (struct MHD_Response *response,
-                   enum MHD_ValueKind kind,
-                   const char *header, 
-                   const char *content)
-{
-  struct MHD_HTTP_Header *hdr;
-
-  if ( (NULL == response) ||
-       (NULL == header) ||
-       (NULL == content) ||
-       (0 == strlen (header)) ||
-       (0 == strlen (content)) ||
-       (NULL != strchr (header, '\t')) ||
-       (NULL != strchr (header, '\r')) ||
-       (NULL != strchr (header, '\n')) ||
-       (NULL != strchr (content, '\t')) ||
-       (NULL != strchr (content, '\r')) || 
-       (NULL != strchr (content, '\n')) )
-    return MHD_NO;
-  if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header))))
-    return MHD_NO;
-  if (NULL == (hdr->header = strdup (header)))
-    {
-      free (hdr);
-      return MHD_NO;
-    }
-  if (NULL == (hdr->value = strdup (content)))
-    {
-      free (hdr->header);
-      free (hdr);
-      return MHD_NO;
-    }
-  hdr->kind = kind;
-  hdr->next = response->first_header;
-  response->first_header = hdr;
-  return MHD_YES;
-}
-
-
-/**
- * Add a header line to the response.
- *
- * @param response response to add a header to
- * @param header the header to add
- * @param content value to add
- * @return MHD_NO on error (i.e. invalid header or content format).
- */
-int
-MHD_add_response_header (struct MHD_Response *response,
-                         const char *header, const char *content)
-{
-  return add_response_entry (response,
-                            MHD_HEADER_KIND,
-                            header,
-                            content);
-}
-
-
-/**
- * Add a footer line to the response.
- *
- * @param response response to remove a header from
- * @param footer the footer to delete
- * @param content value to delete
- * @return MHD_NO on error (i.e. invalid footer or content format).
- */
-int
-MHD_add_response_footer (struct MHD_Response *response,
-                         const char *footer, const char *content)
-{
-  return add_response_entry (response,
-                            MHD_FOOTER_KIND,
-                            footer,
-                            content);
-}
-
-
-/**
- * Delete a header line from the response.
- *
- * @param response response to remove a header from
- * @param header the header to delete
- * @param content value to delete
- * @return MHD_NO on error (no such header known)
- */
-int
-MHD_del_response_header (struct MHD_Response *response,
-                         const char *header, const char *content)
-{
-  struct MHD_HTTP_Header *pos;
-  struct MHD_HTTP_Header *prev;
-
-  if ( (NULL == header) || (NULL == content) )
-    return MHD_NO;
-  prev = NULL;
-  pos = response->first_header;
-  while (pos != NULL)
-    {
-      if ((0 == strcmp (header, pos->header)) &&
-          (0 == strcmp (content, pos->value)))
-        {
-          free (pos->header);
-          free (pos->value);
-          if (NULL == prev)
-            response->first_header = pos->next;
-          else
-            prev->next = pos->next;
-          free (pos);
-          return MHD_YES;
-        }
-      prev = pos;
-      pos = pos->next;
-    }
-  return MHD_NO;
-}
-
-
-/**
- * Get all of the headers added to a response.
- *
- * @param iterator callback to call on each header;
- *        maybe NULL (then just count headers)
- * @param iterator_cls extra argument to iterator
- * @return number of entries iterated over
- */
-int
-MHD_get_response_headers (struct MHD_Response *response,
-                          MHD_KeyValueIterator iterator, void *iterator_cls)
-{
-  struct MHD_HTTP_Header *pos;
-  int numHeaders = 0;
-
-  for (pos = response->first_header; NULL != pos; pos = pos->next)
-    {
-      numHeaders++;
-      if ((NULL != iterator) &&
-          (MHD_YES != iterator (iterator_cls,
-                                pos->kind, pos->header, pos->value)))
-        break;
-    }
-  return numHeaders;
-}
-
-
-/**
- * Get a particular header from the response.
- *
- * @param key which header to get
- * @return NULL if header does not exist
- */
-const char *
-MHD_get_response_header (struct MHD_Response *response, const char *key)
-{
-  struct MHD_HTTP_Header *pos;
-
-  if (NULL == key)
-    return NULL;
-  for (pos = response->first_header; NULL != pos; pos = pos->next)
-    if (0 == strcmp (key, pos->header))
-      return pos->value;
-  return NULL;
-}
-
-
-/**
- * Create a response object.  The response object can be extended with
- * header information and then be used any number of times.
- *
- * @param size size of the data portion of the response, MHD_SIZE_UNKNOWN for 
unknown
- * @param block_size preferred block size for querying crc (advisory only,
- *                   MHD may still call crc using smaller chunks); this
- *                   is essentially the buffer size used for IO, clients
- *                   should pick a value that is appropriate for IO and
- *                   memory performance requirements
- * @param crc callback to use to obtain response data
- * @param crc_cls extra argument to crc
- * @param crfc callback to call to free crc_cls resources
- * @return NULL on error (i.e. invalid arguments, out of memory)
- */
-struct MHD_Response *
-MHD_create_response_from_callback (uint64_t size,
-                                   size_t block_size,
-                                   MHD_ContentReaderCallback crc,
-                                   void *crc_cls,
-                                   MHD_ContentReaderFreeCallback crfc)
-{
-  struct MHD_Response *response;
-
-  if ((NULL == crc) || (0 == block_size))
-    return NULL;
-  if (NULL == (response = malloc (sizeof (struct MHD_Response) + block_size)))
-    return NULL;
-  memset (response, 0, sizeof (struct MHD_Response));
-  response->fd = -1;
-  response->data = (void *) &response[1];
-  response->data_buffer_size = block_size;
-  if (0 != pthread_mutex_init (&response->mutex, NULL))
-    {
-      free (response);
-      return NULL;
-    }
-  response->crc = crc;
-  response->crfc = crfc;
-  response->crc_cls = crc_cls;
-  response->reference_count = 1;
-  response->total_size = size;
-  return response;
-}
-
-
-/**
- * Given a file descriptor, read data from the file
- * to generate the response.
- * 
- * @param cls pointer to the response
- * @param pos offset in the file to access
- * @param buf where to write the data
- * @param max number of bytes to write at most
- * @return number of bytes written
- */
-static ssize_t
-file_reader (void *cls, uint64_t pos, char *buf, size_t max)
-{
-  struct MHD_Response *response = cls;
-  ssize_t n;
-
-  (void) lseek (response->fd, pos + response->fd_off, SEEK_SET);
-  n = read (response->fd, buf, max);
-  if (0 == n) 
-    return MHD_CONTENT_READER_END_OF_STREAM;
-  if (n < 0) 
-    return MHD_CONTENT_READER_END_WITH_ERROR;
-  return n;
-}
-
-
-/**
- * Destroy file reader context.  Closes the file
- * descriptor.
- *
- * @param cls pointer to file descriptor
- */
-static void
-free_callback (void *cls)
-{
-  struct MHD_Response *response = cls;
-
-  (void) close (response->fd);
-  response->fd = -1;
-}
-
-
-/**
- * Create a response object.  The response object can be extended with
- * header information and then be used any number of times.
- *
- * @param size size of the data portion of the response
- * @param fd file descriptor referring to a file on disk with the data
- * @param off offset to start reading from in the file
- * @return NULL on error (i.e. invalid arguments, out of memory)
- */
-struct MHD_Response *MHD_create_response_from_fd_at_offset (size_t size,
-                                                           int fd,
-                                                           off_t offset)
-{
-  struct MHD_Response *response;
-
-  response = MHD_create_response_from_callback (size,
-                                               4 * 1024,
-                                               &file_reader,
-                                               NULL,
-                                               &free_callback);
-  if (NULL == response)
-    return NULL;
-  response->fd = fd;
-  response->fd_off = offset;
-  response->crc_cls = response;
-  return response;
-}
-
-
-/**
- * Create a response object.  The response object can be extended with
- * header information and then be used any number of times.
- *
- * @param size size of the data portion of the response
- * @param fd file descriptor referring to a file on disk with the data
- * @return NULL on error (i.e. invalid arguments, out of memory)
- */
-struct MHD_Response *MHD_create_response_from_fd (size_t size,
-                                                 int fd)
-{
-  return MHD_create_response_from_fd_at_offset (size, fd, 0);
-}
-
-
-/**
- * Create a response object.  The response object can be extended with
- * header information and then be used any number of times.
- *
- * @param size size of the data portion of the response
- * @param data the data itself
- * @param must_free libmicrohttpd should free data when done
- * @param must_copy libmicrohttpd must make a copy of data
- *        right away, the data maybe released anytime after
- *        this call returns
- * @return NULL on error (i.e. invalid arguments, out of memory)
- * @deprecated use MHD_create_response_from_buffer instead
- */
-struct MHD_Response *
-MHD_create_response_from_data (size_t size,
-                               void *data, int must_free, int must_copy)
-{
-  struct MHD_Response *response;
-  void *tmp;
-
-  if ((NULL == data) && (size > 0))
-    return NULL;
-  if (NULL == (response = malloc (sizeof (struct MHD_Response))))
-    return NULL;
-  memset (response, 0, sizeof (struct MHD_Response));
-  response->fd = -1;
-  if (0 != pthread_mutex_init (&response->mutex, NULL))
-    {
-      free (response);
-      return NULL;
-    }
-  if ((must_copy) && (size > 0))
-    {
-      if (NULL == (tmp = malloc (size)))
-        {
-         pthread_mutex_destroy (&response->mutex);
-          free (response);
-          return NULL;
-        }
-      memcpy (tmp, data, size);
-      must_free = MHD_YES;
-      data = tmp;
-    }
-  response->crc = NULL;
-  response->crfc = must_free ? &free : NULL;
-  response->crc_cls = must_free ? data : NULL;
-  response->reference_count = 1;
-  response->total_size = size;
-  response->data = data;
-  response->data_size = size;
-  return response;
-}
-
-
-/**
- * Create a response object.  The response object can be extended with
- * header information and then be used any number of times.
- *
- * @param size size of the data portion of the response
- * @param buffer size bytes containing the response's data portion
- * @param mode flags for buffer management
- * @return NULL on error (i.e. invalid arguments, out of memory)
- */
-struct MHD_Response *
-MHD_create_response_from_buffer (size_t size,
-                                void *buffer,
-                                enum MHD_ResponseMemoryMode mode)
-{
-  return MHD_create_response_from_data (size,
-                                       buffer,
-                                       mode == MHD_RESPMEM_MUST_FREE,
-                                       mode == MHD_RESPMEM_MUST_COPY);
-}
-
-
-/**
- * Destroy a response object and associated resources.  Note that
- * libmicrohttpd may keep some of the resources around if the response
- * is still in the queue for some clients, so the memory may not
- * necessarily be freed immediatley.
- */
-void
-MHD_destroy_response (struct MHD_Response *response)
-{
-  struct MHD_HTTP_Header *pos;
-
-  if (NULL == response)
-    return;
-  pthread_mutex_lock (&response->mutex);
-  if (0 != --(response->reference_count))
-    {
-      pthread_mutex_unlock (&response->mutex);
-      return;
-    }
-  pthread_mutex_unlock (&response->mutex);
-  pthread_mutex_destroy (&response->mutex);
-  if (response->crfc != NULL)
-    response->crfc (response->crc_cls);
-  while (NULL != response->first_header)
-    {
-      pos = response->first_header;
-      response->first_header = pos->next;
-      free (pos->header);
-      free (pos->value);
-      free (pos);
-    }
-  free (response);
-}
-
-
-void
-MHD_increment_response_rc (struct MHD_Response *response)
-{
-  pthread_mutex_lock (&response->mutex);
-  (response->reference_count)++;
-  pthread_mutex_unlock (&response->mutex);
-}
-
-
-/* end of response.c */

Copied: libmicrohttpd/src/microhttpd/response.c (from rev 27024, 
libmicrohttpd/src/daemon/response.c)
===================================================================
--- libmicrohttpd/src/microhttpd/response.c                             (rev 0)
+++ libmicrohttpd/src/microhttpd/response.c     2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,459 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library 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
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
+*/
+
+/**
+ * @file response.c
+ * @brief  Methods for managing response objects
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ */
+
+#include "internal.h"
+#include "response.h"
+
+
+/**
+ * Add a header or footer line to the response.
+ *
+ * @param response response to add a header to
+ * @param kind header or footer
+ * @param header the header to add
+ * @param content value to add
+ * @return MHD_NO on error (i.e. invalid header or content format).
+ */
+static int
+add_response_entry (struct MHD_Response *response,
+                   enum MHD_ValueKind kind,
+                   const char *header, 
+                   const char *content)
+{
+  struct MHD_HTTP_Header *hdr;
+
+  if ( (NULL == response) ||
+       (NULL == header) ||
+       (NULL == content) ||
+       (0 == strlen (header)) ||
+       (0 == strlen (content)) ||
+       (NULL != strchr (header, '\t')) ||
+       (NULL != strchr (header, '\r')) ||
+       (NULL != strchr (header, '\n')) ||
+       (NULL != strchr (content, '\t')) ||
+       (NULL != strchr (content, '\r')) || 
+       (NULL != strchr (content, '\n')) )
+    return MHD_NO;
+  if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header))))
+    return MHD_NO;
+  if (NULL == (hdr->header = strdup (header)))
+    {
+      free (hdr);
+      return MHD_NO;
+    }
+  if (NULL == (hdr->value = strdup (content)))
+    {
+      free (hdr->header);
+      free (hdr);
+      return MHD_NO;
+    }
+  hdr->kind = kind;
+  hdr->next = response->first_header;
+  response->first_header = hdr;
+  return MHD_YES;
+}
+
+
+/**
+ * Add a header line to the response.
+ *
+ * @param response response to add a header to
+ * @param header the header to add
+ * @param content value to add
+ * @return MHD_NO on error (i.e. invalid header or content format).
+ */
+int
+MHD_add_response_header (struct MHD_Response *response,
+                         const char *header, const char *content)
+{
+  return add_response_entry (response,
+                            MHD_HEADER_KIND,
+                            header,
+                            content);
+}
+
+
+/**
+ * Add a footer line to the response.
+ *
+ * @param response response to remove a header from
+ * @param footer the footer to delete
+ * @param content value to delete
+ * @return MHD_NO on error (i.e. invalid footer or content format).
+ */
+int
+MHD_add_response_footer (struct MHD_Response *response,
+                         const char *footer, const char *content)
+{
+  return add_response_entry (response,
+                            MHD_FOOTER_KIND,
+                            footer,
+                            content);
+}
+
+
+/**
+ * Delete a header line from the response.
+ *
+ * @param response response to remove a header from
+ * @param header the header to delete
+ * @param content value to delete
+ * @return MHD_NO on error (no such header known)
+ */
+int
+MHD_del_response_header (struct MHD_Response *response,
+                         const char *header, const char *content)
+{
+  struct MHD_HTTP_Header *pos;
+  struct MHD_HTTP_Header *prev;
+
+  if ( (NULL == header) || (NULL == content) )
+    return MHD_NO;
+  prev = NULL;
+  pos = response->first_header;
+  while (pos != NULL)
+    {
+      if ((0 == strcmp (header, pos->header)) &&
+          (0 == strcmp (content, pos->value)))
+        {
+          free (pos->header);
+          free (pos->value);
+          if (NULL == prev)
+            response->first_header = pos->next;
+          else
+            prev->next = pos->next;
+          free (pos);
+          return MHD_YES;
+        }
+      prev = pos;
+      pos = pos->next;
+    }
+  return MHD_NO;
+}
+
+
+/**
+ * Get all of the headers added to a response.
+ *
+ * @param response response to query
+ * @param iterator callback to call on each header;
+ *        maybe NULL (then just count headers)
+ * @param iterator_cls extra argument to iterator
+ * @return number of entries iterated over
+ */
+int
+MHD_get_response_headers (struct MHD_Response *response,
+                          MHD_KeyValueIterator iterator, void *iterator_cls)
+{
+  struct MHD_HTTP_Header *pos;
+  int numHeaders = 0;
+
+  for (pos = response->first_header; NULL != pos; pos = pos->next)
+    {
+      numHeaders++;
+      if ((NULL != iterator) &&
+          (MHD_YES != iterator (iterator_cls,
+                                pos->kind, pos->header, pos->value)))
+        break;
+    }
+  return numHeaders;
+}
+
+
+/**
+ * Get a particular header from the response.
+ *
+ * @param response response to query
+ * @param key which header to get
+ * @return NULL if header does not exist
+ */
+const char *
+MHD_get_response_header (struct MHD_Response *response, 
+                        const char *key)
+{
+  struct MHD_HTTP_Header *pos;
+
+  if (NULL == key)
+    return NULL;
+  for (pos = response->first_header; NULL != pos; pos = pos->next)
+    if (0 == strcmp (key, pos->header))
+      return pos->value;
+  return NULL;
+}
+
+
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param size size of the data portion of the response, MHD_SIZE_UNKNOWN for 
unknown
+ * @param block_size preferred block size for querying crc (advisory only,
+ *                   MHD may still call crc using smaller chunks); this
+ *                   is essentially the buffer size used for IO, clients
+ *                   should pick a value that is appropriate for IO and
+ *                   memory performance requirements
+ * @param crc callback to use to obtain response data
+ * @param crc_cls extra argument to crc
+ * @param crfc callback to call to free crc_cls resources
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+struct MHD_Response *
+MHD_create_response_from_callback (uint64_t size,
+                                   size_t block_size,
+                                   MHD_ContentReaderCallback crc,
+                                   void *crc_cls,
+                                   MHD_ContentReaderFreeCallback crfc)
+{
+  struct MHD_Response *response;
+
+  if ((NULL == crc) || (0 == block_size))
+    return NULL;
+  if (NULL == (response = malloc (sizeof (struct MHD_Response) + block_size)))
+    return NULL;
+  memset (response, 0, sizeof (struct MHD_Response));
+  response->fd = -1;
+  response->data = (void *) &response[1];
+  response->data_buffer_size = block_size;
+  if (0 != pthread_mutex_init (&response->mutex, NULL))
+    {
+      free (response);
+      return NULL;
+    }
+  response->crc = crc;
+  response->crfc = crfc;
+  response->crc_cls = crc_cls;
+  response->reference_count = 1;
+  response->total_size = size;
+  return response;
+}
+
+
+/**
+ * Given a file descriptor, read data from the file
+ * to generate the response.
+ * 
+ * @param cls pointer to the response
+ * @param pos offset in the file to access
+ * @param buf where to write the data
+ * @param max number of bytes to write at most
+ * @return number of bytes written
+ */
+static ssize_t
+file_reader (void *cls, uint64_t pos, char *buf, size_t max)
+{
+  struct MHD_Response *response = cls;
+  ssize_t n;
+
+  (void) lseek (response->fd, pos + response->fd_off, SEEK_SET);
+  n = read (response->fd, buf, max);
+  if (0 == n) 
+    return MHD_CONTENT_READER_END_OF_STREAM;
+  if (n < 0) 
+    return MHD_CONTENT_READER_END_WITH_ERROR;
+  return n;
+}
+
+
+/**
+ * Destroy file reader context.  Closes the file
+ * descriptor.
+ *
+ * @param cls pointer to file descriptor
+ */
+static void
+free_callback (void *cls)
+{
+  struct MHD_Response *response = cls;
+
+  (void) close (response->fd);
+  response->fd = -1;
+}
+
+
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param size size of the data portion of the response
+ * @param fd file descriptor referring to a file on disk with the data
+ * @param offset offset to start reading from in the file
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+struct MHD_Response *MHD_create_response_from_fd_at_offset (size_t size,
+                                                           int fd,
+                                                           off_t offset)
+{
+  struct MHD_Response *response;
+
+  response = MHD_create_response_from_callback (size,
+                                               4 * 1024,
+                                               &file_reader,
+                                               NULL,
+                                               &free_callback);
+  if (NULL == response)
+    return NULL;
+  response->fd = fd;
+  response->fd_off = offset;
+  response->crc_cls = response;
+  return response;
+}
+
+
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param size size of the data portion of the response
+ * @param fd file descriptor referring to a file on disk with the data
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+struct MHD_Response *MHD_create_response_from_fd (size_t size,
+                                                 int fd)
+{
+  return MHD_create_response_from_fd_at_offset (size, fd, 0);
+}
+
+
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param size size of the data portion of the response
+ * @param data the data itself
+ * @param must_free libmicrohttpd should free data when done
+ * @param must_copy libmicrohttpd must make a copy of data
+ *        right away, the data maybe released anytime after
+ *        this call returns
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @deprecated use MHD_create_response_from_buffer instead
+ */
+struct MHD_Response *
+MHD_create_response_from_data (size_t size,
+                               void *data, int must_free, int must_copy)
+{
+  struct MHD_Response *response;
+  void *tmp;
+
+  if ((NULL == data) && (size > 0))
+    return NULL;
+  if (NULL == (response = malloc (sizeof (struct MHD_Response))))
+    return NULL;
+  memset (response, 0, sizeof (struct MHD_Response));
+  response->fd = -1;
+  if (0 != pthread_mutex_init (&response->mutex, NULL))
+    {
+      free (response);
+      return NULL;
+    }
+  if ((must_copy) && (size > 0))
+    {
+      if (NULL == (tmp = malloc (size)))
+        {
+         pthread_mutex_destroy (&response->mutex);
+          free (response);
+          return NULL;
+        }
+      memcpy (tmp, data, size);
+      must_free = MHD_YES;
+      data = tmp;
+    }
+  response->crc = NULL;
+  response->crfc = must_free ? &free : NULL;
+  response->crc_cls = must_free ? data : NULL;
+  response->reference_count = 1;
+  response->total_size = size;
+  response->data = data;
+  response->data_size = size;
+  return response;
+}
+
+
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param size size of the data portion of the response
+ * @param buffer size bytes containing the response's data portion
+ * @param mode flags for buffer management
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+struct MHD_Response *
+MHD_create_response_from_buffer (size_t size,
+                                void *buffer,
+                                enum MHD_ResponseMemoryMode mode)
+{
+  return MHD_create_response_from_data (size,
+                                       buffer,
+                                       mode == MHD_RESPMEM_MUST_FREE,
+                                       mode == MHD_RESPMEM_MUST_COPY);
+}
+
+
+/**
+ * Destroy a response object and associated resources.  Note that
+ * libmicrohttpd may keep some of the resources around if the response
+ * is still in the queue for some clients, so the memory may not
+ * necessarily be freed immediatley.
+ */
+void
+MHD_destroy_response (struct MHD_Response *response)
+{
+  struct MHD_HTTP_Header *pos;
+
+  if (NULL == response)
+    return;
+  pthread_mutex_lock (&response->mutex);
+  if (0 != --(response->reference_count))
+    {
+      pthread_mutex_unlock (&response->mutex);
+      return;
+    }
+  pthread_mutex_unlock (&response->mutex);
+  pthread_mutex_destroy (&response->mutex);
+  if (response->crfc != NULL)
+    response->crfc (response->crc_cls);
+  while (NULL != response->first_header)
+    {
+      pos = response->first_header;
+      response->first_header = pos->next;
+      free (pos->header);
+      free (pos->value);
+      free (pos);
+    }
+  free (response);
+}
+
+
+void
+MHD_increment_response_rc (struct MHD_Response *response)
+{
+  pthread_mutex_lock (&response->mutex);
+  (response->reference_count)++;
+  pthread_mutex_unlock (&response->mutex);
+}
+
+
+/* end of response.c */

Deleted: libmicrohttpd/src/microhttpd/test_daemon.c
===================================================================
--- libmicrohttpd/src/daemon/test_daemon.c      2013-05-05 12:01:06 UTC (rev 
27023)
+++ libmicrohttpd/src/microhttpd/test_daemon.c  2013-05-05 18:07:33 UTC (rev 
27025)
@@ -1,168 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2007 Christian Grothoff
-
-     libmicrohttpd 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 2, or (at your
-     option) any later version.
-
-     libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file daemon_test.c
- * @brief  Testcase for libmicrohttpd starts and stops
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "platform.h"
-#include "microhttpd.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-
-static int
-testStartError ()
-{
-  struct MHD_Daemon *d;
-
-  d = MHD_start_daemon (MHD_USE_DEBUG, 0, NULL, NULL, NULL, NULL);
-  if (d != NULL)
-    return 1;
-  return 0;
-}
-
-static int
-apc_nothing (void *cls, const struct sockaddr *addr, socklen_t addrlen)
-{
-  return MHD_NO;
-}
-
-static int
-apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
-{
-  return MHD_YES;
-}
-
-static int
-ahc_nothing (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 **unused)
-{
-  return MHD_NO;
-}
-
-static int
-testStartStop ()
-{
-  struct MHD_Daemon *d;
-
-  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
-                        1080,
-                        &apc_nothing,
-                        NULL, &ahc_nothing, NULL, MHD_OPTION_END);
-  if (d == NULL)
-    return 2;
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-static int
-testExternalRun ()
-{
-  struct MHD_Daemon *d;
-  fd_set rs;
-  int maxfd;
-  int i;
-
-  d = MHD_start_daemon (MHD_USE_DEBUG,
-                        1081,
-                        &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
-
-  if (d == NULL)
-    return 4;
-  i = 0;
-  while (i < 15)
-    {
-      maxfd = 0;
-      FD_ZERO (&rs);
-      if (MHD_YES != MHD_get_fdset (d, &rs, &rs, &rs, &maxfd))
-       {
-         MHD_stop_daemon (d);
-         return 256;
-       }
-      if (MHD_run (d) == MHD_NO)
-        {
-          MHD_stop_daemon (d);
-          return 8;
-        }
-      i++;
-    }
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-static int
-testThread ()
-{
-  struct MHD_Daemon *d;
-  d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY,
-                        1082,
-                        &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
-
-  if (d == NULL)
-    return 16;
-  if (MHD_run (d) != MHD_NO)
-    return 32;
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-static int
-testMultithread ()
-{
-  struct MHD_Daemon *d;
-  d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION,
-                        1083,
-                        &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
-
-  if (d == NULL)
-    return 64;
-  if (MHD_run (d) != MHD_NO)
-    return 128;
-  MHD_stop_daemon (d);
-  return 0;
-}
-
-int
-main (int argc, char *const *argv)
-{
-  int errorCount = 0;
-  errorCount += testStartError ();
-  errorCount += testStartStop ();
-  errorCount += testExternalRun ();
-  errorCount += testThread ();
-  errorCount += testMultithread ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  return errorCount != 0;       /* 0 == pass */
-}

Copied: libmicrohttpd/src/microhttpd/test_daemon.c (from rev 27024, 
libmicrohttpd/src/daemon/test_daemon.c)
===================================================================
--- libmicrohttpd/src/microhttpd/test_daemon.c                          (rev 0)
+++ libmicrohttpd/src/microhttpd/test_daemon.c  2013-05-05 18:07:33 UTC (rev 
27025)
@@ -0,0 +1,168 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007 Christian Grothoff
+
+     libmicrohttpd 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 2, or (at your
+     option) any later version.
+
+     libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_daemon.c
+ * @brief  Testcase for libmicrohttpd starts and stops
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "platform.h"
+#include "microhttpd.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+
+static int
+testStartError ()
+{
+  struct MHD_Daemon *d;
+
+  d = MHD_start_daemon (MHD_USE_DEBUG, 0, NULL, NULL, NULL, NULL);
+  if (d != NULL)
+    return 1;
+  return 0;
+}
+
+static int
+apc_nothing (void *cls, const struct sockaddr *addr, socklen_t addrlen)
+{
+  return MHD_NO;
+}
+
+static int
+apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen)
+{
+  return MHD_YES;
+}
+
+static int
+ahc_nothing (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 **unused)
+{
+  return MHD_NO;
+}
+
+static int
+testStartStop ()
+{
+  struct MHD_Daemon *d;
+
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+                        1080,
+                        &apc_nothing,
+                        NULL, &ahc_nothing, NULL, MHD_OPTION_END);
+  if (d == NULL)
+    return 2;
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+static int
+testExternalRun ()
+{
+  struct MHD_Daemon *d;
+  fd_set rs;
+  int maxfd;
+  int i;
+
+  d = MHD_start_daemon (MHD_USE_DEBUG,
+                        1081,
+                        &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
+
+  if (d == NULL)
+    return 4;
+  i = 0;
+  while (i < 15)
+    {
+      maxfd = 0;
+      FD_ZERO (&rs);
+      if (MHD_YES != MHD_get_fdset (d, &rs, &rs, &rs, &maxfd))
+       {
+         MHD_stop_daemon (d);
+         return 256;
+       }
+      if (MHD_run (d) == MHD_NO)
+        {
+          MHD_stop_daemon (d);
+          return 8;
+        }
+      i++;
+    }
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+static int
+testThread ()
+{
+  struct MHD_Daemon *d;
+  d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY,
+                        1082,
+                        &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
+
+  if (d == NULL)
+    return 16;
+  if (MHD_run (d) != MHD_NO)
+    return 32;
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+static int
+testMultithread ()
+{
+  struct MHD_Daemon *d;
+  d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION,
+                        1083,
+                        &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END);
+
+  if (d == NULL)
+    return 64;
+  if (MHD_run (d) != MHD_NO)
+    return 128;
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+int
+main (int argc, char *const *argv)
+{
+  int errorCount = 0;
+  errorCount += testStartError ();
+  errorCount += testStartStop ();
+  errorCount += testExternalRun ();
+  errorCount += testThread ();
+  errorCount += testMultithread ();
+  if (errorCount != 0)
+    fprintf (stderr, "Error (code: %u)\n", errorCount);
+  return errorCount != 0;       /* 0 == pass */
+}

Deleted: libmicrohttpd/src/microhttpd/test_postprocessor.c
===================================================================
--- libmicrohttpd/src/daemon/test_postprocessor.c       2013-05-05 12:01:06 UTC 
(rev 27023)
+++ libmicrohttpd/src/microhttpd/test_postprocessor.c   2013-05-05 18:07:33 UTC 
(rev 27025)
@@ -1,271 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2007 Christian Grothoff
-
-     libmicrohttpd 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 2, or (at your
-     option) any later version.
-
-     libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file postprocessor_test.c
- * @brief  Testcase for postprocessor
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "microhttpd.h"
-#include "internal.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-/**
- * Array of values that the value checker "wants".
- * Each series of checks should be terminated by
- * five NULL-entries.
- */
-const char *want[] = {
-#define URL_DATA "abc=def&x=5"
-#define URL_START 0
-  "abc", NULL, NULL, NULL, "def",
-  "x", NULL, NULL, NULL, "5",
-#define URL_END (URL_START + 10)
-  NULL, NULL, NULL, NULL, NULL,
-#define FORM_DATA "--AaB03x\r\ncontent-disposition: form-data; 
name=\"field1\"\r\n\r\nJoe Blow\r\n--AaB03x\r\ncontent-disposition: form-data; 
name=\"pics\"; filename=\"file1.txt\"\r\nContent-Type: 
text/plain\r\nContent-Transfer-Encoding: 
binary\r\n\r\nfiledata\r\n--AaB03x--\r\n"
-#define FORM_START (URL_END + 5)
-  "field1", NULL, NULL, NULL, "Joe Blow",
-  "pics", "file1.txt", "text/plain", "binary", "filedata",
-#define FORM_END (FORM_START + 10)
-  NULL, NULL, NULL, NULL, NULL,
-#define FORM_NESTED_DATA "--AaB03x\r\ncontent-disposition: form-data; 
name=\"field1\"\r\n\r\nJane Blow\r\n--AaB03x\r\ncontent-disposition: form-data; 
name=\"pics\"\r\nContent-type: multipart/mixed, 
boundary=BbC04y\r\n\r\n--BbC04y\r\nContent-disposition: attachment; 
filename=\"file1.txt\"\r\nContent-Type: 
text/plain\r\n\r\nfiledata1\r\n--BbC04y\r\nContent-disposition: attachment; 
filename=\"file2.gif\"\r\nContent-type: image/gif\r\nContent-Transfer-Encoding: 
binary\r\n\r\nfiledata2\r\n--BbC04y--\r\n--AaB03x--"
-#define FORM_NESTED_START (FORM_END + 5)
-  "field1", NULL, NULL, NULL, "Jane Blow",
-  "pics", "file1.txt", "text/plain", NULL, "filedata1",
-  "pics", "file2.gif", "image/gif", "binary", "filedata2",
-#define FORM_NESTED_END (FORM_NESTED_START + 15)
-  NULL, NULL, NULL, NULL, NULL,
-#define URL_EMPTY_VALUE_DATA "key1=value1&key2=&key3="
-#define URL_EMPTY_VALUE_START (FORM_NESTED_END + 5)
-  "key1", NULL, NULL, NULL, "value1",
-  "key2", NULL, NULL, NULL, "",
-  "key3", NULL, NULL, NULL, "",
-#define URL_EMPTY_VALUE_END (URL_EMPTY_VALUE_START + 15)
-  NULL, NULL, NULL, NULL, NULL
-};
-
-static int
-mismatch (const char *a, const char *b)
-{
-  if (a == b)
-    return 0;
-  if ((a == NULL) || (b == NULL))
-    return 1;
-  return 0 != strcmp (a, b);
-}
-
-static int
-value_checker (void *cls,
-               enum MHD_ValueKind kind,
-               const char *key,
-               const char *filename,
-               const char *content_type,
-               const char *transfer_encoding,
-               const char *data, uint64_t off, size_t size)
-{
-  int *want_off = cls;
-  int idx = *want_off;
-
-#if 0
-  fprintf (stderr,
-           "VC: `%s' `%s' `%s' `%s' `%.*s'\n",
-           key, filename, content_type, transfer_encoding, size, data);
-#endif
-  if ( (0 != off) && (0 == size) )
-    return MHD_YES; 
-  if ((idx < 0) ||
-      (want[idx] == NULL) ||
-      (0 != strcmp (key, want[idx])) ||
-      (mismatch (filename, want[idx + 1])) ||
-      (mismatch (content_type, want[idx + 2])) ||
-      (mismatch (transfer_encoding, want[idx + 3])) ||
-      (0 != memcmp (data, &want[idx + 4][off], size)))
-    {
-      *want_off = -1;
-      return MHD_NO;
-    }
-  if (off + size == strlen (want[idx + 4]))
-    *want_off = idx + 5;
-  return MHD_YES;
-
-}
-
-
-static int
-test_urlencoding ()
-{
-  struct MHD_Connection connection;
-  struct MHD_HTTP_Header header;
-  struct MHD_PostProcessor *pp;
-  unsigned int want_off = URL_START;
-  int i;
-  int delta;
-  size_t size;
-
-  memset (&connection, 0, sizeof (struct MHD_Connection));
-  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
-  connection.headers_received = &header;
-  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
-  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
-  header.kind = MHD_HEADER_KIND;
-  pp = MHD_create_post_processor (&connection,
-                                  1024, &value_checker, &want_off);
-  i = 0;
-  size = strlen (URL_DATA);
-  while (i < size)
-    {
-      delta = 1 + RANDOM () % (size - i);
-      MHD_post_process (pp, &URL_DATA[i], delta);
-      i += delta;
-    }
-  MHD_destroy_post_processor (pp);
-  if (want_off != URL_END)
-    return 1;
-  return 0;
-}
-
-
-static int
-test_multipart ()
-{
-  struct MHD_Connection connection;
-  struct MHD_HTTP_Header header;
-  struct MHD_PostProcessor *pp;
-  unsigned int want_off = FORM_START;
-  int i;
-  int delta;
-  size_t size;
-
-  memset (&connection, 0, sizeof (struct MHD_Connection));
-  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
-  connection.headers_received = &header;
-  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
-  header.value =
-    MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
-  header.kind = MHD_HEADER_KIND;
-  pp = MHD_create_post_processor (&connection,
-                                  1024, &value_checker, &want_off);
-  i = 0;
-  size = strlen (FORM_DATA);
-  while (i < size)
-    {
-      delta = 1 + RANDOM () % (size - i);
-      MHD_post_process (pp, &FORM_DATA[i], delta);
-      i += delta;
-    }
-  MHD_destroy_post_processor (pp);
-  if (want_off != FORM_END)
-    return 2;
-  return 0;
-}
-
-
-static int
-test_nested_multipart ()
-{
-  struct MHD_Connection connection;
-  struct MHD_HTTP_Header header;
-  struct MHD_PostProcessor *pp;
-  unsigned int want_off = FORM_NESTED_START;
-  int i;
-  int delta;
-  size_t size;
-
-  memset (&connection, 0, sizeof (struct MHD_Connection));
-  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
-  connection.headers_received = &header;
-  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
-  header.value =
-    MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
-  header.kind = MHD_HEADER_KIND;
-  pp = MHD_create_post_processor (&connection,
-                                  1024, &value_checker, &want_off);
-  i = 0;
-  size = strlen (FORM_NESTED_DATA);
-  while (i < size)
-    {
-      delta = 1 + RANDOM () % (size - i);
-      MHD_post_process (pp, &FORM_NESTED_DATA[i], delta);
-      i += delta;
-    }
-  MHD_destroy_post_processor (pp);
-  if (want_off != FORM_NESTED_END)
-    return 4;
-  return 0;
-}
-
-
-static int
-test_empty_value ()
-{
-  struct MHD_Connection connection;
-  struct MHD_HTTP_Header header;
-  struct MHD_PostProcessor *pp;
-  unsigned int want_off = URL_EMPTY_VALUE_START;
-  int i;
-  int delta;
-  size_t size;
-
-  memset (&connection, 0, sizeof (struct MHD_Connection));
-  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
-  connection.headers_received = &header;
-  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
-  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
-  header.kind = MHD_HEADER_KIND;
-  pp = MHD_create_post_processor (&connection,
-                                  1024, &value_checker, &want_off);
-  i = 0;
-  size = strlen (URL_EMPTY_VALUE_DATA);
-  while (i < size)
-    {
-      delta = 1 + RANDOM () % (size - i);
-      MHD_post_process (pp, &URL_EMPTY_VALUE_DATA[i], delta);
-      i += delta;
-    }
-  MHD_destroy_post_processor (pp);
-  if (want_off != URL_EMPTY_VALUE_END)
-    return 8;
-  return 0;
-}
-
-
-
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-
-  errorCount += test_urlencoding ();
-  errorCount += test_multipart ();
-  errorCount += test_nested_multipart ();
-  errorCount += test_empty_value ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  return errorCount != 0;       /* 0 == pass */
-}

Copied: libmicrohttpd/src/microhttpd/test_postprocessor.c (from rev 27024, 
libmicrohttpd/src/daemon/test_postprocessor.c)
===================================================================
--- libmicrohttpd/src/microhttpd/test_postprocessor.c                           
(rev 0)
+++ libmicrohttpd/src/microhttpd/test_postprocessor.c   2013-05-05 18:07:33 UTC 
(rev 27025)
@@ -0,0 +1,271 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007 Christian Grothoff
+
+     libmicrohttpd 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 2, or (at your
+     option) any later version.
+
+     libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_postprocessor.c
+ * @brief  Testcase for postprocessor
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include "internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+/**
+ * Array of values that the value checker "wants".
+ * Each series of checks should be terminated by
+ * five NULL-entries.
+ */
+const char *want[] = {
+#define URL_DATA "abc=def&x=5"
+#define URL_START 0
+  "abc", NULL, NULL, NULL, "def",
+  "x", NULL, NULL, NULL, "5",
+#define URL_END (URL_START + 10)
+  NULL, NULL, NULL, NULL, NULL,
+#define FORM_DATA "--AaB03x\r\ncontent-disposition: form-data; 
name=\"field1\"\r\n\r\nJoe Blow\r\n--AaB03x\r\ncontent-disposition: form-data; 
name=\"pics\"; filename=\"file1.txt\"\r\nContent-Type: 
text/plain\r\nContent-Transfer-Encoding: 
binary\r\n\r\nfiledata\r\n--AaB03x--\r\n"
+#define FORM_START (URL_END + 5)
+  "field1", NULL, NULL, NULL, "Joe Blow",
+  "pics", "file1.txt", "text/plain", "binary", "filedata",
+#define FORM_END (FORM_START + 10)
+  NULL, NULL, NULL, NULL, NULL,
+#define FORM_NESTED_DATA "--AaB03x\r\ncontent-disposition: form-data; 
name=\"field1\"\r\n\r\nJane Blow\r\n--AaB03x\r\ncontent-disposition: form-data; 
name=\"pics\"\r\nContent-type: multipart/mixed, 
boundary=BbC04y\r\n\r\n--BbC04y\r\nContent-disposition: attachment; 
filename=\"file1.txt\"\r\nContent-Type: 
text/plain\r\n\r\nfiledata1\r\n--BbC04y\r\nContent-disposition: attachment; 
filename=\"file2.gif\"\r\nContent-type: image/gif\r\nContent-Transfer-Encoding: 
binary\r\n\r\nfiledata2\r\n--BbC04y--\r\n--AaB03x--"
+#define FORM_NESTED_START (FORM_END + 5)
+  "field1", NULL, NULL, NULL, "Jane Blow",
+  "pics", "file1.txt", "text/plain", NULL, "filedata1",
+  "pics", "file2.gif", "image/gif", "binary", "filedata2",
+#define FORM_NESTED_END (FORM_NESTED_START + 15)
+  NULL, NULL, NULL, NULL, NULL,
+#define URL_EMPTY_VALUE_DATA "key1=value1&key2=&key3="
+#define URL_EMPTY_VALUE_START (FORM_NESTED_END + 5)
+  "key1", NULL, NULL, NULL, "value1",
+  "key2", NULL, NULL, NULL, "",
+  "key3", NULL, NULL, NULL, "",
+#define URL_EMPTY_VALUE_END (URL_EMPTY_VALUE_START + 15)
+  NULL, NULL, NULL, NULL, NULL
+};
+
+static int
+mismatch (const char *a, const char *b)
+{
+  if (a == b)
+    return 0;
+  if ((a == NULL) || (b == NULL))
+    return 1;
+  return 0 != strcmp (a, b);
+}
+
+static int
+value_checker (void *cls,
+               enum MHD_ValueKind kind,
+               const char *key,
+               const char *filename,
+               const char *content_type,
+               const char *transfer_encoding,
+               const char *data, uint64_t off, size_t size)
+{
+  int *want_off = cls;
+  int idx = *want_off;
+
+#if 0
+  fprintf (stderr,
+           "VC: `%s' `%s' `%s' `%s' `%.*s'\n",
+           key, filename, content_type, transfer_encoding, size, data);
+#endif
+  if ( (0 != off) && (0 == size) )
+    return MHD_YES; 
+  if ((idx < 0) ||
+      (want[idx] == NULL) ||
+      (0 != strcmp (key, want[idx])) ||
+      (mismatch (filename, want[idx + 1])) ||
+      (mismatch (content_type, want[idx + 2])) ||
+      (mismatch (transfer_encoding, want[idx + 3])) ||
+      (0 != memcmp (data, &want[idx + 4][off], size)))
+    {
+      *want_off = -1;
+      return MHD_NO;
+    }
+  if (off + size == strlen (want[idx + 4]))
+    *want_off = idx + 5;
+  return MHD_YES;
+
+}
+
+
+static int
+test_urlencoding ()
+{
+  struct MHD_Connection connection;
+  struct MHD_HTTP_Header header;
+  struct MHD_PostProcessor *pp;
+  unsigned int want_off = URL_START;
+  int i;
+  int delta;
+  size_t size;
+
+  memset (&connection, 0, sizeof (struct MHD_Connection));
+  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
+  connection.headers_received = &header;
+  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
+  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
+  header.kind = MHD_HEADER_KIND;
+  pp = MHD_create_post_processor (&connection,
+                                  1024, &value_checker, &want_off);
+  i = 0;
+  size = strlen (URL_DATA);
+  while (i < size)
+    {
+      delta = 1 + RANDOM () % (size - i);
+      MHD_post_process (pp, &URL_DATA[i], delta);
+      i += delta;
+    }
+  MHD_destroy_post_processor (pp);
+  if (want_off != URL_END)
+    return 1;
+  return 0;
+}
+
+
+static int
+test_multipart ()
+{
+  struct MHD_Connection connection;
+  struct MHD_HTTP_Header header;
+  struct MHD_PostProcessor *pp;
+  unsigned int want_off = FORM_START;
+  int i;
+  int delta;
+  size_t size;
+
+  memset (&connection, 0, sizeof (struct MHD_Connection));
+  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
+  connection.headers_received = &header;
+  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
+  header.value =
+    MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
+  header.kind = MHD_HEADER_KIND;
+  pp = MHD_create_post_processor (&connection,
+                                  1024, &value_checker, &want_off);
+  i = 0;
+  size = strlen (FORM_DATA);
+  while (i < size)
+    {
+      delta = 1 + RANDOM () % (size - i);
+      MHD_post_process (pp, &FORM_DATA[i], delta);
+      i += delta;
+    }
+  MHD_destroy_post_processor (pp);
+  if (want_off != FORM_END)
+    return 2;
+  return 0;
+}
+
+
+static int
+test_nested_multipart ()
+{
+  struct MHD_Connection connection;
+  struct MHD_HTTP_Header header;
+  struct MHD_PostProcessor *pp;
+  unsigned int want_off = FORM_NESTED_START;
+  int i;
+  int delta;
+  size_t size;
+
+  memset (&connection, 0, sizeof (struct MHD_Connection));
+  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
+  connection.headers_received = &header;
+  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
+  header.value =
+    MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
+  header.kind = MHD_HEADER_KIND;
+  pp = MHD_create_post_processor (&connection,
+                                  1024, &value_checker, &want_off);
+  i = 0;
+  size = strlen (FORM_NESTED_DATA);
+  while (i < size)
+    {
+      delta = 1 + RANDOM () % (size - i);
+      MHD_post_process (pp, &FORM_NESTED_DATA[i], delta);
+      i += delta;
+    }
+  MHD_destroy_post_processor (pp);
+  if (want_off != FORM_NESTED_END)
+    return 4;
+  return 0;
+}
+
+
+static int
+test_empty_value ()
+{
+  struct MHD_Connection connection;
+  struct MHD_HTTP_Header header;
+  struct MHD_PostProcessor *pp;
+  unsigned int want_off = URL_EMPTY_VALUE_START;
+  int i;
+  int delta;
+  size_t size;
+
+  memset (&connection, 0, sizeof (struct MHD_Connection));
+  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
+  connection.headers_received = &header;
+  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
+  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
+  header.kind = MHD_HEADER_KIND;
+  pp = MHD_create_post_processor (&connection,
+                                  1024, &value_checker, &want_off);
+  i = 0;
+  size = strlen (URL_EMPTY_VALUE_DATA);
+  while (i < size)
+    {
+      delta = 1 + RANDOM () % (size - i);
+      MHD_post_process (pp, &URL_EMPTY_VALUE_DATA[i], delta);
+      i += delta;
+    }
+  MHD_destroy_post_processor (pp);
+  if (want_off != URL_EMPTY_VALUE_END)
+    return 8;
+  return 0;
+}
+
+
+
+
+int
+main (int argc, char *const *argv)
+{
+  unsigned int errorCount = 0;
+
+  errorCount += test_urlencoding ();
+  errorCount += test_multipart ();
+  errorCount += test_nested_multipart ();
+  errorCount += test_empty_value ();
+  if (errorCount != 0)
+    fprintf (stderr, "Error (code: %u)\n", errorCount);
+  return errorCount != 0;       /* 0 == pass */
+}

Deleted: libmicrohttpd/src/microhttpd/test_postprocessor_large.c
===================================================================
--- libmicrohttpd/src/daemon/test_postprocessor_large.c 2013-05-05 12:01:06 UTC 
(rev 27023)
+++ libmicrohttpd/src/microhttpd/test_postprocessor_large.c     2013-05-05 
18:07:33 UTC (rev 27025)
@@ -1,105 +0,0 @@
-/*
-     This file is part of libmicrohttpd
-     (C) 2008 Christian Grothoff
-
-     libmicrohttpd 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 2, or (at your
-     option) any later version.
-
-     libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file postprocessor_large_test.c
- * @brief  Testcase with very large input for postprocessor
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "microhttpd.h"
-#include "internal.h"
-
-#ifndef WINDOWS
-#include <unistd.h>
-#endif
-
-static int
-value_checker (void *cls,
-               enum MHD_ValueKind kind,
-               const char *key,
-               const char *filename,
-               const char *content_type,
-               const char *transfer_encoding,
-               const char *data, uint64_t off, size_t size)
-{
-  unsigned int *pos = cls;
-#if 0
-  fprintf (stderr,
-           "VC: %llu %u `%s' `%s' `%s' `%s' `%.*s'\n",
-           off, size,
-           key, filename, content_type, transfer_encoding, size, data);
-#endif
-  if (size == 0)
-    return MHD_YES;
-  *pos += size;
-  return MHD_YES;
-
-}
-
-
-static int
-test_simple_large ()
-{
-  struct MHD_Connection connection;
-  struct MHD_HTTP_Header header;
-  struct MHD_PostProcessor *pp;
-  int i;
-  int delta;
-  size_t size;
-  char data[102400];
-  unsigned int pos;
-
-  pos = 0;
-  memset (data, 'A', sizeof (data));
-  memcpy (data, "key=", 4);
-  data[sizeof (data) - 1] = '\0';
-  memset (&connection, 0, sizeof (struct MHD_Connection));
-  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
-  connection.headers_received = &header;
-  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
-  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
-  header.kind = MHD_HEADER_KIND;
-  pp = MHD_create_post_processor (&connection, 1024, &value_checker, &pos);
-  i = 0;
-  size = strlen (data);
-  while (i < size)
-    {
-      delta = 1 + RANDOM () % (size - i);
-      MHD_post_process (pp, &data[i], delta);
-      i += delta;
-    }
-  MHD_destroy_post_processor (pp);
-  if (pos != sizeof (data) - 5) /* minus 0-termination and 'key=' */
-    return 1;
-  return 0;
-}
-
-int
-main (int argc, char *const *argv)
-{
-  unsigned int errorCount = 0;
-
-  errorCount += test_simple_large ();
-  if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
-  return errorCount != 0;       /* 0 == pass */
-}

Copied: libmicrohttpd/src/microhttpd/test_postprocessor_large.c (from rev 
27024, libmicrohttpd/src/daemon/test_postprocessor_large.c)
===================================================================
--- libmicrohttpd/src/microhttpd/test_postprocessor_large.c                     
        (rev 0)
+++ libmicrohttpd/src/microhttpd/test_postprocessor_large.c     2013-05-05 
18:07:33 UTC (rev 27025)
@@ -0,0 +1,105 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2008 Christian Grothoff
+
+     libmicrohttpd 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 2, or (at your
+     option) any later version.
+
+     libmicrohttpd 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 libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file test_postprocessor_large.c
+ * @brief  Testcase with very large input for postprocessor
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include "internal.h"
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+static int
+value_checker (void *cls,
+               enum MHD_ValueKind kind,
+               const char *key,
+               const char *filename,
+               const char *content_type,
+               const char *transfer_encoding,
+               const char *data, uint64_t off, size_t size)
+{
+  unsigned int *pos = cls;
+#if 0
+  fprintf (stderr,
+           "VC: %llu %u `%s' `%s' `%s' `%s' `%.*s'\n",
+           off, size,
+           key, filename, content_type, transfer_encoding, size, data);
+#endif
+  if (size == 0)
+    return MHD_YES;
+  *pos += size;
+  return MHD_YES;
+
+}
+
+
+static int
+test_simple_large ()
+{
+  struct MHD_Connection connection;
+  struct MHD_HTTP_Header header;
+  struct MHD_PostProcessor *pp;
+  int i;
+  int delta;
+  size_t size;
+  char data[102400];
+  unsigned int pos;
+
+  pos = 0;
+  memset (data, 'A', sizeof (data));
+  memcpy (data, "key=", 4);
+  data[sizeof (data) - 1] = '\0';
+  memset (&connection, 0, sizeof (struct MHD_Connection));
+  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
+  connection.headers_received = &header;
+  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
+  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
+  header.kind = MHD_HEADER_KIND;
+  pp = MHD_create_post_processor (&connection, 1024, &value_checker, &pos);
+  i = 0;
+  size = strlen (data);
+  while (i < size)
+    {
+      delta = 1 + RANDOM () % (size - i);
+      MHD_post_process (pp, &data[i], delta);
+      i += delta;
+    }
+  MHD_destroy_post_processor (pp);
+  if (pos != sizeof (data) - 5) /* minus 0-termination and 'key=' */
+    return 1;
+  return 0;
+}
+
+int
+main (int argc, char *const *argv)
+{
+  unsigned int errorCount = 0;
+
+  errorCount += test_simple_large ();
+  if (errorCount != 0)
+    fprintf (stderr, "Error (code: %u)\n", errorCount);
+  return errorCount != 0;       /* 0 == pass */
+}




reply via email to

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