Blame doc/examples/sessions.c

Packit 875988
/* Feel free to use this example code in any way
Packit 875988
   you see fit (Public Domain) */
Packit 875988
Packit 875988
/* needed for asprintf */
Packit 875988
#define _GNU_SOURCE
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
#if defined _WIN32 && !defined(__MINGW64_VERSION_MAJOR)
Packit 875988
static int
Packit 875988
asprintf (char **resultp, const char *format, ...)
Packit 875988
{
Packit 875988
  va_list argptr;
Packit 875988
  char *result = NULL;
Packit 875988
  int len = 0;
Packit 875988
Packit 875988
  if (format == NULL)
Packit 875988
    return -1;
Packit 875988
Packit 875988
  va_start (argptr, format);
Packit 875988
Packit 875988
  len = _vscprintf ((char *) format, argptr);
Packit 875988
  if (len >= 0)
Packit 875988
  {
Packit 875988
    len += 1;
Packit 875988
    result = (char *) malloc (sizeof (char *) * len);
Packit 875988
    if (result != NULL)
Packit 875988
    {
Packit 875988
      int len2 = _vscprintf ((char *) format, argptr);
Packit 875988
      if (len2 != len - 1 || len2 <= 0)
Packit 875988
      {
Packit 875988
        free (result);
Packit 875988
        result = NULL;
Packit 875988
        len = -1;
Packit 875988
      }
Packit 875988
      else
Packit 875988
      {
Packit 875988
        len = len2;
Packit 875988
        if (resultp)
Packit 875988
          *resultp = result;
Packit 875988
      }
Packit 875988
    }
Packit 875988
  }
Packit 875988
  va_end (argptr);
Packit 875988
  return len;
Packit 875988
}
Packit 875988
#endif
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
  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 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
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
  const char *form = cls;
Packit 875988
  char *reply;
Packit 875988
  struct MHD_Response *response;
Packit 875988
Packit 875988
  if (-1 == asprintf (&reply,
Packit 875988
		      form,
Packit 875988
		      session->value_1))
Packit 875988
    {
Packit 875988
      /* oops */
Packit 875988
      return MHD_NO;
Packit 875988
    }
Packit 875988
  /* return static form */
Packit 875988
  response = MHD_create_response_from_buffer (strlen (reply),
Packit 875988
					      (void *) reply,
Packit 875988
					      MHD_RESPMEM_MUST_FREE);
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 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
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
  const char *form = cls;
Packit 875988
  char *reply;
Packit 875988
  struct MHD_Response *response;
Packit 875988
Packit 875988
  if (-1 == asprintf (&reply,
Packit 875988
		      form,
Packit 875988
		      session->value_1,
Packit 875988
		      session->value_2))
Packit 875988
    {
Packit 875988
      /* oops */
Packit 875988
      return MHD_NO;
Packit 875988
    }
Packit 875988
  /* return static form */
Packit 875988
  response = MHD_create_response_from_buffer (strlen (reply),
Packit 875988
					      (void *) reply,
Packit 875988
					      MHD_RESPMEM_MUST_FREE);
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
  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, MAIN_PAGE },
Packit 875988
    { "/2", "text/html", &fill_v1_v2_form, SECOND_PAGE },
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;
Packit 875988
      memcpy (&session->value_1[off],
Packit 875988
	      data,
Packit 875988
	      size);
Packit 875988
      if (size + off < sizeof (session->value_1))
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;
Packit 875988
      memcpy (&session->value_2[off],
Packit 875988
	      data,
Packit 875988
	      size);
Packit 875988
      if (size + off < sizeof (session->value_2))
Packit 875988
	session->value_2[size+off] = '\0';
Packit 875988
      return MHD_YES;
Packit 875988
    }
Packit 875988
  fprintf (stderr, "Unsupported form value `%s'\n", 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
 *
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 to connection which is being processed
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
	    fprintf (stderr,
Packit 875988
		     "Aborting due to error during select: %s\n",
Packit 875988
		     strerror (errno));
Packit 875988
	  break;
Packit 875988
	}
Packit 875988
      MHD_run (d);
Packit 875988
    }
Packit 875988
  MHD_stop_daemon (d);
Packit 875988
  return 0;
Packit 875988
}