|
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, ¬_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 |
}
|