libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit a2da1819c6be4fa6949b13b7156aa34c054d555b
parent 67c412a99c2e974092b69260f2c6525ced3fbd02
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed,  1 Sep 2010 12:01:18 +0000

unescaping and 1494 fix

Diffstat:
MChangeLog | 7+++++++
Mdoc/microhttpd.texi | 44++++++++++++++++++++++++++++++++++++++++++++
Msrc/daemon/connection.c | 12+++++++++---
Msrc/daemon/daemon.c | 7+++++++
Msrc/daemon/internal.c | 13+++++++++++--
Msrc/daemon/internal.h | 41++++++++++++++++++++++++++++++++++++++---
Msrc/daemon/postprocessor.c | 4++--
Msrc/include/microhttpd.h | 47++++++++++++++++++++++++++++++++++++++++++++---
Msrc/include/platform.h | 4++--
9 files changed, 164 insertions(+), 15 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,10 @@ +Wed Sep 1 13:59:16 CEST 2010 + Added ability to specify external unescape function. + "microhttpd.h" now includes the right headers for GNU/Linux + systems unless MHD_PLATFORM_H is defined (in which case it + is assumed that the right headers were already determined by + some configure-like process). -CG + Tue Aug 31 15:39:25 CEST 2010 Fixed bug with missing call to response cleanup in case of connection handling error (for example, after getting a SIGPIPE). -CG diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi @@ -183,6 +183,28 @@ Additionally, clients can specify resource limits on the overall number of connections, number of connections per IP address and memory used per connection to avoid resource exhaustion. +@section Including the microhttpd.h header +@cindex portability +@cindex microhttpd.h + +Ideally, before including "microhttpd.h" you should add the necessary +includes to define the @code{uint64_t}, @code{size_t}, @code{fd_set}, +@code{socklen_t} and @code{struct sockaddr} data types. Which +specific headers are needed may depend on your platform and your build +system might include some tests to provide you with the necessary +conditional operations. For possible suggestions consult +@code{platform.h} and @code{configure.ac} in the MHD distribution. + +Once you have ensured that you manually (!) included the right headers +for your platform before "microhttpd.h", you should also add a line +with @code{#define MHD_PLATFORM_H} which will prevent the +"microhttpd.h" header from trying (and, depending on your platform, +failing) to include the right headers. + +If you do not define MHD_PLATFORM_H, the "microhttpd.h" header will +automatically include headers needed on GNU/Linux systems (possibly +causing problems when porting to other platforms). + @section SIGPIPE @cindex signals @mhd{} does not install a signal handler for SIGPIPE. On platforms @@ -461,6 +483,7 @@ model). @item MHD_OPTION_ARRAY @cindex options +@cindex foreign-function interface This option can be used for initializing MHD using options from an array. A common use for this is writing an FFI for MHD. The actual options given are in an array of 'struct MHD_OptionItem', so this @@ -482,6 +505,27 @@ For options that expect a single pointer argument, the second member of the @code{struct MHD_OptionItem} is ignored. For options that expect two pointer arguments, the first argument must be cast to @code{intptr_t}. + +@item MHD_OPTION_UNESCAPE_CALLBACK +@cindex internationalization +@cindex escaping + +Specify a function that should be called for unescaping escape +sequences in URIs and URI arguments. Note that this function will NOT +be used by the MHD_PostProcessor. If this option is not specified, +the default method will be used which decodes escape sequences of the +form "%HH". This option should be followed by two arguments, the +first one must be of the form + +@example + size_t my_unescaper(void * cls, struct MHD_Connection *c, char *s) +@end example + +where the return value must be @code{strlen(s)} and @code{s} should be +updated. Note that the unescape function must not lengthen @code{s} +(the result must be shorter than the input and still be 0-terminated). +@code{cls} will be set to the second argument following +MHD_OPTION_UNESCAPE_CALLBACK. @end table @end deftp diff --git a/src/daemon/connection.c b/src/daemon/connection.c @@ -1030,8 +1030,12 @@ parse_arguments (enum MHD_ValueKind kind, amper[0] = '\0'; amper++; } - MHD_http_unescape (args); - MHD_http_unescape (equals); + connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, + connection, + args); + connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, + connection, + equals); if (MHD_NO == connection_add_header (connection, args, equals, kind)) return MHD_NO; args = amper; @@ -1172,7 +1176,9 @@ parse_initial_message_line (struct MHD_Connection *connection, char *line) args++; parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args); } - MHD_http_unescape (uri); + connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, + connection, + uri); connection->url = uri; if (httpVersion == NULL) connection->version = ""; diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -1435,6 +1435,7 @@ parse_options_va (struct MHD_Daemon *daemon, case MHD_OPTION_NOTIFY_COMPLETED: case MHD_OPTION_URI_LOG_CALLBACK: case MHD_OPTION_EXTERNAL_LOGGER: + case MHD_OPTION_UNESCAPE_CALLBACK: if (MHD_YES != parse_options (daemon, servaddr, opt, @@ -1450,6 +1451,11 @@ parse_options_va (struct MHD_Daemon *daemon, i++; } break; + case MHD_OPTION_UNESCAPE_CALLBACK: + daemon->unescape_callback = + va_arg (ap, UnescapeCallback); + daemon->unescape_callback_cls = va_arg (ap, void *); + break; default: #if HAVE_MESSAGES if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) && @@ -1526,6 +1532,7 @@ MHD_start_daemon_va (unsigned int options, retVal->default_handler_cls = dh_cls; retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; retVal->pool_size = MHD_POOL_SIZE_DEFAULT; + retVal->unescape_callback = &MHD_http_unescape; retVal->connection_timeout = 0; /* no timeout */ #if HAVE_MESSAGES retVal->custom_error_log = diff --git a/src/daemon/internal.c b/src/daemon/internal.c @@ -110,10 +110,19 @@ MHD_tls_log_func (int level, const char *str) } /** - * Process escape sequences ('+'=space, %HH) + * Process escape sequences ('+'=space, %HH) Updates val in place; the + * result should be UTF-8 encoded and cannot be larger than the input. + * The result must also still be 0-terminated. + * + * @param cls closure (use NULL) + * @param connection handle to connection, not used + * @return length of the resulting val (strlen(val) maybe + * shorter afterwards due to elimination of escape sequences) */ size_t -MHD_http_unescape (char *val) +MHD_http_unescape (void *cls, + struct MHD_Connection *connection, + char *val) { char *rpos = val; char *wpos = val; diff --git a/src/daemon/internal.h b/src/daemon/internal.h @@ -105,13 +105,18 @@ void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...); void MHD_tls_log_func (int level, const char *str); /** - * Process escape sequences ('+'=space, %HH). - * Updates val in place. + * Process escape sequences ('+'=space, %HH) Updates val in place; the + * result should be UTF-8 encoded and cannot be larger than the input. + * The result must also still be 0-terminated. * + * @param cls closure (use NULL) + * @param connection handle to connection, not used * @return length of the resulting val (strlen(val) maybe * shorter afterwards due to elimination of escape sequences) */ -size_t MHD_http_unescape (char *val); +size_t MHD_http_unescape (void *cls, + struct MHD_Connection *connection, + char *val); /** * Header or cookie in HTTP request or response. @@ -666,9 +671,29 @@ struct MHD_Connection #endif }; +/** + * Signature of function called to log URI accesses. + * + * @param cls closure + * @param uri uri being accessed + * @return new closure + */ typedef void * (*LogCallback)(void * cls, const char * uri); /** + * Signature of function called to unescape URIs. See also + * MHD_http_unescape. + * + * @param cls closure + * @param conn connection handle + * @param uri 0-terminated string to unescape (should be updated) + * @return length of the resulting string + */ +typedef size_t (*UnescapeCallback)(void *cls, + struct MHD_Connection *conn, + char *uri); + +/** * State kept for each MHD daemon. */ struct MHD_Daemon @@ -726,6 +751,16 @@ struct MHD_Daemon */ void *uri_log_callback_cls; + /** + * Function to call when we unescape escape sequences. + */ + UnescapeCallback unescape_callback; + + /** + * Closure for unescape callback. + */ + void *unescape_callback_cls; + #if HAVE_MESSAGES /** * Function for logging error messages (if we diff --git a/src/daemon/postprocessor.c b/src/daemon/postprocessor.c @@ -344,7 +344,7 @@ post_process_urlencoded (struct MHD_PostProcessor *pp, return MHD_YES; /* no '=' yet */ buf[pp->buffer_pos] = '\0'; /* 0-terminate key */ pp->buffer_pos = 0; /* reset for next key */ - MHD_http_unescape (buf); + MHD_http_unescape (NULL, NULL, buf); poff += equals + 1; pp->state = PP_ProcessValue; pp->value_offset = 0; @@ -404,7 +404,7 @@ post_process_urlencoded (struct MHD_PostProcessor *pp, /* unescape */ xbuf[xoff] = '\0'; /* 0-terminate in preparation */ - xoff = MHD_http_unescape (xbuf); + xoff = MHD_http_unescape (NULL, NULL, xbuf); /* finally: call application! */ if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1], /* key */ NULL, NULL, NULL, xbuf, pp->value_offset, diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -63,8 +63,10 @@ * includes to define the "uint64_t", "size_t", "fd_set", "socklen_t" * and "struct sockaddr" data types (which headers are needed may * depend on your platform; for possible suggestions consult - * "platform.h" in the MHD distribution). - * + * "platform.h" in the MHD distribution). If you have done so, you + * should also have a line with "#define MHD_PLATFORM_H" which will + * prevent this header from trying (and, depending on your platform, + * failing) to #include the right headers. */ #ifndef MHD_MICROHTTPD_H @@ -78,6 +80,25 @@ extern "C" #endif #endif +/* While we generally would like users to use a configure-driven + build process which detects which headers are present and + hence works on any platform, we use "standard" includes here + to build out-of-the-box for beginning users on common systems. + + Once you have a proper build system and go for more exotic + platforms, you should define MHD_PLATFORM_H in some header that + you always include *before* "microhttpd.h". Then the following + "standard" includes won't be used (which might be a good + idea, especially on platforms where they do not exist). */ +#ifndef MHD_PLATFORM_H +#include <unistd.h> +#include <stdarg.h> +#include <stdint.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#endif + /** * Current version of the library. */ @@ -479,7 +500,27 @@ enum MHD_OPTION * For options that expect two pointer arguments, the first * argument must be cast to 'intptr_t'. */ - MHD_OPTION_ARRAY = 15 + MHD_OPTION_ARRAY = 15, + + /** + * Specify a function that should be called for unescaping escape + * sequences in URIs and URI arguments. Note that this function + * will NOT be used by the MHD_PostProcessor. If this option is + * not specified, the default method will be used which decodes + * escape sequences of the form "%HH". + * This option should be followed by two arguments, the first + * one must be of the form + * <pre> + * size_t my_unescaper(void * cls, struct MHD_Connection *c, char *s) + * </pre> + * where the return value must be "strlen(s)" and + * "s" should be updated. Note that the unescape function + * must not lengthen "s" (the result must be shorter than + * the input and still be 0-terminated). + * "cls" will be set to the second argument following + * MHD_OPTION_UNESCAPE_CALLBACK. + */ + MHD_OPTION_UNESCAPE_CALLBACK = 16 }; diff --git a/src/include/platform.h b/src/include/platform.h @@ -31,8 +31,8 @@ * Hence you cannot include it directly in applications * that use libmicrohttpd. */ -#ifndef PLATFORM_H -#define PLATFORM_H +#ifndef MHD_PLATFORM_H +#define MHD_PLATFORM_H #include "MHD_config.h"