Blame src/examples/post_example.c

Packit 875988
/*
Packit 875988
     This file is part of libmicrohttpd
Packit 875988
     Copyright (C) 2011 Christian Grothoff (and other contributing authors)
Packit 875988
Packit 875988
     This library is free software; you can redistribute it and/or
Packit 875988
     modify it under the terms of the GNU Lesser General Public
Packit 875988
     License as published by the Free Software Foundation; either
Packit 875988
     version 2.1 of the License, or (at your option) any later version.
Packit 875988
Packit 875988
     This library is distributed in the hope that it will be useful,
Packit 875988
     but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
     Lesser General Public License for more details.
Packit 875988
Packit 875988
     You should have received a copy of the GNU Lesser General Public
Packit 875988
     License along with this library; if not, write to the Free Software
Packit 875988
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 875988
*/
Packit 875988
/**
Packit 875988
 * @file post_example.c
Packit 875988
 * @brief example for processing POST requests using libmicrohttpd
Packit 875988
 * @author Christian Grothoff
Packit 875988
 */
Packit 875988
Packit 875988
#include <stdlib.h>
Packit 875988
#include <string.h>
Packit 875988
#include <stdio.h>
Packit 875988
#include <errno.h>
Packit 875988
#include <time.h>
Packit 875988
#include <microhttpd.h>
Packit 875988
Packit 875988
/**
Packit 875988
 * Invalid method page.
Packit 875988
 */
Packit 875988
#define METHOD_ERROR "<html><head><title>Illegal request</title></head><body>Go away.</body></html>"
Packit 875988
Packit 875988
/**
Packit 875988
 * Invalid URL page.
Packit 875988
 */
Packit 875988
#define NOT_FOUND_ERROR "<html><head><title>Not found</title></head><body>Go away.</body></html>"
Packit 875988
Packit 875988
/**
Packit 875988
 * Front page. (/)
Packit 875988
 */
Packit 875988
#define MAIN_PAGE "<html><head><title>Welcome</title></head><body><form action=\"/2\" method=\"post\">What is your name? <input type=\"text\" name=\"v1\" value=\"%s\" /><input type=\"submit\" value=\"Next\" /></body></html>"
Packit 875988
Packit 875988
/**
Packit 875988
 * Second page. (/2)
Packit 875988
 */
Packit 875988
#define SECOND_PAGE "<html><head><title>Tell me more</title></head><body>previous <form action=\"/S\" method=\"post\">%s, what is your job? <input type=\"text\" name=\"v2\" value=\"%s\" /><input type=\"submit\" value=\"Next\" /></body></html>"
Packit 875988
Packit 875988
/**
Packit 875988
 * Second page (/S)
Packit 875988
 */
Packit 875988
#define SUBMIT_PAGE "<html><head><title>Ready to submit?</title></head><body><form action=\"/F\" method=\"post\">previous  <input type=\"hidden\" name=\"DONE\" value=\"yes\" /><input type=\"submit\" value=\"Submit\" /></body></html>"
Packit 875988
Packit 875988
/**
Packit 875988
 * Last page.
Packit 875988
 */
Packit 875988
#define LAST_PAGE "<html><head><title>Thank you</title></head><body>Thank you.</body></html>"
Packit 875988
Packit 875988
/**
Packit 875988
 * Name of our cookie.
Packit 875988
 */
Packit 875988
#define COOKIE_NAME "session"
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * State we keep for each user/session/browser.
Packit 875988
 */
