[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r26703 - in libmicrohttpd: . src/examples
From: |
gnunet |
Subject: |
[GNUnet-SVN] r26703 - in libmicrohttpd: . src/examples |
Date: |
Sun, 31 Mar 2013 22:22:02 +0200 |
Author: grothoff
Date: 2013-03-31 22:22:02 +0200 (Sun, 31 Mar 2013)
New Revision: 26703
Modified:
libmicrohttpd/configure.ac
libmicrohttpd/src/examples/Makefile.am
libmicrohttpd/src/examples/demo.c
Log:
add mime types to demo
Modified: libmicrohttpd/configure.ac
===================================================================
--- libmicrohttpd/configure.ac 2013-03-31 20:03:26 UTC (rev 26702)
+++ libmicrohttpd/configure.ac 2013-03-31 20:22:02 UTC (rev 26703)
@@ -255,6 +255,14 @@
AC_DEFINE_UNQUOTED([MHD_REQ_CURL_GNUTLS_VERSION],
"$MHD_REQ_CURL_GNUTLS_VERSION", [gnuTLS lib version - used in conjunction with
cURL])
AC_DEFINE_UNQUOTED([MHD_REQ_CURL_NSS_VERSION], "$MHD_REQ_CURL_NSS_VERSION",
[NSS lib version - used in conjunction with cURL])
fi
+
+AC_MSG_CHECKING(for magic_open -lmagic)
+AC_CHECK_LIB(magic, magic_open,
+ [AC_CHECK_HEADERS([magic.h],
+ AM_CONDITIONAL(HAVE_MAGIC, true),
+ AM_CONDITIONAL(HAVE_MAGIC, false))],
+ AM_CONDITIONAL(HAVE_MAGIC, false))
+
LIBS=$SAVE_LIBS
AM_CONDITIONAL(HAVE_CURL, test x$curl = x1)
Modified: libmicrohttpd/src/examples/Makefile.am
===================================================================
--- libmicrohttpd/src/examples/Makefile.am 2013-03-31 20:03:26 UTC (rev
26702)
+++ libmicrohttpd/src/examples/Makefile.am 2013-03-31 20:22:02 UTC (rev
26703)
@@ -29,9 +29,12 @@
endif
if HAVE_POSTPROCESSOR
noinst_PROGRAMS += \
- demo \
post_example
+if HAVE_MAGIC
+noinst_PROGRAMS += \
+ demo
endif
+endif
if ENABLE_DAUTH
noinst_PROGRAMS += \
@@ -55,7 +58,8 @@
demo_SOURCES = \
demo.c
demo_LDADD = \
- $(top_builddir)/src/daemon/libmicrohttpd.la
+ $(top_builddir)/src/daemon/libmicrohttpd.la \
+ -lmagic
dual_stack_example_SOURCES = \
dual_stack_example.c
Modified: libmicrohttpd/src/examples/demo.c
===================================================================
--- libmicrohttpd/src/examples/demo.c 2013-03-31 20:03:26 UTC (rev 26702)
+++ libmicrohttpd/src/examples/demo.c 2013-03-31 20:22:02 UTC (rev 26703)
@@ -23,17 +23,23 @@
* @author Christian Grothoff
*
* TODO:
- * - even with LARGE memory pool & buffers, uploads proceed at 5000 bytes/call
(ugh)
* - should have a slightly more ambitious upload form & file listing
(structure!)
- * - may want to add MIME-types to replies
*/
#include "platform.h"
#include <microhttpd.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <dirent.h>
+#include <magic.h>
+/**
+ * How many bytes of a file do we give to libmagic to determine the mime type?
+ * 16k might be a bit excessive, but ought not hurt performance much anyway,
+ * and should definitively be on the safe side.
+ */
+#define MAGIC_HEADER_SIZE (16 * 1024)
/**
* Page returned for file-not-found.
@@ -48,6 +54,12 @@
/**
+ * Page returned for refused requests.
+ */
+#define REQUEST_REFUSED_PAGE "<html><head><title>Request
refused</title></head><body>Request refused (file exists?)</body></html>"
+
+
+/**
* Head of index page.
*/
#define INDEX_PAGE_HEADER
"<html>\n<head><title>Welcome</title></head>\n<body>\n"\
@@ -63,6 +75,7 @@
#define INDEX_PAGE_FOOTER "</ol>\n</body>\n</html>"
+
/**
* Response returned if the requested file does not exist (or is not
accessible).
*/
@@ -79,12 +92,36 @@
static struct MHD_Response *cached_directory_response;
/**
+ * Response returned for refused uploads.
+ */
+static struct MHD_Response *request_refused_response;
+
+/**
* Mutex used when we update the cached directory response object.
*/
static pthread_mutex_t mutex;
+/**
+ * Global handle to MAGIC data.
+ */
+static magic_t magic;
+
/**
+ * Mark the given response as HTML for the brower.
+ *
+ * @param response response to mark
+ */
+static void
+mark_as_html (struct MHD_Response *response)
+{
+ (void) MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ "text/html");
+}
+
+
+/**
* Replace the existing 'cached_directory_response' with the
* given response.
*
@@ -102,68 +139,119 @@
/**
- * Re-scan our local directory and re-build the index.
+ * Context keeping the data for the response we're building.
*/
-static void
-update_directory ()
+struct ResponseDataContext
{
- static size_t initial_allocation = 32 * 1024; /* initial size for response
buffer */
- DIR *dir;
- struct dirent *de;
- struct MHD_Response *response;
+ /**
+ * Response data string.
+ */
char *buf;
+
+ /**
+ * Number of bytes allocated for 'buf'.
+ */
size_t buf_len;
+
+ /**
+ * Current position where we append to 'buf'. Must be smaller or equal to
'buf_len'.
+ */
size_t off;
- dir = opendir (".");
- if (NULL == dir)
- goto err;
- buf_len = initial_allocation;
- buf = malloc (buf_len);
- if (NULL == buf)
- {
- closedir (dir);
- goto err;
- }
- off = snprintf (buf, buf_len,
- "%s",
- INDEX_PAGE_HEADER);
+};
+
+
+/**
+ * Create a listing of the files in 'dirname' in HTML.
+ *
+ * @param rdc where to store the list of files
+ * @param dirname name of the directory to list
+ * @return MHD_YES on success, MHD_NO on error
+ */
+static int
+list_directory (struct ResponseDataContext *rdc,
+ const char *dirname)
+{
+ char fullname[PATH_MAX];
+ struct stat sbuf;
+ DIR *dir;
+ struct dirent *de;
+
+ if (NULL == (dir = opendir (dirname)))
+ return MHD_NO;
while (NULL != (de = readdir (dir)))
{
if ('.' == de->d_name[0])
continue;
- if (off + 1024 > buf_len)
+ if (sizeof (fullname) <=
+ snprintf (fullname, sizeof (fullname),
+ "%s/%s",
+ dirname, de->d_name))
+ continue; /* ugh, file too long? how can this be!? */
+ if (0 != stat (fullname, &sbuf))
+ continue; /* ugh, failed to 'stat' */
+ if (! S_ISREG (sbuf.st_mode))
+ continue; /* not a regular file, skip */
+ if (rdc->off + 1024 > rdc->buf_len)
{
void *r;
- if ( (2 * buf_len + 1024) < buf_len)
+ if ( (2 * rdc->buf_len + 1024) < rdc->buf_len)
break; /* more than SIZE_T _index_ size? Too big for us */
- buf_len = 2 * buf_len + 1024;
- if (NULL == (r = realloc (buf, buf_len)))
+ rdc->buf_len = 2 * rdc->buf_len + 1024;
+ if (NULL == (r = realloc (rdc->buf, rdc->buf_len)))
break; /* out of memory */
- buf = r;
+ rdc->buf = r;
}
- off += snprintf (&buf[off], buf_len - off,
- "<li><a href=\"/%s\">%s</a></li>\n",
- de->d_name,
- de->d_name);
+ rdc->off += snprintf (&rdc->buf[rdc->off],
+ rdc->buf_len - rdc->off,
+ "<li><a href=\"/%s\">%s</a></li>\n",
+ de->d_name,
+ de->d_name);
}
+ (void) closedir (dir);
+ return MHD_YES;
+}
+
+
+/**
+ * Re-scan our local directory and re-build the index.
+ */
+static void
+update_directory ()
+{
+ static size_t initial_allocation = 32 * 1024; /* initial size for response
buffer */
+ struct MHD_Response *response;
+ struct ResponseDataContext rdc;
+
+ rdc.buf_len = initial_allocation;
+ if (NULL == (rdc.buf = malloc (rdc.buf_len)))
+ {
+ update_cached_response (NULL);
+ return;
+ }
+ rdc.off = snprintf (rdc.buf, rdc.buf_len,
+ "%s",
+ INDEX_PAGE_HEADER);
+
+ if (MHD_NO == list_directory (&rdc, "."))
+ {
+ free (rdc.buf);
+ update_cached_response (NULL);
+ return;
+ }
/* we ensured always +1k room, filenames are ~256 bytes,
so there is always still enough space for the footer
without need for a final reallocation check. */
- off += snprintf (&buf[off], buf_len - off,
- "%s",
- INDEX_PAGE_FOOTER);
- closedir (dir);
- initial_allocation = buf_len; /* remember for next time */
- response = MHD_create_response_from_buffer (off,
- buf,
+ rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off,
+ "%s",
+ INDEX_PAGE_FOOTER);
+ initial_allocation = rdc.buf_len; /* remember for next time */
+ response = MHD_create_response_from_buffer (rdc.off,
+ rdc.buf,
MHD_RESPMEM_MUST_FREE);
+ mark_as_html (response);
update_cached_response (response);
- return;
- err:
- /* failed to list directory, use error page */
- update_cached_response (NULL);
}
@@ -178,6 +266,11 @@
int fd;
/**
+ * Name of the file on disk (used to remove on errors).
+ */
+ char *filename;
+
+ /**
* Post processor we're using to process the upload.
*/
struct MHD_PostProcessor *pp;
@@ -186,6 +279,11 @@
* Handle to connection that we're processing the upload for.
*/
struct MHD_Connection *connection;
+
+ /**
+ * Response to generate, NULL to use directory.
+ */
+ struct MHD_Response *response;
};
@@ -228,32 +326,48 @@
}
if (-1 == uc->fd)
{
+ if ( (NULL != strstr (filename, "..")) ||
+ (NULL != strchr (filename, '/')) ||
+ (NULL != strchr (filename, '\\')) )
+ {
+ uc->response = request_refused_response;
+ return MHD_NO;
+ }
uc->fd = open (filename,
O_CREAT | O_EXCL
#if O_LARGEFILE
| O_LARGEFILE
#endif
-#if O_NONBLOCK
- | O_NONBLOCK
-#endif
| O_WRONLY,
S_IRUSR | S_IWUSR);
if (-1 == uc->fd)
{
- // FIXME: generate error page NICELY
- fprintf (stderr, "Error opening file to write!\n");
+ fprintf (stderr,
+ "Error opening file `%s' for upload: %s\n",
+ filename,
+ strerror (errno));
+ uc->response = request_refused_response;
return MHD_NO;
}
}
- else if (0 == size)
- sleep (1);
-
-
+ uc->filename = strdup (filename);
if ( (0 != size) &&
(size != write (uc->fd, data, size)) )
{
- // FIXME: generate error page NICELY
- fprintf (stderr, "Error writing to disk!\n");
+ /* write failed; likely: disk full */
+ fprintf (stderr,
+ "Error writing to file `%s': %s\n",
+ filename,
+ strerror (errno));
+ uc->response = internal_error_response;
+ close (uc->fd);
+ uc->fd = -1;
+ if (NULL != uc->filename)
+ {
+ unlink (uc->filename);
+ free (uc->filename);
+ uc->filename = NULL;
+ }
return MHD_NO;
}
return MHD_YES;
@@ -288,10 +402,17 @@
}
if (-1 != uc->fd)
{
- close (uc->fd);
- fprintf (stderr, "Possible upload failure, need to remove file?!\n");
- /* FIXME: unlink here on error!? */
+ (void) close (uc->fd);
+ if (NULL != uc->filename)
+ {
+ fprintf (stderr,
+ "Upload of file `%s' failed (incomplete or aborted), removing
file.\n",
+ uc->filename);
+ (void) unlink (uc->filename);
+ }
}
+ if (NULL != uc->filename)
+ free (uc->filename);
free (uc);
}
@@ -303,7 +424,7 @@
* @return MHD_YES on success, MHD_NO on error
*/
static int
-list_directory (struct MHD_Connection *connection)
+return_directory_response (struct MHD_Connection *connection)
{
int ret;
@@ -321,7 +442,6 @@
}
-
/**
* Main callback from MHD, used to generate the page.
*
@@ -352,6 +472,10 @@
if (0 != strcmp (url, "/"))
{
/* should be file download */
+ char file_data[MAGIC_HEADER_SIZE];
+ ssize_t got;
+ const char *mime;
+
if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
return MHD_NO; /* unexpected method (we're not polite...) */
if ( (0 == stat (&url[1], &buf)) &&
@@ -364,6 +488,14 @@
return MHD_queue_response (connection,
MHD_HTTP_NOT_FOUND,
file_not_found_response);
+ /* read beginning of the file to determine mime type */
+ got = read (fd, file_data, sizeof (file_data));
+ if (-1 != got)
+ mime = magic_buffer (magic, file_data, got);
+ else
+ mime = NULL;
+ (void) lseek (fd, 0, SEEK_SET);
+
if (NULL == (response = MHD_create_response_from_fd (buf.st_size,
fd)))
{
@@ -371,6 +503,12 @@
(void) close (fd);
return MHD_NO;
}
+
+ /* add mime type if we had one */
+ if (NULL != mime)
+ (void) MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ mime);
ret = MHD_queue_response (connection,
MHD_HTTP_OK,
response);
@@ -387,6 +525,8 @@
{
if (NULL == (uc = malloc (sizeof (struct UploadContext))))
return MHD_NO; /* out of memory, close connection */
+ uc->response = NULL;
+ uc->filename = NULL;
uc->fd = -1;
uc->connection = connection;
uc->pp = MHD_create_post_processor (connection,
@@ -400,14 +540,15 @@
}
*ptr = uc;
return MHD_YES;
- }
+ }
if (0 != *upload_data_size)
{
- ret = MHD_post_process (uc->pp,
- upload_data,
- *upload_data_size);
+ if (NULL != uc->response)
+ (void) MHD_post_process (uc->pp,
+ upload_data,
+ *upload_data_size);
*upload_data_size = 0;
- return ret;
+ return MHD_YES;
}
/* end of upload, finish it! */
MHD_destroy_post_processor (uc->pp);
@@ -417,22 +558,32 @@
close (uc->fd);
uc->fd = -1;
}
- update_directory ();
- return list_directory (connection);
+ if (NULL != uc->response)
+ {
+ return MHD_queue_response (connection,
+ MHD_HTTP_FORBIDDEN,
+ uc->response);
+ }
+ else
+ {
+ update_directory ();
+ return return_directory_response (connection);
+ }
}
if (0 == strcmp (method, MHD_HTTP_METHOD_GET))
- return list_directory (connection);
+ return return_directory_response (connection);
/* unexpected request, refuse */
- fprintf (stderr, "Unexpected request, refusing\n");
- return MHD_NO;
+ return MHD_queue_response (connection,
+ MHD_HTTP_FORBIDDEN,
+ request_refused_response);
}
/**
* Entry point to demo. Note: this HTTP server will make all
* files in the current directory and its subdirectories available
- * to anyone.
+ * to anyone. Press ENTER to stop the server once it has started.
*
* @param argc number of arguments in argv
* @param argv first and only argument should be the port number
@@ -452,13 +603,22 @@
"%s PORT\n", argv[0]);
return 1;
}
+ magic = magic_open (MAGIC_MIME_TYPE);
+ (void) magic_load (magic, NULL);
+
(void) pthread_mutex_init (&mutex, NULL);
file_not_found_response = MHD_create_response_from_buffer (strlen
(FILE_NOT_FOUND_PAGE),
(void *)
FILE_NOT_FOUND_PAGE,
MHD_RESPMEM_PERSISTENT);
+ mark_as_html (file_not_found_response);
+ request_refused_response = MHD_create_response_from_buffer (strlen
(REQUEST_REFUSED_PAGE),
+ (void *)
REQUEST_REFUSED_PAGE,
+
MHD_RESPMEM_PERSISTENT);
+ mark_as_html (request_refused_response);
internal_error_response = MHD_create_response_from_buffer (strlen
(INTERNAL_ERROR_PAGE),
(void *)
INTERNAL_ERROR_PAGE,
MHD_RESPMEM_PERSISTENT);
+ mark_as_html (internal_error_response);
update_directory ();
d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
port,
@@ -470,12 +630,15 @@
MHD_OPTION_END);
if (NULL == d)
return 1;
+ fprintf (stderr, "HTTP server running. Press ENTER to stop the server\n");
(void) getc (stdin);
MHD_stop_daemon (d);
MHD_destroy_response (file_not_found_response);
+ MHD_destroy_response (request_refused_response);
MHD_destroy_response (internal_error_response);
update_cached_response (NULL);
(void) pthread_mutex_destroy (&mutex);
+ magic_close (magic);
return 0;
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r26703 - in libmicrohttpd: . src/examples,
gnunet <=