|
Packit |
875988 |
/*
|
|
Packit |
875988 |
This file is part of libmicrohttpd
|
|
Packit |
875988 |
Copyright (C) 2013 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 |
/**
|
|
Packit |
875988 |
* @file demo.c
|
|
Packit |
875988 |
* @brief complex demonstration site: create directory index, offer
|
|
Packit |
875988 |
* upload via form and HTTP POST, download with mime type detection
|
|
Packit |
875988 |
* and error reporting (403, etc.) --- and all of this with
|
|
Packit |
875988 |
* high-performance settings (large buffers, thread pool).
|
|
Packit |
875988 |
* If you want to benchmark MHD, this code should be used to
|
|
Packit |
875988 |
* run tests against. Note that the number of threads may need
|
|
Packit |
875988 |
* to be adjusted depending on the number of available cores.
|
|
Packit |
875988 |
* @author Christian Grothoff
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#include "platform.h"
|
|
Packit |
875988 |
#include <microhttpd.h>
|
|
Packit |
875988 |
#include <unistd.h>
|
|
Packit |
875988 |
#include <pthread.h>
|
|
Packit |
875988 |
#include <sys/types.h>
|
|
Packit |
875988 |
#include <sys/stat.h>
|
|
Packit |
875988 |
#include <dirent.h>
|
|
Packit |
875988 |
#ifdef MHD_HAVE_LIBMAGIC
|
|
Packit |
875988 |
#include <magic.h>
|
|
Packit |
875988 |
#endif /* MHD_HAVE_LIBMAGIC */
|
|
Packit |
875988 |
#include <limits.h>
|
|
Packit |
875988 |
#include <ctype.h>
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#if defined(CPU_COUNT) && (CPU_COUNT+0) < 2
|
|
Packit |
875988 |
#undef CPU_COUNT
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
#if !defined(CPU_COUNT)
|
|
Packit |
875988 |
#define CPU_COUNT 2
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Number of threads to run in the thread pool. Should (roughly) match
|
|
Packit |
875988 |
* the number of cores on your system.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define NUMBER_OF_THREADS CPU_COUNT
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#ifdef MHD_HAVE_LIBMAGIC
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* How many bytes of a file do we give to libmagic to determine the mime type?
|
|
Packit |
875988 |
* 16k might be a bit excessive, but ought not hurt performance much anyway,
|
|
Packit |
875988 |
* and should definitively be on the safe side.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define MAGIC_HEADER_SIZE (16 * 1024)
|
|
Packit |
875988 |
#endif /* MHD_HAVE_LIBMAGIC */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Page returned for file-not-found.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define FILE_NOT_FOUND_PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Page returned for internal errors.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define INTERNAL_ERROR_PAGE "<html><head><title>Internal error</title></head><body>Internal error</body></html>"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Page returned for refused requests.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define REQUEST_REFUSED_PAGE "<html><head><title>Request refused</title></head><body>Request refused (file exists?)</body></html>"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Head of index page.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define INDEX_PAGE_HEADER "<html>\n<head><title>Welcome</title></head>\n<body>\n"\
|
|
Packit |
875988 |
"Upload\n"\
|
|
Packit |
875988 |
"<form method=\"POST\" enctype=\"multipart/form-data\" action=\"/\">\n"\
|
|
Packit |
875988 |
"- Content type:
- "\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"category\" value=\"books\">Book</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"category\" value=\"images\">Image</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"category\" value=\"music\">Music</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"category\" value=\"software\">Software</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"category\" value=\"videos\">Videos</input>\n"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"category\" value=\"other\" checked>Other</input>"\
|
|
Packit |
875988 |
"Language:"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"language\" value=\"no-lang\" checked>none</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"language\" value=\"en\">English</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"language\" value=\"de\">German</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"language\" value=\"fr\">French</input>"\
|
|
Packit |
875988 |
"<input type=\"radio\" name=\"language\" value=\"es\">Spanish</input>\n"\
|
|
Packit |
875988 |
"File:"\
|
|
Packit |
875988 |
"<input type=\"file\" name=\"upload\"/>"\
|
|
Packit |
875988 |
"<input type=\"submit\" value=\"Send!\"/>\n"\
|
|
Packit |
875988 |
"</form>\n"\
|
|
Packit |
875988 |
"Download\n"\
|
|
Packit |
875988 |
"\n"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Footer of index page.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
#define INDEX_PAGE_FOOTER "\n</body>\n</html>"
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* NULL-terminated array of supported upload categories. Should match HTML
|
|
Packit |
875988 |
* in the form.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static const char * const categories[] =
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
"books",
|
|
Packit |
875988 |
"images",
|
|
Packit |
875988 |
"music",
|
|
Packit |
875988 |
"software",
|
|
Packit |
875988 |
"videos",
|
|
Packit |
875988 |
"other",
|
|
Packit |
875988 |
NULL,
|
|
Packit |
875988 |
};
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Specification of a supported language.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct Language
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Directory name for the language.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
const char *dirname;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Long name for humans.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
const char *longname;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
};
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* NULL-terminated array of supported upload categories. Should match HTML
|
|
Packit |
875988 |
* in the form.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static const struct Language languages[] =
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
{ "no-lang", "No language specified" },
|
|
Packit |
875988 |
{ "en", "English" },
|
|
Packit |
875988 |
{ "de", "German" },
|
|
Packit |
875988 |
{ "fr", "French" },
|
|
Packit |
875988 |
{ "es", "Spanish" },
|
|
Packit |
875988 |
{ NULL, NULL },
|
|
Packit |
875988 |
};
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Response returned if the requested file does not exist (or is not accessible).
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static struct MHD_Response *file_not_found_response;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Response returned for internal errors.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static struct MHD_Response *internal_error_response;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Response returned for '/' (GET) to list the contents of the directory and allow upload.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static struct MHD_Response *cached_directory_response;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Response returned for refused uploads.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static struct MHD_Response *request_refused_response;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Mutex used when we update the cached directory response object.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static pthread_mutex_t mutex;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#ifdef MHD_HAVE_LIBMAGIC
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Global handle to MAGIC data.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static magic_t magic;
|
|
Packit |
875988 |
#endif /* MHD_HAVE_LIBMAGIC */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Mark the given response as HTML for the brower.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response response to mark
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
mark_as_html (struct MHD_Response *response)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
(void) MHD_add_response_header (response,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_CONTENT_TYPE,
|
|
Packit |
875988 |
"text/html");
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Replace the existing 'cached_directory_response' with the
|
|
Packit |
875988 |
* given response.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param response new directory response
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
update_cached_response (struct MHD_Response *response)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
(void) pthread_mutex_lock (&mutex);
|
|
Packit |
875988 |
if (NULL != cached_directory_response)
|
|
Packit |
875988 |
MHD_destroy_response (cached_directory_response);
|
|
Packit |
875988 |
cached_directory_response = response;
|
|
Packit |
875988 |
(void) pthread_mutex_unlock (&mutex);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Context keeping the data for the response we're building.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct ResponseDataContext
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Response data string.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
char *buf;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Number of bytes allocated for 'buf'.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
size_t buf_len;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Current position where we append to 'buf'. Must be smaller or equal to 'buf_len'.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
size_t off;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
};
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Create a listing of the files in 'dirname' in HTML.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param rdc where to store the list of files
|
|
Packit |
875988 |
* @param dirname name of the directory to list
|
|
Packit |
875988 |
* @return #MHD_YES on success, #MHD_NO on error
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
list_directory (struct ResponseDataContext *rdc,
|
|
Packit |
875988 |
const char *dirname)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
char fullname[PATH_MAX];
|
|
Packit |
875988 |
struct stat sbuf;
|
|
Packit |
875988 |
DIR *dir;
|
|
Packit |
875988 |
struct dirent *de;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == (dir = opendir (dirname)))
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
while (NULL != (de = readdir (dir)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if ('.' == de->d_name[0])
|
|
Packit |
875988 |
continue;
|
|
Packit |
875988 |
if (sizeof (fullname) <= (unsigned int)
|
|
Packit |
875988 |
snprintf (fullname, sizeof (fullname),
|
|
Packit |
875988 |
"%s/%s",
|
|
Packit |
875988 |
dirname, de->d_name))
|
|
Packit |
875988 |
continue; /* ugh, file too long? how can this be!? */
|
|
Packit |
875988 |
if (0 != stat (fullname, &sbuf))
|
|
Packit |
875988 |
continue; /* ugh, failed to 'stat' */
|
|
Packit |
875988 |
if (! S_ISREG (sbuf.st_mode))
|
|
Packit |
875988 |
continue; /* not a regular file, skip */
|
|
Packit |
875988 |
if (rdc->off + 1024 > rdc->buf_len)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
void *r;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (2 * rdc->buf_len + 1024) < rdc->buf_len)
|
|
Packit |
875988 |
break; /* more than SIZE_T _index_ size? Too big for us */
|
|
Packit |
875988 |
rdc->buf_len = 2 * rdc->buf_len + 1024;
|
|
Packit |
875988 |
if (NULL == (r = realloc (rdc->buf, rdc->buf_len)))
|
|
Packit |
875988 |
break; /* out of memory */
|
|
Packit |
875988 |
rdc->buf = r;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
rdc->off += snprintf (&rdc->buf[rdc->off],
|
|
Packit |
875988 |
rdc->buf_len - rdc->off,
|
|
Packit |
875988 |
"%s\n",
|
|
Packit |
875988 |
fullname,
|
|
Packit |
875988 |
de->d_name);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
(void) closedir (dir);
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Re-scan our local directory and re-build the index.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
update_directory ()
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
static size_t initial_allocation = 32 * 1024; /* initial size for response buffer */
|
|
Packit |
875988 |
struct MHD_Response *response;
|
|
Packit |
875988 |
struct ResponseDataContext rdc;
|
|
Packit |
875988 |
unsigned int language_idx;
|
|
Packit |
875988 |
unsigned int category_idx;
|
|
Packit |
875988 |
const struct Language *language;
|
|
Packit |
875988 |
const char *category;
|
|
Packit |
875988 |
char dir_name[128];
|
|
Packit |
875988 |
struct stat sbuf;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
rdc.buf_len = initial_allocation;
|
|
Packit |
875988 |
if (NULL == (rdc.buf = malloc (rdc.buf_len)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
update_cached_response (NULL);
|
|
Packit |
875988 |
return;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
rdc.off = snprintf (rdc.buf, rdc.buf_len,
|
|
Packit |
875988 |
"%s",
|
|
Packit |
875988 |
INDEX_PAGE_HEADER);
|
|
Packit |
875988 |
for (language_idx = 0; NULL != languages[language_idx].dirname; language_idx++)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
language = &languages[language_idx];
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (0 != stat (language->dirname, &sbuf))
|
|
Packit |
875988 |
continue; /* empty */
|
|
Packit |
875988 |
/* we ensured always +1k room, filenames are ~256 bytes,
|
|
Packit |
875988 |
so there is always still enough space for the header
|
|
Packit |
875988 |
without need for an additional reallocation check. */
|
|
Packit |
875988 |
rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
|
|
Packit |
875988 |
"%s\n",
|
|
Packit |
875988 |
language->longname);
|
|
Packit |
875988 |
for (category_idx = 0; NULL != categories[category_idx]; category_idx++)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
category = categories[category_idx];
|
|
Packit |
875988 |
snprintf (dir_name, sizeof (dir_name),
|
|
Packit |
875988 |
"%s/%s",
|
|
Packit |
875988 |
language->dirname,
|
|
Packit |
875988 |
category);
|
|
Packit |
875988 |
if (0 != stat (dir_name, &sbuf))
|
|
Packit |
875988 |
continue; /* empty */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* we ensured always +1k room, filenames are ~256 bytes,
|
|
Packit |
875988 |
so there is always still enough space for the header
|
|
Packit |
875988 |
without need for an additional reallocation check. */
|
|
Packit |
875988 |
rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
|
|
Packit |
875988 |
"%s\n",
|
|
Packit |
875988 |
category);
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (MHD_NO == list_directory (&rdc, dir_name))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
free (rdc.buf);
|
|
Packit |
875988 |
update_cached_response (NULL);
|
|
Packit |
875988 |
return;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* we ensured always +1k room, filenames are ~256 bytes,
|
|
Packit |
875988 |
so there is always still enough space for the footer
|
|
Packit |
875988 |
without need for a final reallocation check. */
|
|
Packit |
875988 |
rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
|
|
Packit |
875988 |
"%s",
|
|
Packit |
875988 |
INDEX_PAGE_FOOTER);
|
|
Packit |
875988 |
initial_allocation = rdc.buf_len; /* remember for next time */
|
|
Packit |
875988 |
response = MHD_create_response_from_buffer (rdc.off,
|
|
Packit |
875988 |
rdc.buf,
|
|
Packit |
875988 |
MHD_RESPMEM_MUST_FREE);
|
|
Packit |
875988 |
mark_as_html (response);
|
|
Packit |
875988 |
#if FORCE_CLOSE
|
|
Packit |
875988 |
(void) MHD_add_response_header (response,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_CONNECTION,
|
|
Packit |
875988 |
"close");
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
update_cached_response (response);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Context we keep for an upload.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct UploadContext
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Handle where we write the uploaded file to.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int fd;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Name of the file on disk (used to remove on errors).
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
char *filename;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Language for the upload.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
char *language;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Category for the upload.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
char *category;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Post processor we're using to process the upload.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_PostProcessor *pp;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Handle to connection that we're processing the upload for.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_Connection *connection;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Response to generate, NULL to use directory.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
struct MHD_Response *response;
|
|
Packit |
875988 |
};
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Append the 'size' bytes from 'data' to '*ret', adding
|
|
Packit |
875988 |
* 0-termination. If '*ret' is NULL, allocate an empty string first.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param ret string to update, NULL or 0-terminated
|
|
Packit |
875988 |
* @param data data to append
|
|
Packit |
875988 |
* @param size number of bytes in 'data'
|
|
Packit |
875988 |
* @return MHD_NO on allocation failure, MHD_YES on success
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
do_append (char **ret,
|
|
Packit |
875988 |
const char *data,
|
|
Packit |
875988 |
size_t size)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
char *buf;
|
|
Packit |
875988 |
size_t old_len;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == *ret)
|
|
Packit |
875988 |
old_len = 0;
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
old_len = strlen (*ret);
|
|
Packit |
875988 |
buf = malloc (old_len + size + 1);
|
|
Packit |
875988 |
if (NULL == buf)
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
memcpy (buf, *ret, old_len);
|
|
Packit |
875988 |
if (NULL != *ret)
|
|
Packit |
875988 |
free (*ret);
|
|
Packit |
875988 |
memcpy (&buf[old_len], data, size);
|
|
Packit |
875988 |
buf[old_len + size] = '\0';
|
|
Packit |
875988 |
*ret = buf;
|
|
Packit |
875988 |
return MHD_YES;
|
|
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, always MHD_POSTDATA_KIND when called from MHD
|
|
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 |
process_upload_data (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,
|
|
Packit |
875988 |
uint64_t off,
|
|
Packit |
875988 |
size_t size)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct UploadContext *uc = cls;
|
|
Packit |
875988 |
int i;
|
|
Packit |
875988 |
(void)kind; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
(void)content_type; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
(void)transfer_encoding; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
(void)off; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (0 == strcmp (key, "category"))
|
|
Packit |
875988 |
return do_append (&uc->category, data, size);
|
|
Packit |
875988 |
if (0 == strcmp (key, "language"))
|
|
Packit |
875988 |
return do_append (&uc->language, data, size);
|
|
Packit |
875988 |
if (0 != strcmp (key, "upload"))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
fprintf (stderr,
|
|
Packit |
875988 |
"Ignoring unexpected form value `%s'\n",
|
|
Packit |
875988 |
key);
|
|
Packit |
875988 |
return MHD_YES; /* ignore */
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (NULL == filename)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
fprintf (stderr, "No filename, aborting upload\n");
|
|
Packit |
875988 |
return MHD_NO; /* no filename, error */
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if ( (NULL == uc->category) ||
|
|
Packit |
875988 |
(NULL == uc->language) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
fprintf (stderr,
|
|
Packit |
875988 |
"Missing form data for upload `%s'\n",
|
|
Packit |
875988 |
filename);
|
|
Packit |
875988 |
uc->response = request_refused_response;
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (-1 == uc->fd)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
char fn[PATH_MAX];
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (NULL != strstr (filename, "..")) ||
|
|
Packit |
875988 |
(NULL != strchr (filename, '/')) ||
|
|
Packit |
875988 |
(NULL != strchr (filename, '\\')) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
uc->response = request_refused_response;
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* create directories -- if they don't exist already */
|
|
Packit |
875988 |
#ifdef WINDOWS
|
|
Packit |
875988 |
(void) mkdir (uc->language);
|
|
Packit |
875988 |
#else
|
|
Packit |
875988 |
(void) mkdir (uc->language, S_IRWXU);
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
snprintf (fn, sizeof (fn),
|
|
Packit |
875988 |
"%s/%s",
|
|
Packit |
875988 |
uc->language,
|
|
Packit |
875988 |
uc->category);
|
|
Packit |
875988 |
#ifdef WINDOWS
|
|
Packit |
875988 |
(void) mkdir (fn);
|
|
Packit |
875988 |
#else
|
|
Packit |
875988 |
(void) mkdir (fn, S_IRWXU);
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
/* open file */
|
|
Packit |
875988 |
snprintf (fn, sizeof (fn),
|
|
Packit |
875988 |
"%s/%s/%s",
|
|
Packit |
875988 |
uc->language,
|
|
Packit |
875988 |
uc->category,
|
|
Packit |
875988 |
filename);
|
|
Packit |
875988 |
for (i=strlen (fn)-1;i>=0;i--)
|
|
Packit |
875988 |
if (! isprint ((unsigned char) fn[i]))
|
|
Packit |
875988 |
fn[i] = '_';
|
|
Packit |
875988 |
uc->fd = open (fn,
|
|
Packit |
875988 |
O_CREAT | O_EXCL
|
|
Packit |
875988 |
#if O_LARGEFILE
|
|
Packit |
875988 |
| O_LARGEFILE
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
| O_WRONLY,
|
|
Packit |
875988 |
S_IRUSR | S_IWUSR);
|
|
Packit |
875988 |
if (-1 == uc->fd)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
fprintf (stderr,
|
|
Packit |
875988 |
"Error opening file `%s' for upload: %s\n",
|
|
Packit |
875988 |
fn,
|
|
Packit |
875988 |
strerror (errno));
|
|
Packit |
875988 |
uc->response = request_refused_response;
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
uc->filename = strdup (fn);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if ( (0 != size) &&
|
|
Packit |
875988 |
(size != (size_t) write (uc->fd, data, size)) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* write failed; likely: disk full */
|
|
Packit |
875988 |
fprintf (stderr,
|
|
Packit |
875988 |
"Error writing to file `%s': %s\n",
|
|
Packit |
875988 |
uc->filename,
|
|
Packit |
875988 |
strerror (errno));
|
|
Packit |
875988 |
uc->response = internal_error_response;
|
|
Packit |
875988 |
(void) close (uc->fd);
|
|
Packit |
875988 |
uc->fd = -1;
|
|
Packit |
875988 |
if (NULL != uc->filename)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
unlink (uc->filename);
|
|
Packit |
875988 |
free (uc->filename);
|
|
Packit |
875988 |
uc->filename = NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Function called whenever a request was completed.
|
|
Packit |
875988 |
* Used to clean up 'struct UploadContext' objects.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param cls client-defined closure, NULL
|
|
Packit |
875988 |
* @param connection connection handle
|
|
Packit |
875988 |
* @param con_cls value as set by the last call to
|
|
Packit |
875988 |
* the MHD_AccessHandlerCallback, points to NULL if this was
|
|
Packit |
875988 |
* not an upload
|
|
Packit |
875988 |
* @param toe reason for request termination
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
response_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 UploadContext *uc = *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 == uc)
|
|
Packit |
875988 |
return; /* this request wasn't an upload request */
|
|
Packit |
875988 |
if (NULL != uc->pp)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
MHD_destroy_post_processor (uc->pp);
|
|
Packit |
875988 |
uc->pp = NULL;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (-1 != uc->fd)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
(void) close (uc->fd);
|
|
Packit |
875988 |
if (NULL != uc->filename)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
fprintf (stderr,
|
|
Packit |
875988 |
"Upload of file `%s' failed (incomplete or aborted), removing file.\n",
|
|
Packit |
875988 |
uc->filename);
|
|
Packit |
875988 |
(void) unlink (uc->filename);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (NULL != uc->filename)
|
|
Packit |
875988 |
free (uc->filename);
|
|
Packit |
875988 |
free (uc);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Return the current directory listing.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param connection connection to return the directory for
|
|
Packit |
875988 |
* @return MHD_YES on success, MHD_NO on error
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
return_directory_response (struct MHD_Connection *connection)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
int ret;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
(void) pthread_mutex_lock (&mutex);
|
|
Packit |
875988 |
if (NULL == cached_directory_response)
|
|
Packit |
875988 |
ret = MHD_queue_response (connection,
|
|
Packit |
875988 |
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
|
Packit |
875988 |
internal_error_response);
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
ret = MHD_queue_response (connection,
|
|
Packit |
875988 |
MHD_HTTP_OK,
|
|
Packit |
875988 |
cached_directory_response);
|
|
Packit |
875988 |
(void) pthread_mutex_unlock (&mutex);
|
|
Packit |
875988 |
return ret;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Main callback from MHD, used to generate the page.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param cls NULL
|
|
Packit |
875988 |
* @param connection connection handle
|
|
Packit |
875988 |
* @param url requested URL
|
|
Packit |
875988 |
* @param method GET, PUT, POST, etc.
|
|
Packit |
875988 |
* @param version HTTP version
|
|
Packit |
875988 |
* @param upload_data data from upload (PUT/POST)
|
|
Packit |
875988 |
* @param upload_data_size number of bytes in "upload_data"
|
|
Packit |
875988 |
* @param ptr our context
|
|
Packit |
875988 |
* @return MHD_YES on success, MHD_NO to drop connection
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static int
|
|
Packit |
875988 |
generate_page (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, void **ptr)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Response *response;
|
|
Packit |
875988 |
int ret;
|
|
Packit |
875988 |
int fd;
|
|
Packit |
875988 |
struct stat buf;
|
|
Packit |
875988 |
(void)cls; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
(void)version; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (0 != strcmp (url, "/"))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* should be file download */
|
|
Packit |
875988 |
#ifdef MHD_HAVE_LIBMAGIC
|
|
Packit |
875988 |
char file_data[MAGIC_HEADER_SIZE];
|
|
Packit |
875988 |
ssize_t got;
|
|
Packit |
875988 |
#endif /* MHD_HAVE_LIBMAGIC */
|
|
Packit |
875988 |
const char *mime;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (0 != strcmp (method, MHD_HTTP_METHOD_GET)) &&
|
|
Packit |
875988 |
(0 != strcmp (method, MHD_HTTP_METHOD_HEAD)) )
|
|
Packit |
875988 |
return MHD_NO; /* unexpected method (we're not polite...) */
|
|
Packit |
875988 |
fd = -1;
|
|
Packit |
875988 |
if ( (NULL == strstr (&url[1], "..")) &&
|
|
Packit |
875988 |
('/' != url[1]) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
fd = open (&url[1], O_RDONLY);
|
|
Packit |
875988 |
if ( (-1 != fd) &&
|
|
Packit |
875988 |
( (0 != fstat (fd, &buf)) ||
|
|
Packit |
875988 |
(! S_ISREG (buf.st_mode)) ) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
(void) close (fd);
|
|
Packit |
875988 |
fd = -1;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (-1 == fd)
|
|
Packit |
875988 |
return MHD_queue_response (connection,
|
|
Packit |
875988 |
MHD_HTTP_NOT_FOUND,
|
|
Packit |
875988 |
file_not_found_response);
|
|
Packit |
875988 |
#ifdef MHD_HAVE_LIBMAGIC
|
|
Packit |
875988 |
/* read beginning of the file to determine mime type */
|
|
Packit |
875988 |
got = read (fd, file_data, sizeof (file_data));
|
|
Packit |
875988 |
(void) lseek (fd, 0, SEEK_SET);
|
|
Packit |
875988 |
if (-1 != got)
|
|
Packit |
875988 |
mime = magic_buffer (magic, file_data, got);
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
#endif /* MHD_HAVE_LIBMAGIC */
|
|
Packit |
875988 |
mime = NULL;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == (response = MHD_create_response_from_fd (buf.st_size,
|
|
Packit |
875988 |
fd)))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* internal error (i.e. out of memory) */
|
|
Packit |
875988 |
(void) close (fd);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* add mime type if we had one */
|
|
Packit |
875988 |
if (NULL != mime)
|
|
Packit |
875988 |
(void) MHD_add_response_header (response,
|
|
Packit |
875988 |
MHD_HTTP_HEADER_CONTENT_TYPE,
|
|
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 |
if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* upload! */
|
|
Packit |
875988 |
struct UploadContext *uc = *ptr;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if (NULL == uc)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (NULL == (uc = malloc (sizeof (struct UploadContext))))
|
|
Packit |
875988 |
return MHD_NO; /* out of memory, close connection */
|
|
Packit |
875988 |
memset (uc, 0, sizeof (struct UploadContext));
|
|
Packit |
875988 |
uc->fd = -1;
|
|
Packit |
875988 |
uc->connection = connection;
|
|
Packit |
875988 |
uc->pp = MHD_create_post_processor (connection,
|
|
Packit |
875988 |
64 * 1024 /* buffer size */,
|
|
Packit |
875988 |
&process_upload_data, uc);
|
|
Packit |
875988 |
if (NULL == uc->pp)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
/* out of memory, close connection */
|
|
Packit |
875988 |
free (uc);
|
|
Packit |
875988 |
return MHD_NO;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
*ptr = uc;
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (0 != *upload_data_size)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
if (NULL == uc->response)
|
|
Packit |
875988 |
(void) MHD_post_process (uc->pp,
|
|
Packit |
875988 |
upload_data,
|
|
Packit |
875988 |
*upload_data_size);
|
|
Packit |
875988 |
*upload_data_size = 0;
|
|
Packit |
875988 |
return MHD_YES;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
/* end of upload, finish it! */
|
|
Packit |
875988 |
MHD_destroy_post_processor (uc->pp);
|
|
Packit |
875988 |
uc->pp = NULL;
|
|
Packit |
875988 |
if (-1 != uc->fd)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
close (uc->fd);
|
|
Packit |
875988 |
uc->fd = -1;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
if (NULL != uc->response)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
return MHD_queue_response (connection,
|
|
Packit |
875988 |
MHD_HTTP_FORBIDDEN,
|
|
Packit |
875988 |
uc->response);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
else
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
update_directory ();
|
|
Packit |
875988 |
return return_directory_response (connection);
|
|
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 |
return return_directory_response (connection);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* unexpected request, refuse */
|
|
Packit |
875988 |
return MHD_queue_response (connection,
|
|
Packit |
875988 |
MHD_HTTP_FORBIDDEN,
|
|
Packit |
875988 |
request_refused_response);
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
#ifndef MINGW
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Function called if we get a SIGPIPE. Does nothing.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param sig will be SIGPIPE (ignored)
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
catcher (int sig)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
(void)sig; /* Unused. Silent compiler warning. */
|
|
Packit |
875988 |
/* do nothing */
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* setup handlers to ignore SIGPIPE.
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
static void
|
|
Packit |
875988 |
ignore_sigpipe ()
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct sigaction oldsig;
|
|
Packit |
875988 |
struct sigaction sig;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
sig.sa_handler = &catcher;
|
|
Packit |
875988 |
sigemptyset (&sig.sa_mask);
|
|
Packit |
875988 |
#ifdef SA_INTERRUPT
|
|
Packit |
875988 |
sig.sa_flags = SA_INTERRUPT; /* SunOS */
|
|
Packit |
875988 |
#else
|
|
Packit |
875988 |
sig.sa_flags = SA_RESTART;
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
if (0 != sigaction (SIGPIPE, &sig, &oldsig))
|
|
Packit |
875988 |
fprintf (stderr,
|
|
Packit |
875988 |
"Failed to install SIGPIPE handler: %s\n", strerror (errno));
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/**
|
|
Packit |
875988 |
* Entry point to demo. Note: this HTTP server will make all
|
|
Packit |
875988 |
* files in the current directory and its subdirectories available
|
|
Packit |
875988 |
* to anyone. Press ENTER to stop the server once it has started.
|
|
Packit |
875988 |
*
|
|
Packit |
875988 |
* @param argc number of arguments in argv
|
|
Packit |
875988 |
* @param argv first and only argument should be the port number
|
|
Packit |
875988 |
* @return 0 on success
|
|
Packit |
875988 |
*/
|
|
Packit |
875988 |
int
|
|
Packit |
875988 |
main (int argc, char *const *argv)
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
struct MHD_Daemon *d;
|
|
Packit |
875988 |
unsigned int port;
|
|
Packit |
875988 |
|
|
Packit |
875988 |
if ( (argc != 2) ||
|
|
Packit |
875988 |
(1 != sscanf (argv[1], "%u", &port)) ||
|
|
Packit |
875988 |
(UINT16_MAX < port) )
|
|
Packit |
875988 |
{
|
|
Packit |
875988 |
fprintf (stderr,
|
|
Packit |
875988 |
"%s PORT\n", argv[0]);
|
|
Packit |
875988 |
return 1;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
#ifndef MINGW
|
|
Packit |
875988 |
ignore_sigpipe ();
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
#ifdef MHD_HAVE_LIBMAGIC
|
|
Packit |
875988 |
magic = magic_open (MAGIC_MIME_TYPE);
|
|
Packit |
875988 |
(void) magic_load (magic, NULL);
|
|
Packit |
875988 |
#endif /* MHD_HAVE_LIBMAGIC */
|
|
Packit |
875988 |
|
|
Packit |
875988 |
(void) pthread_mutex_init (&mutex, NULL);
|
|
Packit |
875988 |
file_not_found_response = MHD_create_response_from_buffer (strlen (FILE_NOT_FOUND_PAGE),
|
|
Packit |
875988 |
(void *) FILE_NOT_FOUND_PAGE,
|
|
Packit |
875988 |
MHD_RESPMEM_PERSISTENT);
|
|
Packit |
875988 |
mark_as_html (file_not_found_response);
|
|
Packit |
875988 |
request_refused_response = MHD_create_response_from_buffer (strlen (REQUEST_REFUSED_PAGE),
|
|
Packit |
875988 |
(void *) REQUEST_REFUSED_PAGE,
|
|
Packit |
875988 |
MHD_RESPMEM_PERSISTENT);
|
|
Packit |
875988 |
mark_as_html (request_refused_response);
|
|
Packit |
875988 |
internal_error_response = MHD_create_response_from_buffer (strlen (INTERNAL_ERROR_PAGE),
|
|
Packit |
875988 |
(void *) INTERNAL_ERROR_PAGE,
|
|
Packit |
875988 |
MHD_RESPMEM_PERSISTENT);
|
|
Packit |
875988 |
mark_as_html (internal_error_response);
|
|
Packit |
875988 |
update_directory ();
|
|
Packit |
875988 |
d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
|
|
Packit |
875988 |
port,
|
|
Packit |
875988 |
NULL, NULL,
|
|
Packit |
875988 |
&generate_page, NULL,
|
|
Packit |
875988 |
MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (256 * 1024),
|
|
Packit |
875988 |
#if PRODUCTION
|
|
Packit |
875988 |
MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) (64),
|
|
Packit |
875988 |
#endif
|
|
Packit |
875988 |
MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) (120 /* seconds */),
|
|
Packit |
875988 |
MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) NUMBER_OF_THREADS,
|
|
Packit |
875988 |
MHD_OPTION_NOTIFY_COMPLETED, &response_completed_callback, NULL,
|
|
Packit |
875988 |
MHD_OPTION_END);
|
|
Packit |
875988 |
if (NULL == d)
|
|
Packit |
875988 |
return 1;
|
|
Packit |
875988 |
fprintf (stderr, "HTTP server running. Press ENTER to stop the server\n");
|
|
Packit |
875988 |
(void) getc (stdin);
|
|
Packit |
875988 |
MHD_stop_daemon (d);
|
|
Packit |
875988 |
MHD_destroy_response (file_not_found_response);
|
|
Packit |
875988 |
MHD_destroy_response (request_refused_response);
|
|
Packit |
875988 |
MHD_destroy_response (internal_error_response);
|
|
Packit |
875988 |
update_cached_response (NULL);
|
|
Packit |
875988 |
(void) pthread_mutex_destroy (&mutex);
|
|
Packit |
875988 |
#ifdef MHD_HAVE_LIBMAGIC
|
|
Packit |
875988 |
magic_close (magic);
|
|
Packit |
875988 |
#endif /* MHD_HAVE_LIBMAGIC */
|
|
Packit |
875988 |
return 0;
|
|
Packit |
875988 |
}
|
|
Packit |
875988 |
|
|
Packit |
875988 |
/* end of demo.c */
|