libmicrohttpd

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

commit bf1d64a78d084b997718ceba48c30ec1bd2b461a
parent 4856b2cf00d3c90215c8224c62c51c703df7c0fe
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri,  4 Dec 2009 12:17:07 +0000

adding MHD_OPTION_ARRAY

Diffstat:
Mdoc/microhttpd.texi | 39+++++++++++++++++++++++++++++++++++++++
Msrc/daemon/daemon.c | 286++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/include/microhttpd.h | 51++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 298 insertions(+), 78 deletions(-)

diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi @@ -384,10 +384,49 @@ Note that MHD will not generate any log messages if it was compiled without the "--enable-messages" flag being set and the MHD_USE_DEBUG flag being set, even if this argument is used. + +@item MHD_OPTION_ARRAY +@cindex options +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 +option requires a single argument of type 'struct MHD_OptionItem'. +The array must be terminated with an entry @code{MHD_OPTION_END}. + +An example for code using MHD_OPTION_ARRAY is: +@example +struct MHD_OptionItem ops[] = @{ + @{ MHD_OPTION_CONNECTION_LIMIT, 100, NULL @}, + @{ MHD_OPTION_CONNECTION_TIMEOUT, 10, NULL @}, + @{ MHD_OPTION_END, 0, NULL @} +@}; +d = MHD_start_daemon(0, 8080, NULL, NULL, dh, NULL, + MHD_OPTION_ARRAY, ops, + MHD_OPTION_END); +@end example +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}. @end table @end deftp +@deftp {C Struct} MHD_OptionItem +Entry in an MHD_OPTION_ARRAY. See the @code{MHD_OPTION_ARRAY} option +argument for its use. + +The @code{option} member is used to specify which option is specified +in the array. The other members specify the respective argument. + +Note that for options taking only a single pointer, the +@code{ptr_value} member should be set. For options taking two pointer +arguments, the first pointer must be cast to @code{intptr_t} and both +the @code{value} and the @code{ptr_value} members should be used to +pass the two pointers. +@end deftp + + @deftp {Enumeration} MHD_ValueKind The @code{MHD_ValueKind} specifies the source of the key-value pairs in the @http{} protocol. diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c @@ -1141,6 +1141,212 @@ MHD_start_daemon (unsigned int options, typedef void (*VfprintfFunctionPointerType)(void *, const char *, va_list); + +/** + * Parse a list of options given as varargs. + * + * @param daemon the daemon to initialize + * @param ap the options + * @return MHD_YES on success, MHD_NO on error + */ +static int +parse_options_va (struct MHD_Daemon *daemon, + const struct sockaddr **servaddr, + va_list ap); + + +/** + * Parse a list of options given as varargs. + * + * @param daemon the daemon to initialize + * @param ... the options + * @return MHD_YES on success, MHD_NO on error + */ +static int +parse_options (struct MHD_Daemon *daemon, + const struct sockaddr **servaddr, + ...) +{ + va_list ap; + int ret; + + va_start (ap, servaddr); + ret = parse_options_va (daemon, servaddr, ap); + va_end (ap); + return ret; +} + + +/** + * Parse a list of options given as varargs. + * + * @param daemon the daemon to initialize + * @param ap the options + * @return MHD_YES on success, MHD_NO on error + */ +static int +parse_options_va (struct MHD_Daemon *daemon, + const struct sockaddr **servaddr, + va_list ap) +{ + enum MHD_OPTION opt; + struct MHD_OptionItem *oa; + unsigned int i; + + while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION))) + { + switch (opt) + { + case MHD_OPTION_CONNECTION_MEMORY_LIMIT: + daemon->pool_size = va_arg (ap, size_t); + break; + case MHD_OPTION_CONNECTION_LIMIT: + daemon->max_connections = va_arg (ap, unsigned int); + break; + case MHD_OPTION_CONNECTION_TIMEOUT: + daemon->connection_timeout = va_arg (ap, unsigned int); + break; + case MHD_OPTION_NOTIFY_COMPLETED: + daemon->notify_completed = + va_arg (ap, MHD_RequestCompletedCallback); + daemon->notify_completed_cls = va_arg (ap, void *); + break; + case MHD_OPTION_PER_IP_CONNECTION_LIMIT: + daemon->per_ip_connection_limit = va_arg (ap, unsigned int); + break; + case MHD_OPTION_SOCK_ADDR: + *servaddr = va_arg (ap, const struct sockaddr *); + break; + case MHD_OPTION_URI_LOG_CALLBACK: + daemon->uri_log_callback = + va_arg (ap, LogCallback); + daemon->uri_log_callback_cls = va_arg (ap, void *); + break; + case MHD_OPTION_THREAD_POOL_SIZE: + daemon->worker_pool_size = va_arg (ap, unsigned int); + break; +#if HTTPS_SUPPORT + case MHD_OPTION_PROTOCOL_VERSION: + _set_priority (&daemon->priority_cache->protocol, + va_arg (ap, const int *)); + break; + case MHD_OPTION_HTTPS_MEM_KEY: + daemon->https_mem_key = va_arg (ap, const char *); + break; + case MHD_OPTION_HTTPS_MEM_CERT: + daemon->https_mem_cert = va_arg (ap, const char *); + break; + case MHD_OPTION_CIPHER_ALGORITHM: + _set_priority (&daemon->priority_cache->cipher, + va_arg (ap, const int *)); + break; +#endif + case MHD_OPTION_EXTERNAL_LOGGER: +#if HAVE_MESSAGES + daemon->custom_error_log = + va_arg (ap, VfprintfFunctionPointerType); + daemon->custom_error_log_cls = va_arg (ap, void *); +#else + va_arg (ap, VfprintfFunctionPointerType); + va_arg (ap, void *); +#endif + break; + case MHD_OPTION_ARRAY: + oa = va_arg (ap, struct MHD_OptionItem*); + i = 0; + while (MHD_OPTION_END != (opt = oa[i].option)) + { + switch (opt) + { + case MHD_OPTION_END: + abort (); + break; + /* all options taking 'size_t' */ + case MHD_OPTION_CONNECTION_MEMORY_LIMIT: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (size_t) oa[i].value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking 'unsigned int' */ + case MHD_OPTION_CONNECTION_LIMIT: + case MHD_OPTION_CONNECTION_TIMEOUT: + case MHD_OPTION_PER_IP_CONNECTION_LIMIT: + case MHD_OPTION_THREAD_POOL_SIZE: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (unsigned int) oa[i].value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking 'int' or 'enum' */ + case MHD_OPTION_CRED_TYPE: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (int) oa[i].value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking one pointer */ + case MHD_OPTION_SOCK_ADDR: + case MHD_OPTION_HTTPS_MEM_KEY: + case MHD_OPTION_HTTPS_MEM_CERT: + case MHD_OPTION_PROTOCOL_VERSION: + case MHD_OPTION_CIPHER_ALGORITHM: + case MHD_OPTION_ARRAY: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + oa[i].ptr_value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking two pointers */ + case MHD_OPTION_NOTIFY_COMPLETED: + case MHD_OPTION_URI_LOG_CALLBACK: + case MHD_OPTION_EXTERNAL_LOGGER: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (void *) oa[i].value, + oa[i].ptr_value, + MHD_OPTION_END)) + return MHD_NO; + break; + + default: + return MHD_NO; + } + i++; + } + break; + default: +#if HAVE_MESSAGES + if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) && + (opt <= MHD_OPTION_CIPHER_ALGORITHM)) + { + FPRINTF (stderr, + "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n", + opt); + } + else + { + FPRINTF (stderr, + "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n", + opt); + } +#endif + return MHD_NO; + } + } + return MHD_YES; +} + + /** * Start a webserver on the given port. * @@ -1168,7 +1374,6 @@ MHD_start_daemon_va (unsigned int options, #endif const struct sockaddr *servaddr = NULL; socklen_t addrlen; - enum MHD_OPTION opt; unsigned int i; if ((port == 0) || (dh == NULL)) @@ -1215,83 +1420,10 @@ MHD_start_daemon_va (unsigned int options, } #endif - while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION))) + if (MHD_YES != parse_options_va (retVal, &servaddr, ap)) { - switch (opt) - { - case MHD_OPTION_CONNECTION_MEMORY_LIMIT: - retVal->pool_size = va_arg (ap, size_t); - break; - case MHD_OPTION_CONNECTION_LIMIT: - retVal->max_connections = va_arg (ap, unsigned int); - break; - case MHD_OPTION_CONNECTION_TIMEOUT: - retVal->connection_timeout = va_arg (ap, unsigned int); - break; - case MHD_OPTION_NOTIFY_COMPLETED: - retVal->notify_completed = - va_arg (ap, MHD_RequestCompletedCallback); - retVal->notify_completed_cls = va_arg (ap, void *); - break; - case MHD_OPTION_PER_IP_CONNECTION_LIMIT: - retVal->per_ip_connection_limit = va_arg (ap, unsigned int); - break; - case MHD_OPTION_SOCK_ADDR: - servaddr = va_arg (ap, struct sockaddr *); - break; - case MHD_OPTION_URI_LOG_CALLBACK: - retVal->uri_log_callback = - va_arg (ap, LogCallback); - retVal->uri_log_callback_cls = va_arg (ap, void *); - break; - case MHD_OPTION_THREAD_POOL_SIZE: - retVal->worker_pool_size = va_arg (ap, unsigned int); - break; -#if HTTPS_SUPPORT - case MHD_OPTION_PROTOCOL_VERSION: - _set_priority (&retVal->priority_cache->protocol, - va_arg (ap, const int *)); - break; - case MHD_OPTION_HTTPS_MEM_KEY: - retVal->https_mem_key = va_arg (ap, const char *); - break; - case MHD_OPTION_HTTPS_MEM_CERT: - retVal->https_mem_cert = va_arg (ap, const char *); - break; - case MHD_OPTION_CIPHER_ALGORITHM: - _set_priority (&retVal->priority_cache->cipher, - va_arg (ap, const int *)); - break; -#endif - case MHD_OPTION_EXTERNAL_LOGGER: -#if HAVE_MESSAGES - retVal->custom_error_log = - va_arg (ap, VfprintfFunctionPointerType); - retVal->custom_error_log_cls = va_arg (ap, void *); -#else - va_arg (ap, VfprintfFunctionPointerType); - va_arg (ap, void *); -#endif - break; - default: -#if HAVE_MESSAGES - if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) && - (opt <= MHD_OPTION_CIPHER_ALGORITHM)) - { - FPRINTF (stderr, - "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n", - opt); - } - else - { - FPRINTF (stderr, - "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n", - opt); - } -#endif - free (retVal); - return NULL; - } + free (retVal); + return NULL; } /* poll support currently only works with MHD_USE_THREAD_PER_CONNECTION */ diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -453,9 +453,58 @@ enum MHD_OPTION * (MHD_start_daemon returns NULL for an unsupported thread * model). */ - MHD_OPTION_THREAD_POOL_SIZE = 14 + MHD_OPTION_THREAD_POOL_SIZE = 14, + + /** + * Additional options given in an array of "struct MHD_OptionItem". + * The array must be terminated with an entry '{MHD_OPTION_END, 0, NULL}'. + * An example for code using MHD_OPTION_ARRAY is: + * <code> + * struct MHD_OptionItem ops[] = { + * { MHD_OPTION_CONNECTION_LIMIT, 100, NULL }, + * { MHD_OPTION_CONNECTION_TIMEOUT, 10, NULL }, + * { MHD_OPTION_END, 0, NULL } + * }; + * d = MHD_start_daemon(0, 8080, NULL, NULL, dh, NULL, + * MHD_OPTION_ARRAY, ops, + * MHD_OPTION_END); + * </code> + * For options that expect a single pointer argument, the + * second member of the struct MHD_OptionItem is ignored. + * For options that expect two pointer arguments, the first + * argument must be cast to 'intptr_t'. + */ + MHD_OPTION_ARRAY = 15 }; + +/** + * Entry in an MHD_OPTION_ARRAY. + */ +struct MHD_OptionItem +{ + /** + * Which option is being given. Use MHD_OPTION_END + * to terminate the array. + */ + enum MHD_OPTION option; + + /** + * Option value (for integer arguments, and for options requiring + * two pointer arguments); should be 0 for options that take no + * arguments or only a single pointer argument. + */ + intptr_t value; + + /** + * Pointer option value (use NULL for options taking no arguments + * or only an integer option). + */ + void *ptr_value; + +}; + + /** * The MHD_ValueKind specifies the source of * the key-value pairs in the HTTP protocol.