Packit 875988
struct Session
Packit 875988
{
Packit 875988
  /**
Packit 875988
   * We keep all sessions in a linked list.
Packit 875988
   */
Packit 875988
  struct Session *next;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Unique ID for this session.
Packit 875988
   */
Packit 875988
  char sid[33];
Packit 875988
Packit 875988
  /**
Packit 875988
   * Reference counter giving the number of connections
Packit 875988
   * currently using this session.
Packit 875988
   */
Packit 875988
  unsigned int rc;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Time when this session was last active.
Packit 875988
   */
Packit 875988
  time_t start;
Packit 875988
Packit 875988
  /**
Packit 875988
   * String submitted via form.
Packit 875988
   */
Packit 875988
  char value_1[64];
Packit 875988
Packit 875988
  /**
Packit 875988
   * Another value submitted via form.
Packit 875988
   */
Packit 875988
  char value_2[64];
Packit 875988
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Data kept per request.
Packit 875988
 */
Packit 875988
struct Request
Packit 875988
{
Packit 875988
Packit 875988
  /**
Packit 875988
   * Associated session.
Packit 875988
   */
Packit 875988
  struct Session *session;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Post processor handling form data (IF this is
Packit 875988
   * a POST request).
Packit 875988
   */
Packit 875988
  struct MHD_PostProcessor *pp;
Packit 875988
Packit 875988
  /**
Packit 875988
   * URL to serve in response to this POST (if this request
Packit 875988
   * was a 'POST')
Packit 875988
   */
Packit 875988
  const char *post_url;
Packit 875988
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Linked list of all active sessions.  Yes, O(n) but a
Packit 875988
 * hash table would be overkill for a simple example...
Packit 875988
 */
Packit 875988
static struct Session *sessions;
Packit 875988
Packit 875988
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Return the session handle for this connection, or
Packit 875988
 * create one if this is a new user.
Packit 875988
 */
Packit 875988
static struct Session *
Packit 875988
get_session (struct MHD_Connection *connection)
Packit 875988
{
Packit 875988
  struct Session *ret;
Packit 875988
  const char *cookie;
Packit 875988
Packit 875988
  cookie = MHD_lookup_connection_value (connection,
Packit 875988
					MHD_COOKIE_KIND,
Packit 875988
					COOKIE_NAME);
Packit 875988
  if (cookie != NULL)
Packit 875988
    {
Packit 875988
      /* find existing session */
Packit 875988
      ret = sessions;
Packit 875988
      while (NULL != ret)
Packit 875988
	{
Packit 875988
	  if (0 == strcmp (cookie, ret->sid))
Packit 875988
	    break;
Packit 875988
	  ret = ret->next;
Packit 875988
	}
Packit 875988
      if (NULL != ret)
Packit 875988
	{
Packit 875988
	  ret->rc++;
Packit 875988
	  return ret;
Packit 875988
	}
Packit 875988
    }
Packit 875988
  /* create fresh session */
Packit 875988
  ret = calloc (1, sizeof (struct Session));
Packit 875988
  if (NULL == ret)
Packit 875988
    {
Packit 875988
      fprintf (stderr, "calloc error: %s\n", strerror (errno));
Packit 875988
      return NULL;
Packit 875988
    }
Packit 875988
  /* not a super-secure way to generate a random session ID,
Packit 875988
     but should do for a simple example... */
Packit 875988
  snprintf (ret->sid,
Packit 875988
	    sizeof (ret->sid),
Packit 875988
	    "%X%X%X%X",
Packit 875988
	    (unsigned int) rand (),
Packit 875988
	    (unsigned int) rand (),
Packit 875988
	    (unsigned int) rand (),
Packit 875988
	    (unsigned int) rand ());
Packit 875988
  ret->rc++;
Packit 875988
  ret->start = time (NULL);
Packit 875988
  ret->next = sessions;
Packit 875988
  sessions = ret;
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Type of handler that generates a reply.
Packit 875988
 *
Packit 875988
 * @param cls content for the page (handler-specific)
Packit 875988
 * @param mime mime type to use
Packit 875988
 * @param session session information
Packit 875988
 * @param connection connection to process
Packit 875988
 * @param MHD_YES on success, MHD_NO on failure
Packit 875988
 */
Packit 875988
typedef int (*PageHandler)(const void *cls,
Packit 875988
			   const char *mime,
Packit 875988
			   struct Session *session,
Packit 875988
			   struct MHD_Connection *connection);
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Entry we generate for each page served.
Packit 875988
 */
Packit 875988
struct Page
Packit 875988
{
Packit 875988
  /**
Packit 875988
   * Acceptable URL for this page.
Packit 875988
   */
Packit 875988
  const char *url;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Mime type to set for the page.
Packit 875988
   */
Packit 875988
  const char *mime;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Handler to call to generate response.
Packit 875988
   */
Packit 875988
  PageHandler handler;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Extra argument to handler.
Packit 875988
   */
Packit 875988
  const void *handler_cls;
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Add header to response to set a session cookie.
Packit 875988
 *
Packit 875988
 * @param session session to use
Packit 875988
 * @param response response to modify
Packit 875988
 */
Packit 875988
static void
Packit 875988
add_session_cookie (struct Session *session,
Packit 875988
		    struct MHD_Response *response)
Packit 875988
{
Packit 875988
  char cstr[256];
Packit 875988
  snprintf (cstr,
Packit 875988
	    sizeof (cstr),
Packit 875988
	    "%s=%s",
Packit 875988
	    COOKIE_NAME,
Packit 875988
	    session->sid);
Packit 875988
  if (MHD_NO ==
Packit 875988
      MHD_add_response_header (response,
Packit 875988
			       MHD_HTTP_HEADER_SET_COOKIE,
Packit 875988
			       cstr))
Packit 875988
    {
Packit 875988
      fprintf (stderr,
Packit 875988
	       "Failed to set session cookie header!\n");
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Handler that returns a simple static HTTP page that
Packit 875988
 * is passed in via 'cls'.
Packit 875988
 *
Packit 875988
 * @param cls a 'const char *' with the HTML webpage to return
Packit 875988
 * @param mime mime type to use
Packit 875988
 * @param session session handle
Packit 875988
 * @param connection connection to use
Packit 875988
 */
Packit 875988
static int
Packit 875988
serve_simple_form (const void *cls,
Packit 875988
		   const char *mime,
Packit 875988
		   struct Session *session,
Packit 875988
		   struct MHD_Connection *connection)
Packit 875988
{
Packit 875988
  int ret;
Packit 875988
  const char *form = cls;
Packit 875988
  struct MHD_Response *response;
Packit 875988
Packit 875988
  /* return static form */
Packit 875988
  response = MHD_create_response_from_buffer (strlen (form),
Packit 875988
					      (void *) form,
Packit 875988
					      MHD_RESPMEM_PERSISTENT);
Packit 875988
  if (NULL == response)
Packit 875988
    return MHD_NO;
Packit 875988
  add_session_cookie (session, response);
Packit 875988
  MHD_add_response_header (response,
Packit 875988
			   MHD_HTTP_HEADER_CONTENT_ENCODING,
Packit 875988
			   mime);
Packit 875988
  ret = MHD_queue_response (connection,
Packit 875988
			    MHD_HTTP_OK,
Packit 875988
			    response);
Packit 875988
  MHD_destroy_response (response);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Handler that adds the 'v1' value to the given HTML code.
Packit 875988
 *
Packit 875988
 * @param cls unused
Packit 875988
 * @param mime mime type to use
Packit 875988
 * @param session session handle
Packit 875988
 * @param connection connection to use
Packit 875988
 */
Packit 875988
static int
Packit 875988
fill_v1_form (const void *cls,
Packit 875988
	      const char *mime,
Packit 875988
	      struct Session *session,
Packit 875988
	      struct MHD_Connection *connection)
Packit 875988
{
Packit 875988
  int ret;
Packit 875988
  size_t slen;
Packit 875988
  char *reply;
Packit 875988
  struct MHD_Response *response;
Packit 875988
  (void)cls; /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  slen = strlen (MAIN_PAGE) + strlen (session->value_1);
Packit 875988
  reply = malloc (slen + 1);
Packit 875988
  if (NULL == reply)
Packit 875988
    return MHD_NO;
Packit 875988
  snprintf (reply,
Packit 875988
	    slen + 1,
Packit 875988
	    MAIN_PAGE,
Packit 875988
	    session->value_1);
Packit 875988
  /* return static form */
Packit 875988
  response = MHD_create_response_from_buffer (slen,
Packit 875988
					      (void *) reply,
Packit 875988
					      MHD_RESPMEM_MUST_FREE);
Packit 875988
  if (NULL == response)
Packit 875988
  {
Packit 875988
    free (reply);
Packit 875988
    return MHD_NO;
Packit 875988
  }
Packit 875988
  add_session_cookie (session, response);
Packit 875988
  MHD_add_response_header (response,
Packit 875988
			   MHD_HTTP_HEADER_CONTENT_ENCODING,
Packit 875988
			   mime);
Packit 875988
  ret = MHD_queue_response (connection,
Packit 875988
			    MHD_HTTP_OK,
Packit 875988
			    response);
Packit 875988
  MHD_destroy_response (response);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Handler that adds the 'v1' and 'v2' values to the given HTML code.
Packit 875988
 *
Packit 875988
 * @param cls unused
Packit 875988
 * @param mime mime type to use
Packit 875988
 * @param session session handle
Packit 875988
 * @param connection connection to use
Packit 875988
 */
Packit 875988
static int
Packit 875988
fill_v1_v2_form (const void *cls,
Packit 875988
		 const char *mime,
Packit 875988
		 struct Session *session,
Packit 875988
		 struct MHD_Connection *connection)
Packit 875988
{
Packit 875988
  int ret;
Packit 875988
  char *reply;
Packit 875988
  struct MHD_Response *response;
Packit 875988
  size_t slen;
Packit 875988
  (void)cls; /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  slen = strlen (SECOND_PAGE) + strlen (session->value_1) + strlen (session->value_2);
Packit 875988
  reply = malloc (slen + 1);
Packit 875988
  if (NULL == reply)
Packit 875988
    return MHD_NO;
Packit 875988
  snprintf (reply,
Packit 875988
	    slen + 1,
Packit 875988
	    SECOND_PAGE,
Packit 875988
	    session->value_1,
Packit 875988
            session->value_2);
Packit 875988
  /* return static form */
Packit 875988
  response = MHD_create_response_from_buffer (slen,
Packit 875988
					      (void *) reply,
Packit 875988
					      MHD_RESPMEM_MUST_FREE);
Packit 875988
  if (NULL == response)
Packit 875988
  {
Packit 875988
    free (reply);
Packit 875988
    return MHD_NO;
Packit 875988
  }
Packit 875988
  add_session_cookie (session, response);
Packit 875988
  MHD_add_response_header (response,
Packit 875988
			   MHD_HTTP_HEADER_CONTENT_ENCODING,
Packit 875988
			   mime);
Packit 875988
  ret = MHD_queue_response (connection,
Packit 875988
			    MHD_HTTP_OK,
Packit 875988
			    response);
Packit 875988
  MHD_destroy_response (response);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Handler used to generate a 404 reply.
Packit 875988
 *
Packit 875988
 * @param cls a 'const char *' with the HTML webpage to return
Packit 875988
 * @param mime mime type to use
Packit 875988
 * @param session session handle
Packit 875988
 * @param connection connection to use
Packit 875988
 */
Packit 875988
static int
Packit 875988
not_found_page (const void *cls,
Packit 875988
		const char *mime,
Packit 875988
		struct Session *session,
Packit 875988
		struct MHD_Connection *connection)
Packit 875988
{
Packit 875988
  int ret;
Packit 875988
  struct MHD_Response *response;
Packit 875988
  (void)cls;     /* Unused. Silent compiler warning. */
Packit 875988
  (void)session; /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  /* unsupported HTTP method */
Packit 875988
  response = MHD_create_response_from_buffer (strlen (NOT_FOUND_ERROR),
Packit 875988
					      (void *) NOT_FOUND_ERROR,
Packit 875988
					      MHD_RESPMEM_PERSISTENT);
Packit 875988
  if (NULL == response)
Packit 875988
    return MHD_NO;
Packit 875988
  ret = MHD_queue_response (connection,
Packit 875988
			    MHD_HTTP_NOT_FOUND,
Packit 875988
			    response);
Packit 875988
  MHD_add_response_header (response,
Packit 875988
			   MHD_HTTP_HEADER_CONTENT_ENCODING,
Packit 875988
			   mime);
Packit 875988
  MHD_destroy_response (response);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * List of all pages served by this HTTP server.
Packit 875988
 */
Packit 875988
static struct Page pages[] =
Packit 875988
  {
Packit 875988
    { "/", "text/html",  &fill_v1_form, NULL },
Packit 875988
    { "/2", "text/html", &fill_v1_v2_form, NULL },
Packit 875988
    { "/S", "text/html", &serve_simple_form, SUBMIT_PAGE },
Packit 875988
    { "/F", "text/html", &serve_simple_form, LAST_PAGE },
Packit 875988
    { NULL, NULL, &not_found_page, NULL } /* 404 */
Packit 875988
  };
Packit 875988
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Iterator over key-value pairs where the value
Packit 875988
 * maybe made available in increments and/or may
Packit 875988
 * not be zero-terminated.  Used for processing
Packit 875988
 * POST data.
Packit 875988
 *
Packit 875988
 * @param cls user-specified closure
Packit 875988
 * @param kind type of the value
Packit 875988
 * @param key 0-terminated key for the value
Packit 875988
 * @param filename name of the uploaded file, NULL if not known
Packit 875988
 * @param content_type mime-type of the data, NULL if not known
Packit 875988
 * @param transfer_encoding encoding of the data, NULL if not known
Packit 875988
 * @param data pointer to size bytes of data at the
Packit 875988
 *              specified offset
Packit 875988
 * @param off offset of data in the overall value
Packit 875988
 * @param size number of bytes in data available
Packit 875988
 * @return MHD_YES to continue iterating,
Packit 875988
 *         MHD_NO to abort the iteration
Packit 875988
 */
Packit 875988
static int
Packit 875988
post_iterator (void *cls,
Packit 875988
	       enum MHD_ValueKind kind,
Packit 875988
	       const char *key,
Packit 875988
	       const char *filename,
Packit 875988
	       const char *content_type,
Packit 875988
	       const char *transfer_encoding,
Packit 875988
	       const char *data, uint64_t off, size_t size)
Packit 875988
{
Packit 875988
  struct Request *request = cls;
Packit 875988
  struct Session *session = request->session;
Packit 875988
  (void)kind;              /* Unused. Silent compiler warning. */
Packit 875988
  (void)filename;          /* Unused. Silent compiler warning. */
Packit 875988
  (void)content_type;      /* Unused. Silent compiler warning. */
Packit 875988
  (void)transfer_encoding; /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  if (0 == strcmp ("DONE", key))
Packit 875988
    {
Packit 875988
      fprintf (stdout,
Packit 875988
	       "Session `%s' submitted `%s', `%s'\n",
Packit 875988
	       session->sid,
Packit 875988
	       session->value_1,
Packit 875988
	       session->value_2);
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
  if (0 == strcmp ("v1", key))
Packit 875988
    {
Packit 875988
      if (size + off >= sizeof(session->value_1))
Packit 875988
	size = sizeof (session->value_1) - off - 1;
Packit 875988
      memcpy (&session->value_1[off],
Packit 875988
	      data,
Packit 875988
	      size);
Packit 875988
      session->value_1[size+off] = '\0';
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
  if (0 == strcmp ("v2", key))
Packit 875988
    {
Packit 875988
      if (size + off >= sizeof(session->value_2))
Packit 875988
	size = sizeof (session->value_2) - off - 1;
Packit 875988
      memcpy (&session->value_2[off],
Packit 875988
	      data,
Packit 875988
	      size);
Packit 875988
      session->value_2[size+off] = '\0';
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
  fprintf (stderr,
Packit 875988
           "Unsupported form value `%s'\n",
Packit 875988
           key);
Packit 875988
  return MHD_YES;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Main MHD callback for handling requests.
Packit 875988
 *
Packit 875988
 * @param cls argument given together with the function
Packit 875988
 *        pointer when the handler was registered with MHD
Packit 875988
 * @param connection handle identifying the incoming connection
Packit 875988
 * @param url the requested url
Packit 875988
 * @param method the HTTP method used ("GET", "PUT", etc.)
Packit 875988
 * @param version the HTTP version string (i.e. "HTTP/1.1")
Packit 875988
 * @param upload_data the data being uploaded (excluding HEADERS,
Packit 875988
 *        for a POST that fits into memory and that is encoded
Packit 875988
 *        with a supported encoding, the POST data will NOT be
Packit 875988
 *        given in upload_data and is instead available as
Packit 875988
 *        part of MHD_get_connection_values; very large POST
Packit 875988
 *        data *will* be made available incrementally in
Packit 875988
 *        upload_data)
Packit 875988
 * @param upload_data_size set initially to the size of the
Packit 875988
 *        upload_data provided; the method must update this
Packit 875988
 *        value to the number of bytes NOT processed;
Packit 875988
 * @param ptr pointer that the callback can set to some
Packit 875988
 *        address and that will be preserved by MHD for future
Packit 875988
 *        calls for this request; since the access handler may
Packit 875988
 *        be called many times (i.e., for a PUT/POST operation
Packit 875988
 *        with plenty of upload data) this allows the application
Packit 875988
 *        to easily associate some request-specific state.
Packit 875988
 *        If necessary, this state can be cleaned up in the
Packit 875988
 *        global "MHD_RequestCompleted" callback (which
Packit 875988
 *        can be set with the MHD_OPTION_NOTIFY_COMPLETED).
Packit 875988
 *        Initially, <tt>*con_cls</tt> will be NULL.
Packit 875988
 * @return MHS_YES if the connection was handled successfully,
Packit 875988
 *         MHS_NO if the socket must be closed due to a serios
Packit 875988
 *         error while handling the request
Packit 875988
 */
Packit 875988
static int
Packit 875988
create_response (void *cls,
Packit 875988
		 struct MHD_Connection *connection,
Packit 875988
		 const char *url,
Packit 875988
		 const char *method,
Packit 875988
		 const char *version,
Packit 875988
		 const char *upload_data,
Packit 875988
		 size_t *upload_data_size,
Packit 875988
		 void **ptr)
Packit 875988
{
Packit 875988
  struct MHD_Response *response;
Packit 875988
  struct Request *request;
Packit 875988
  struct Session *session;
Packit 875988
  int ret;
Packit 875988
  unsigned int i;
Packit 875988
  (void)cls;               /* Unused. Silent compiler warning. */
Packit 875988
  (void)version;           /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  request = *ptr;
Packit 875988
  if (NULL == request)
Packit 875988
    {
Packit 875988
      request = calloc (1, sizeof (struct Request));
Packit 875988
      if (NULL == request)
Packit 875988
	{
Packit 875988
	  fprintf (stderr, "calloc error: %s\n", strerror (errno));
Packit 875988
	  return MHD_NO;
Packit 875988
	}
Packit 875988
      *ptr = request;
Packit 875988
      if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
Packit 875988
	{
Packit 875988
	  request->pp = MHD_create_post_processor (connection, 1024,
Packit 875988
						   &post_iterator, request);
Packit 875988
	  if (NULL == request->pp)
Packit 875988
	    {
Packit 875988
	      fprintf (stderr, "Failed to setup post processor for `%s'\n",
Packit 875988
		       url);
Packit 875988
	      return MHD_NO; /* internal error */
Packit 875988
	    }
Packit 875988
	}
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
  if (NULL == request->session)
Packit 875988
    {
Packit 875988
      request->session = get_session (connection);
Packit 875988
      if (NULL == request->session)
Packit 875988
	{
Packit 875988
	  fprintf (stderr, "Failed to setup session for `%s'\n",
Packit 875988
		   url);
Packit 875988
	  return MHD_NO; /* internal error */
Packit 875988
	}
Packit 875988
    }
Packit 875988
  session = request->session;
Packit 875988
  session->start = time (NULL);
Packit 875988
  if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
Packit 875988
    {
Packit 875988
      /* evaluate POST data */
Packit 875988
      MHD_post_process (request->pp,
Packit 875988
			upload_data,
Packit 875988
			*upload_data_size);
Packit 875988
      if (0 != *upload_data_size)
Packit 875988
	{
Packit 875988
	  *upload_data_size = 0;
Packit 875988
	  return MHD_YES;
Packit 875988
	}
Packit 875988
      /* done with POST data, serve response */
Packit 875988
      MHD_destroy_post_processor (request->pp);
Packit 875988
      request->pp = NULL;
Packit 875988
      method = MHD_HTTP_METHOD_GET; /* fake 'GET' */
Packit 875988
      if (NULL != request->post_url)
Packit 875988
	url = request->post_url;
Packit 875988
    }
Packit 875988
Packit 875988
  if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
Packit 875988
       (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
Packit 875988
    {
Packit 875988
      /* find out which page to serve */
Packit 875988
      i=0;
Packit 875988
      while ( (pages[i].url != NULL) &&
Packit 875988
	      (0 != strcmp (pages[i].url, url)) )
Packit 875988
	i++;
Packit 875988
      ret = pages[i].handler (pages[i].handler_cls,
Packit 875988
			      pages[i].mime,
Packit 875988
			      session, connection);
Packit 875988
      if (ret != MHD_YES)
Packit 875988
	fprintf (stderr, "Failed to create page for `%s'\n",
Packit 875988
		 url);
Packit 875988
      return ret;
Packit 875988
    }
Packit 875988
  /* unsupported HTTP method */
Packit 875988
  response = MHD_create_response_from_buffer (strlen (METHOD_ERROR),
Packit 875988
					      (void *) METHOD_ERROR,
Packit 875988
					      MHD_RESPMEM_PERSISTENT);
Packit 875988
  ret = MHD_queue_response (connection,
Packit 875988
			    MHD_HTTP_NOT_ACCEPTABLE,
Packit 875988
			    response);
Packit 875988
  MHD_destroy_response (response);
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Callback called upon completion of a request.
Packit 875988
 * Decrements session reference counter.
Packit 875988
 *
Packit 875988
 * @param cls not used
Packit 875988
 * @param connection connection that completed
Packit 875988
 * @param con_cls session handle
Packit 875988
 * @param toe status code
Packit 875988
 */
Packit 875988
static void
Packit 875988
request_completed_callback (void *cls,
Packit 875988
			    struct MHD_Connection *connection,
Packit 875988
			    void **con_cls,
Packit 875988
			    enum MHD_RequestTerminationCode toe)
Packit 875988
{
Packit 875988
  struct Request *request = *con_cls;
Packit 875988
  (void)cls;         /* Unused. Silent compiler warning. */
Packit 875988
  (void)connection;  /* Unused. Silent compiler warning. */
Packit 875988
  (void)toe;         /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  if (NULL == request)
Packit 875988
    return;
Packit 875988
  if (NULL != request->session)
Packit 875988
    request->session->rc--;
Packit 875988
  if (NULL != request->pp)
Packit 875988
    MHD_destroy_post_processor (request->pp);
Packit 875988
  free (request);
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Clean up handles of sessions that have been idle for
Packit 875988
 * too long.
Packit 875988
 */
Packit 875988
static void
Packit 875988
expire_sessions ()
Packit 875988
{
Packit 875988
  struct Session *pos;
Packit 875988
  struct Session *prev;
Packit 875988
  struct Session *next;
Packit 875988
  time_t now;
Packit 875988
Packit 875988
  now = time (NULL);
Packit 875988
  prev = NULL;
Packit 875988
  pos = sessions;
Packit 875988
  while (NULL != pos)
Packit 875988
    {
Packit 875988
      next = pos->next;
Packit 875988
      if (now - pos->start > 60 * 60)
Packit 875988
	{
Packit 875988
	  /* expire sessions after 1h */
Packit 875988
	  if (NULL == prev)
Packit 875988
	    sessions = pos->next;
Packit 875988
	  else
Packit 875988
	    prev->next = next;
Packit 875988
	  free (pos);
Packit 875988
	}
Packit 875988
      else
Packit 875988
        prev = pos;
Packit 875988
      pos = next;
Packit 875988
    }
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Call with the port number as the only argument.
Packit 875988
 * Never terminates (other than by signals, such as CTRL-C).
Packit 875988
 */
Packit 875988
int
Packit 875988
main (int argc, char *const *argv)
Packit 875988
{
Packit 875988
  struct MHD_Daemon *d;
Packit 875988
  struct timeval tv;
Packit 875988
  struct timeval *tvp;
Packit 875988
  fd_set rs;
Packit 875988
  fd_set ws;
Packit 875988
  fd_set es;
Packit 875988
  MHD_socket max;
Packit 875988
  MHD_UNSIGNED_LONG_LONG mhd_timeout;
Packit 875988
Packit 875988
  if (argc != 2)
Packit 875988
    {
Packit 875988
      printf ("%s PORT\n", argv[0]);
Packit 875988
      return 1;
Packit 875988
    }
Packit 875988
  /* initialize PRNG */
Packit 875988
  srand ((unsigned int) time (NULL));
Packit 875988
  d = MHD_start_daemon (MHD_USE_ERROR_LOG,
Packit 875988
                        atoi (argv[1]),
Packit 875988
                        NULL, NULL,
Packit 875988
			&create_response, NULL,
Packit 875988
			MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 15,
Packit 875988
			MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL,
Packit 875988
			MHD_OPTION_END);
Packit 875988
  if (NULL == d)
Packit 875988
    return 1;
Packit 875988
  while (1)
Packit 875988
    {
Packit 875988
      expire_sessions ();
Packit 875988
      max = 0;
Packit 875988
      FD_ZERO (&rs);
Packit 875988
      FD_ZERO (&ws);
Packit 875988
      FD_ZERO (&es);
Packit 875988
      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
Packit 875988
	break; /* fatal internal error */
Packit 875988
      if (MHD_get_timeout (d, &mhd_timeout) == MHD_YES)
Packit 875988
	{
Packit 875988
	  tv.tv_sec = mhd_timeout / 1000;
Packit 875988
	  tv.tv_usec = (mhd_timeout - (tv.tv_sec * 1000)) * 1000;
Packit 875988
	  tvp = &tv;
Packit 875988
	}
Packit 875988
      else
Packit 875988
	tvp = NULL;
Packit 875988
      if (-1 == select (max + 1, &rs, &ws, &es, tvp))
Packit 875988
        {
Packit 875988
          if (EINTR != errno)
Packit 875988
            abort ();
Packit 875988
        }
Packit 875988
      MHD_run (d);
Packit 875988
    }
Packit 875988
  MHD_stop_daemon (d);
Packit 875988
  return 0;
Packit 875988
}