diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h index 7a67fbd3..c69d8731 100644 --- a/src/include/microhttpd2.h +++ b/src/include/microhttpd2.h @@ -1,6 +1,6 @@ /* This file is part of libmicrohttpd - Copyright (C) 2006-2017 Christian Grothoff, Karlson2k (Evgeny Grin) + Copyright (C) 2006-2018 Christian Grothoff, Karlson2k (Evgeny Grin) (and other contributing authors) This library is free software; you can redistribute it and/or @@ -23,8 +23,9 @@ * Note that we do not indicate which of the OLD APIs * simply need to be kept vs. deprecated. * + * * The goal is to provide a basis for discussion! - * None of this is implemented yet. + * Little of this is implemented yet. * * Main goals: * - simplify application callbacks by splitting header/upload/post @@ -64,7 +65,13 @@ * supported (include the descriptive string) by using an enum; * - simplify API for common-case of one-shot responses by * eliminating need for destroy response in most cases; + * + * TODO: + * - varargs in upgrade is still there and ugly (and not even used!) + * - migrate event loop apis (get fdset, timeout, MHD_run(), etc.) */ +#ifndef MICROHTTPD2_H +#define MICROHTTPD2_H /** @@ -1018,8 +1025,8 @@ MHD_daemon_tls_key_and_cert_from_memory (struct MHD_Daemon *daemon, * @return #MHD_SC_OK upon success; TODO: define failure modes */ _MHD_EXTERN enum MHD_StatusCode - MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon, - const char *dh); +MHD_daemon_tls_mem_dhparams (struct MHD_Daemon *daemon, + const char *dh); /** @@ -1356,17 +1363,16 @@ MHD_daemon_digest_auth_nc_length (struct MHD_Daemon *daemon, /** - * Generate option to set a custom timeout for the given connection. - * Specified as the number of seconds. Use zero for no timeout. If - * timeout was set to zero (or unset) before, setting of a new value - * by MHD_connection_set_option() will reset timeout timer. + * Set custom timeout for the given connection. + * Specified as the number of seconds. Use zero for no timeout. + * Calling this function will reset timeout timer. * * @param connection connection to configure timeout for * @param timeout_s new timeout in seconds */ -_MHD_EXTERN struct MHD_ConnectionOption -MHD_connection_timeout (struct MHD_Connection *connection, - unsigned int timeout_s); +_MHD_EXTERN void +MHD_connection_set_timeout (struct MHD_Connection *connection, + unsigned int timeout_s); /* **************** Request handling functions ***************** */ @@ -1792,6 +1798,9 @@ struct MHD_UpgradeResponseHandle; * It allows applications to perform 'special' actions on * the underlying socket from the upgrade. * + * FIXME: this API still uses the untyped, ugly varargs. + * Should we not modernize this one as well? + * * @param urh the handle identifying the connection to perform * the upgrade @a action on. * @param operation which operation should be performed @@ -1987,6 +1996,7 @@ MHD_response_get_header (struct MHD_Response *response, /* ************Upload and PostProcessor functions ********************** */ + /** * Action telling MHD to continue processing the upload. * @@ -2493,3 +2503,6 @@ MHD_daemon_get_information_sz (struct MHD_Daemon *daemon, info_type, \ return_value) \ MHD_daemon_get_information_sz((daemon), (info_type), (return_value), sizeof(union MHD_DaemonInformation)); + + +#endif diff --git a/src/lib/action_continue.c b/src/lib/action_continue.c new file mode 100644 index 00000000..0367f536 --- /dev/null +++ b/src/lib/action_continue.c @@ -0,0 +1,60 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/action_continue.c + * @brief implementation of MHD_action_continue() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * The continue action is being run. Continue + * handling the upload. + * + * @param cls NULL + * @param request the request to apply the action to + */ +static void +cont_action (void *cls, + struct MHD_Request *request) +{ + /* not sure yet, but this function body may + just legitimately stay empty... */ +} + + +/** + * Action telling MHD to continue processing the upload. + * + * @return action operation, never NULL + */ +struct MHD_Action * +MHD_action_continue (void) +{ + static MHD_Action acont = { + .action = &cont_action, + .action_cls = NULL + }; + + return &acont; +} + +/* end of action_continue.c */ diff --git a/src/lib/action_from_response.c b/src/lib/action_from_response.c new file mode 100644 index 00000000..3c13cf42 --- /dev/null +++ b/src/lib/action_from_response.c @@ -0,0 +1,130 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/action_from_response.c + * @brief implementation of #MHD_action_from_response() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * A response was given as the desired action for a @a request. + * Queue the response for the request. + * + * @param cls the `struct MHD_Response` + * @param request the request we are processing + */ +static void +response_action (void *cls, + struct MHD_Request *request) +{ + struct MHD_Response *response = cls; + struct MHD_Daemon *daemon = response->daemon; + + if (daemon->shutdown) + return MHD_YES; /* If daemon was shut down in parallel, + * response will be aborted now or on later stage. */ + +#ifdef UPGRADE_SUPPORT + if ( (NULL != response->upgrade_handler) && + (0 == (daemon->options & MHD_ALLOW_UPGRADE)) ) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (daemon, + _("Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n")); +#endif + return MHD_NO; + } +#endif /* UPGRADE_SUPPORT */ + request->response = response; +#if defined(_MHD_HAVE_SENDFILE) + if ( (-1 == response->fd) +#if HTTPS_SUPPORT + || (NULL != daemon->tls_api) +#endif + ) + request->resp_sender = MHD_resp_sender_std; + else + request->resp_sender = MHD_resp_sender_sendfile; +#endif /* _MHD_HAVE_SENDFILE */ + + if ( ( (NULL != request->method) && + (MHD_str_equal_caseless_ (request->method, + MHD_HTTP_METHOD_HEAD)) ) || + (MHD_HTTP_OK > response->status_code) || + (MHD_HTTP_NO_CONTENT == response->status_code) || + (MHD_HTTP_NOT_MODIFIED == response->status_code) ) + { + /* if this is a "HEAD" request, or a status code for + which a body is not allowed, pretend that we + have already sent the full message body. */ + request->response_write_position = response->total_size; + } + if ( (MHD_REQUEST_HEADERS_PROCESSED == request->state) && + (NULL != connection->method) && + ( (MHD_str_equal_caseless_ (request->method, + MHD_HTTP_METHOD_POST)) || + (MHD_str_equal_caseless_ (request->method, + MHD_HTTP_METHOD_PUT))) ) + { + /* response was queued "early", refuse to read body / footers or + further requests! */ + connection->read_closed = true; + request->state = MHD_CONNECTION_FOOTERS_RECEIVED; + } + if (! request->in_idle) + (void) MHD_connection_handle_idle (connection); +} + + +/** + * Converts a @a response to an action. If @a consume + * is set, the reference to the @a response is consumed + * by the conversion. If @a consume is #MHD_NO, then + * the response can be converted to actions in the future. + * However, the @a response is frozen by this step and + * must no longer be modified (i.e. by setting headers). + * + * @param response response to convert, not NULL + * @param destroy_after_use should the response object be consumed? + * @return corresponding action, never returns NULL + * + * Implementation note: internally, this is largely just + * a cast (and possibly an RC increment operation), + * as a response *is* an action. As no memory is + * allocated, this operation cannot fail. + */ +_MHD_EXTERN struct MHD_Action * +MHD_action_from_response (struct MHD_Response *response, + enum MHD_bool destroy_after_use) +{ + response->action.action = &response_action; + response->action.action_cls = response; + if (! destroy_after_use) + { + MHD_mutex_lock_chk_ (&response->mutex); + response->reference_count++; + MHD_mutex_unlock_chk_ (&response->mutex); + } + return &response->action; +} + +/* end of action_from_response */ diff --git a/src/lib/action_parse_post.c b/src/lib/action_parse_post.c new file mode 100644 index 00000000..202e52f1 --- /dev/null +++ b/src/lib/action_parse_post.c @@ -0,0 +1,61 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/action_parse_post.c + * @brief implementation of MHD_action_parse_post() + * @author Christian Grothoff + */ +#include "internal.h" + + + +/** + * Create an action that parses a POST request. + * + * This action can be used to (incrementally) parse the data portion + * of a POST request. Note that some buggy browsers fail to set the + * encoding type. If you want to support those, you may have to call + * #MHD_set_connection_value with the proper encoding type before + * returning this action (if no supported encoding type is detected, + * returning this action will cause a bad request to be returned to + * the client). + * + * @param buffer_size maximum number of bytes to use for + * internal buffering (used only for the parsing, + * specifically the parsing of the keys). A + * tiny value (256-1024) should be sufficient. + * Do NOT use a value smaller than 256. For good + * performance, use 32 or 64k (i.e. 65536). + * @param iter iterator to be called with the parsed data, + * Must NOT be NULL. + * @param iter_cls first argument to @a iter + * @return NULL on error (out of memory, unsupported encoding), + * otherwise a PP handle + * @ingroup request + */ +struct MHD_Action * +MHD_action_parse_post (size_t buffer_size, + MHD_PostDataIterator iter, + void *iter_cls) +{ + return NULL; /* not yet implemented */ +} + +/* end of action_parse_post.c */ diff --git a/src/lib/action_process_upload.c b/src/lib/action_process_upload.c new file mode 100644 index 00000000..d67b60a1 --- /dev/null +++ b/src/lib/action_process_upload.c @@ -0,0 +1,92 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/action_process_upload.c + * @brief implementation of MHD_action_process_upload() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Internal details about an upload action. + */ +struct UploadAction +{ + /** + * An upload action is an action. This field + * must come first! + */ + struct MHD_Action action; + + MHD_UploadCallback uc; + + void *uc_cls; + +}; + + +/** + * The application wants to process uploaded data for + * the given request. Do it! + * + * @param cls the `struct UploadAction` with the + * function we are to call for upload data + * @param request the request for which we are to process + * upload data + */ +static void +upload_action (void *cls, + struct MHD_Request *request) +{ + struct UploadAction *ua = cls; + + (void) ua; + // FIXME: implement! +} + + +/** + * Create an action that handles an upload. + * + * @param uc function to call with uploaded data + * @param uc_cls closure for @a uc + * @return NULL on error (out of memory) + * @ingroup action + */ +struct MHD_Action * +MHD_action_process_upload (MHD_UploadCallback uc, + void *uc_cls) +{ + struct UploadAction *ua; + + if (NULL == (ua = malloc (sizeof (struct UploadAction)))) + return NULL; + ua->action = &upload_action; + ua->action_cls = ua; + ua->uc = uc; + ua->uc_cls = uc_cls; + return ua; +} + + +/* end of action_process_upload.c */ + + diff --git a/src/lib/action_suspend.c b/src/lib/action_suspend.c new file mode 100644 index 00000000..8327992d --- /dev/null +++ b/src/lib/action_suspend.c @@ -0,0 +1,132 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/action_suspend.c + * @brief implementation of MHD_action_suspend() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * The suspend action is being run. Suspend handling + * of the given request. + * + * @param cls NULL + * @param request the request to apply the action to + */ +static void +suspend_action (void *cls, + struct MHD_Request *request) +{ + struct MHD_Daemon *daemon = connection->daemon; + + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + if (connection->resuming) + { + /* suspending again while we didn't even complete resuming yet */ + connection->resuming = false; + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); + return; + } + if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + { + if (connection->connection_timeout == daemon->connection_timeout) + XDLL_remove (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + else + XDLL_remove (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + connection); + } + DLL_remove (daemon->connections_head, + daemon->connections_tail, + connection); + mhd_assert (! connection->suspended); + DLL_insert (daemon->suspended_connections_head, + daemon->suspended_connections_tail, + connection); + connection->suspended = true; +#ifdef EPOLL_SUPPORT + if (MHD_ELS_EPOLL == daemon->event_loop_syscall) + { + if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)) + { + EDLL_remove (daemon->eready_head, + daemon->eready_tail, + connection); + connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EREADY_EDLL; + } + if (0 != (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) + { + if (0 != epoll_ctl (daemon->epoll_fd, + EPOLL_CTL_DEL, + connection->socket_fd, + NULL)) + MHD_PANIC (_("Failed to remove FD from epoll set\n")); + connection->epoll_state &= ~MHD_EPOLL_STATE_IN_EPOLL_SET; + } + connection->epoll_state |= MHD_EPOLL_STATE_SUSPENDED; + } +#endif + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); +} + + +/** + * Suspend handling of network data for a given request. This can + * be used to dequeue a request from MHD's event loop for a while. + * + * If you use this API in conjunction with a internal select or a + * thread pool, you must set the option #MHD_USE_ITC to + * ensure that a resumed request is immediately processed by MHD. + * + * Suspended requests continue to count against the total number of + * requests allowed (per daemon, as well as per IP, if such limits + * are set). Suspended requests will NOT time out; timeouts will + * restart when the request handling is resumed. While a + * request is suspended, MHD will not detect disconnects by the + * client. + * + * The only safe time to suspend a request is from either a + * #MHD_RequestHeaderCallback, #MHD_UploadCallback, or a + * #MHD_RequestfetchResponseCallback. Suspending a request + * at any other time will cause an assertion failure. + * + * Finally, it is an API violation to call #MHD_daemon_stop() while + * having suspended requests (this will at least create memory and + * socket leaks or lead to undefined behavior). You must explicitly + * resume all requests before stopping the daemon. + * + * @return action to cause a request to be suspended. + */ +struct MHD_Action * +MHD_action_suspend (void) +{ + static MHD_Action suspend = { + .action = &suspend_action, + .action_cls = NULL + }; + + return &suspend; +} + +/* end of action_suspend.c */ diff --git a/src/lib/connection_info.c b/src/lib/connection_info.c new file mode 100644 index 00000000..a4337679 --- /dev/null +++ b/src/lib/connection_info.c @@ -0,0 +1,52 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/connection_info.c + * @brief implementation of MHD_connection_get_information_sz() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Obtain information about the given connection. + * Use wrapper macro #MHD_connection_get_information() instead of direct use + * of this function. + * + * @param connection what connection to get information about + * @param info_type what information is desired? + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size size of union MHD_ConnectionInformation at compile + * time + * @return #MHD_YES on success, #MHD_NO on error + * (@a info_type is unknown, NULL pointer etc.) + * @ingroup specialized + */ +enum MHD_Bool +MHD_connection_get_information_sz (struct MHD_Connection *connection, + enum MHD_ConnectionInformationType info_type, + union MHD_ConnectionInformation *return_value, + size_t return_value_size) +{ + return MHD_NO; /* FIXME: not yet implemented */ +} + +/* end of connection_info.c */ diff --git a/src/lib/connection_options.c b/src/lib/connection_options.c index 163c956a..24301ddf 100644 --- a/src/lib/connection_options.c +++ b/src/lib/connection_options.c @@ -1,16 +1,113 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ /** - * Generate option to set a custom timeout for the given connection. - * Specified as the number of seconds. Use zero for no timeout. If - * timeout was set to zero (or unset) before, setting of a new value - * by MHD_connection_set_option() will reset timeout timer. + * @file lib/connection_options.c + * @brief functions to set per-connection options + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Set custom timeout for the given connection. Specified as the + * number of seconds. Use zero for no timeout. Calling this function + * will reset timeout timer. * * @param connection connection to configure timeout for * @param timeout_s new timeout in seconds */ -struct MHD_ConnectionOption -MHD_connection_timeout (struct MHD_Connection *connection, - unsigned int timeout_s); +void +MHD_connection_set_timeout (struct MHD_Connection *connection, + unsigned int timeout_s) +{ + struct MHD_Daemon *daemon = connection->daemon; + + connection->last_activity = MHD_monotonic_sec_counter(); + if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model) + { + /* Simple case, no need to lock to update DLLs */ + connection->connection_timeout = (time_t) timeout_s; + return; + } + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + if (! connection->suspended) + { + if (connection->connection_timeout == daemon->connection_timeout) + XDLL_remove (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + else + XDLL_remove (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + connection); + } + connection->connection_timeout = (time_t) timeout_s; + if (! connection->suspended) + { + if (connection->connection_timeout == daemon->connection_timeout) + XDLL_insert (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + else + XDLL_insert (daemon->manual_timeout_head, + daemon->manual_timeout_tail, + connection); + } + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); +} +/** + * Update the 'last_activity' field of the connection to the current + * time and move the connection to the head of the 'normal_timeout' + * list if the timeout for the connection uses the default value. + * + * @param connection the connection that saw some activity + */ +void +MHD_update_last_activity_ (struct MHD_Connection *connection) +{ + struct MHD_Daemon *daemon = connection->daemon; + if (0 == connection->connection_timeout) + return; /* Skip update of activity for connections + without timeout timer. */ + if (connection->suspended) + return; /* no activity on suspended connections */ + + connection->last_activity = MHD_monotonic_sec_counter(); + if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model) + return; /* each connection has personal timeout */ + + if (connection->connection_timeout != daemon->connection_timeout) + return; /* custom timeout, no need to move it in "normal" DLL */ + + MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex); + /* move connection to head of timeout list (by remove + add operation) */ + XDLL_remove (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + XDLL_insert (daemon->normal_timeout_head, + daemon->normal_timeout_tail, + connection); + MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex); +} + +/* end of connection_options.c */ diff --git a/src/lib/daemon_info.c b/src/lib/daemon_info.c index b724094d..47009687 100644 --- a/src/lib/daemon_info.c +++ b/src/lib/daemon_info.c @@ -1,20 +1,52 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ /** - * Obtain information about the given daemon - * (not fully implemented!). + * @file lib/daemon_info.c + * @brief implementation of MHD_daemon_get_information_sz() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Obtain information about the given daemon. + * Use wrapper macro #MHD_daemon_get_information() instead of direct use + * of this function. * * @param daemon what daemon to get information about * @param info_type what information is desired? - * @param ... depends on @a info_type - * @return NULL if this information is not available - * (or if the @a info_type is unknown) + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size size of union MHD_DaemonInformation at compile + * time + * @return #MHD_YES on success, #MHD_NO on error + * (@a info_type is unknown, NULL pointer etc.) * @ingroup specialized */ -const union MHD_DaemonInfo * -MHD_get_daemon_info (struct MHD_Daemon *daemon, - enum MHD_DaemonInfoType info_type, - ...) +enum MHD_Bool +MHD_daemon_get_information_sz (struct MHD_Daemon *daemon, + enum MHD_DaemonInformationType info_type, + union MHD_DaemonInformation *return_value, + size_t return_value_size) { +#if OLD if (NULL == daemon) return NULL; switch (info_type) @@ -55,6 +87,9 @@ MHD_get_daemon_info (struct MHD_Daemon *daemon, default: return NULL; } +#else + return MHD_NO; +#endif } - +/* end of daemon_info.c */ diff --git a/src/lib/daemon.c b/src/lib/daemon_start.c similarity index 99% rename from src/lib/daemon.c rename to src/lib/daemon_start.c index 2973dd2e..51c48a28 100644 --- a/src/lib/daemon.c +++ b/src/lib/daemon_start.c @@ -19,7 +19,7 @@ /** * @file lib/daemon.c - * @brief main functions to start a daemon + * @brief functions to start a daemon * @author Christian Grothoff */ #include "internal.h" @@ -642,8 +642,8 @@ setup_thread_pool (struct MHD_Daemon *daemon) enum MHD_StatusCode sc; /* Allocate memory for pooled objects */ - daemon->worker_pool = calloc (daemon->threading_model, - sizeof (struct MHD_Daemon)); + daemon->worker_pool = MHD_calloc_ (daemon->threading_model, + sizeof (struct MHD_Daemon)); if (NULL == daemon->worker_pool) return MHD_SC_THREAD_POOL_MALLOC_FAILURE; diff --git a/src/lib/init.c b/src/lib/init.c index d7a6faa1..d7ba332d 100644 --- a/src/lib/init.c +++ b/src/lib/init.c @@ -1,3 +1,28 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/init.c + * @brief initialization routines + * @author Christian Grothoff + */ +#include "internal.h" #include "init.h" diff --git a/src/lib/init.h b/src/lib/init.h index 25243c17..f64f9b51 100644 --- a/src/lib/init.h +++ b/src/lib/init.h @@ -1,3 +1,28 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/init.h + * @brief functions to initialize library + * @author Christian Grothoff + */ +#include "internal.h" #ifndef INIT_H diff --git a/src/lib/internal.h b/src/lib/internal.h index c14d96eb..f5df8ce2 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -561,12 +561,6 @@ struct MHD_Request */ enum MHD_RequestEventLoopInfo event_loop_info; - /** - * HTTP response code. Only valid if response object - * is already set. - */ - unsigned int responseCode; - /** * Did we ever call the "default_handler" on this request? (this * flag will determine if we call the #MHD_OPTION_NOTIFY_COMPLETED @@ -594,16 +588,6 @@ struct MHD_Request * be set to #MHD_NO again (before the final call to the handler). */ bool have_chunked_upload; - - /** - * Is the request suspended? - */ - bool suspended; - - /** - * Is the request wanting to resume? - */ - bool resuming; }; @@ -660,6 +644,15 @@ struct MHD_Connection */ struct MHD_Request request; + /** + * Is the connection suspended? + */ + bool suspended; + + /** + * Is the connection wanting to resume? + */ + bool resuming; /** * Set to `true` if the thread has been joined. @@ -679,8 +672,7 @@ struct MHD_Connection */ bool read_closed; - - /** + /** * Length of the foreign address. */ socklen_t addr_len; @@ -998,13 +990,167 @@ struct MHD_Daemon */ bool allow_address_reuse; + +}; + + +/** + * Action function implementing some action to be + * performed on a request. + * + * @param cls action-specfic closure + * @param request the request on which the action is to be performed + */ +typedef void +(*ActionCallback) (void *cls, + const struct MHD_Request *request); + + +/** + * Actions are returned by the application to drive the request + * handling of MHD. + */ +struct MHD_Action +{ + + /** + * Function to call for the action. + */ + ActionCallback action; + + /** + * Closure for @a action + */ + void *action_cls; +}; + + +/** + * Representation of an HTTP response. + */ +struct MHD_Response +{ + + /** + * A response *is* an action. See also + * #MHD_action_from_response(). Hence this field + * must be the first field in a response! + */ + struct MHD_Action action; + + /** + * Headers to send for the response. Initially + * the linked list is created in inverse order; + * the order should be inverted before sending! + */ + struct MHD_HTTP_Header *first_header; + + /** + * Buffer pointing to data that we are supposed + * to send as a response. + */ + char *data; + + /** + * Closure to give to the content reader @e crc + * and content reader free callback @e crfc. + */ + void *crc_cls; + + /** + * How do we get more data? NULL if we are + * given all of the data up front. + */ + MHD_ContentReaderCallback crc; + + /** + * NULL if data must not be freed, otherwise + * either user-specified callback or "&free". + */ + MHD_ContentReaderFreeCallback crfc; + + /** + * Function to call once MHD is finished with + * the request, may be NULL. + */ + MHD_RequestTerminationCallback termination_cb; + + /** + * Closure for @e termination_cb. + */ + void *termination_cb_cls; + +#ifdef UPGRADE_SUPPORT + /** + * Application function to call once we are done sending the headers + * of the response; NULL unless this is a response created with + * #MHD_create_response_for_upgrade(). + */ + MHD_UpgradeHandler upgrade_handler; + + /** + * Closure for @e uh. + */ + void *upgrade_handler_cls; +#endif /* UPGRADE_SUPPORT */ + + /** + * Mutex to synchronize access to @e data, @e size and + * @e reference_count. + */ + MHD_mutex_ mutex; + + /** + * Set to #MHD_SIZE_UNKNOWN if size is not known. + */ + uint64_t total_size; + + /** + * At what offset in the stream is the + * beginning of @e data located? + */ + uint64_t data_start; + + /** + * Offset to start reading from when using @e fd. + */ + uint64_t fd_off; + + /** + * Number of bytes ready in @e data (buffer may be larger + * than what is filled with payload). + */ + size_t data_size; + + /** + * Size of the data buffer @e data. + */ + size_t data_buffer_size; + + /** + * HTTP status code of the response. + */ + enum MHD_HTTP_StatusCode status_code; + + /** + * Reference count for this response. Free once the counter hits + * zero. + */ + unsigned int reference_count; + + /** + * File-descriptor if this response is FD-backed. + */ + int fd; + + /** + * Only respond in HTTP 1.0 mode. + */ + bool v10_only; }; - - - #endif diff --git a/src/lib/panic.c b/src/lib/panic.c index f3cfe82d..0c2c7940 100644 --- a/src/lib/panic.c +++ b/src/lib/panic.c @@ -1,3 +1,28 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/panic.c + * @brief functions to panic (abort) + * @author Christian Grothoff + */ +#include "internal.h" /** diff --git a/src/lib/request_info.c b/src/lib/request_info.c new file mode 100644 index 00000000..4a903ef0 --- /dev/null +++ b/src/lib/request_info.c @@ -0,0 +1,53 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/request_info.c + * @brief implementation of MHD_request_get_information_sz() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Obtain information about the given request. + * Use wrapper macro #MHD_request_get_information() instead of direct use + * of this function. + * + * @param request what request to get information about + * @param info_type what information is desired? + * @param[out] return_value pointer to union where requested information will + * be stored + * @param return_value_size size of union MHD_RequestInformation at compile + * time + * @return #MHD_YES on success, #MHD_NO on error + * (@a info_type is unknown, NULL pointer etc.) + * @ingroup specialized + */ +enum MHD_Bool +MHD_request_get_information_sz (struct MHD_Request *request, + enum MHD_RequestInformationType info_type, + union MHD_RequestInformation *return_value, + size_t return_value_size) +{ + return MHD_NO; /* not implemented */ +} + + +/* end of request_info.c */ diff --git a/src/lib/request_resume.c b/src/lib/request_resume.c new file mode 100644 index 00000000..cd642580 --- /dev/null +++ b/src/lib/request_resume.c @@ -0,0 +1,48 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/request_resume.c + * @brief implementation of MHD_request_resume() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Resume handling of network data for suspended request. It is + * safe to resume a suspended request at any time. Calling this + * function on a request that was not previously suspended will + * result in undefined behavior. + * + * If you are using this function in ``external'' select mode, you must + * make sure to run #MHD_run() afterwards (before again calling + * #MHD_get_fdset(), as otherwise the change may not be reflected in + * the set returned by #MHD_get_fdset() and you may end up with a + * request that is stuck until the next network activity. + * + * @param request the request to resume + */ +void +MHD_request_resume (struct MHD_Request *request) +{ + abort (); // not implemented... +} + +/* end of request_resume.c */ diff --git a/src/lib/response.c b/src/lib/response.c new file mode 100644 index 00000000..25943883 --- /dev/null +++ b/src/lib/response.c @@ -0,0 +1,264 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/response.c + * @brief implementation of general response functions + * @author Daniel Pittman + * @author Christian Grothoff + * @author Karlson2k (Evgeny Grin) + */ +#include "internal.h" + + +/** + * Add a header or footer line to the response. + * + * @param response response to add a header to + * @param kind header or footer + * @param header the header to add + * @param content value to add + * @return false on error (i.e. invalid header or content format). + */ +static bool +add_response_entry (struct MHD_Response *response, + enum MHD_ValueKind kind, + const char *header, + const char *content) +{ + struct MHD_HTTP_Header *hdr; + + if ( (NULL == header) || + (NULL == content) || + (0 == header[0]) || + (0 == content[0]) || + (NULL != strchr (header, '\t')) || + (NULL != strchr (header, '\r')) || + (NULL != strchr (header, '\n')) || + (NULL != strchr (content, '\t')) || + (NULL != strchr (content, '\r')) || + (NULL != strchr (content, '\n')) ) + return false; + if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header)))) + return false; + if (NULL == (hdr->header = strdup (header))) + { + free (hdr); + return false; + } + if (NULL == (hdr->value = strdup (content))) + { + free (hdr->header); + free (hdr); + return false; + } + hdr->kind = kind; + hdr->next = response->first_header; + response->first_header = hdr; + return true; +} + + +/** + * Explicitly decrease reference counter of a response object. If the + * counter hits zero, destroys a response object and associated + * resources. Usually, this is implicitly done by converting a + * response to an action and returning the action to MHD. + * + * @param response response to decrement RC of + * @ingroup response + */ +void +MHD_response_queue_for_destroy (struct MHD_Response *response) +{ + struct MHD_HTTP_Header *pos; + + MHD_mutex_lock_chk_ (&response->mutex); + if (0 != --(response->reference_count)) + { + MHD_mutex_unlock_chk_ (&response->mutex); + return; + } + MHD_mutex_unlock_chk_ (&response->mutex); + MHD_mutex_destroy_chk_ (&response->mutex); + if (NULL != response->crfc) + response->crfc (response->crc_cls); + while (NULL != response->first_header) + { + pos = response->first_header; + response->first_header = pos->next; + free (pos->header); + free (pos->value); + free (pos); + } + free (response); +} + + +/** + * Add a header line to the response. + * + * @param response response to add a header to + * @param header the header to add + * @param content value to add + * @return #MHD_NO on error (i.e. invalid header or content format), + * or out of memory + * @ingroup response + */ +enum MHD_Bool +MHD_response_add_header (struct MHD_Response *response, + const char *header, + const char *content) +{ + return add_response_entry (response, + MHD_HEADER_KIND, + header, + content) ? MHD_TRUE : MHD_FALSE; +} + + +/** + * Add a tailer line to the response. + * + * @param response response to add a footer to + * @param footer the footer to add + * @param content value to add + * @return #MHD_NO on error (i.e. invalid footer or content format), + * or out of memory + * @ingroup response + */ +enum MHD_Bool +MHD_response_add_trailer (struct MHD_Response *response, + const char *footer, + const char *content) +{ + return add_response_entry (response, + MHD_FOOTER_KIND, + footer, + content) ? MHD_TRUE : MHD_FALSE; +} + + +/** + * Delete a header (or footer) line from the response. + * + * @param response response to remove a header from + * @param header the header to delete + * @param content value to delete + * @return #MHD_NO on error (no such header known) + * @ingroup response + */ +enum MHD_Bool +MHD_response_del_header (struct MHD_Response *response, + const char *header, + const char *content) +{ + struct MHD_HTTP_Header *pos; + struct MHD_HTTP_Header *prev; + + if ( (NULL == header) || + (NULL == content) ) + return MHD_NO; + prev = NULL; + pos = response->first_header; + while (NULL != pos) + { + if ((0 == strcmp (header, + pos->header)) && + (0 == strcmp (content, + pos->value))) + { + free (pos->header); + free (pos->value); + if (NULL == prev) + response->first_header = pos->next; + else + prev->next = pos->next; + free (pos); + return MHD_YES; + } + prev = pos; + pos = pos->next; + } + return MHD_NO; +} + + +/** + * Get all of the headers (and footers) added to a response. + * + * @param response response to query + * @param iterator callback to call on each header; + * maybe NULL (then just count headers) + * @param iterator_cls extra argument to @a iterator + * @return number of entries iterated over + * @ingroup response + */ +unsigned int +MHD_response_get_headers (struct MHD_Response *response, + MHD_KeyValueIterator iterator, + void *iterator_cls) +{ + unsigned int numHeaders = 0; + struct MHD_HTTP_Header *pos; + + for (pos = response->first_header; + NULL != pos; + pos = pos->next) + { + numHeaders++; + if ( (NULL != iterator) && + (MHD_YES != iterator (iterator_cls, + pos->kind, + pos->header, + pos->value)) ) + break; + } + return numHeaders; +} + + +/** + * Get a particular header (or footer) from the response. + * + * @param response response to query + * @param key which header to get + * @return NULL if header does not exist + * @ingroup response + */ +const char * +MHD_response_get_header (struct MHD_Response *response, + const char *key) +{ + struct MHD_HTTP_Header *pos; + + if (NULL == key) + return NULL; + for (pos = response->first_header; + NULL != pos; + pos = pos->next) + { + if (MHD_str_equal_caseless_ (pos->header, + key)) + return pos->value; + } + return NULL; +} + +/* end of response.c */ diff --git a/src/lib/response_for_upgrade.c b/src/lib/response_for_upgrade.c new file mode 100644 index 00000000..90e361b6 --- /dev/null +++ b/src/lib/response_for_upgrade.c @@ -0,0 +1,90 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/response_for_upgrade.c + * @brief implementation of MHD_response_for_upgrade() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Create a response object that can be used for 101 UPGRADE + * responses, for example to implement WebSockets. After sending the + * response, control over the data stream is given to the callback (which + * can then, for example, start some bi-directional communication). + * If the response is queued for multiple connections, the callback + * will be called for each connection. The callback + * will ONLY be called after the response header was successfully passed + * to the OS; if there are communication errors before, the usual MHD + * connection error handling code will be performed. + * + * MHD will automatically set the correct HTTP status + * code (#MHD_HTTP_SWITCHING_PROTOCOLS). + * Setting correct HTTP headers for the upgrade must be done + * manually (this way, it is possible to implement most existing + * WebSocket versions using this API; in fact, this API might be useful + * for any protocol switch, not just WebSockets). Note that + * draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this + * way as the header "HTTP/1.1 101 WebSocket Protocol Handshake" + * cannot be generated; instead, MHD will always produce "HTTP/1.1 101 + * Switching Protocols" (if the response code 101 is used). + * + * As usual, the response object can be extended with header + * information and then be used any number of times (as long as the + * header information is not connection-specific). + * + * @param upgrade_handler function to call with the "upgraded" socket + * @param upgrade_handler_cls closure for @a upgrade_handler + * @return NULL on error (i.e. invalid arguments, out of memory) + */ +struct MHD_Response * +MHD_response_for_upgrade (MHD_UpgradeHandler upgrade_handler, + void *upgrade_handler_cls) +{ + struct MHD_Response *response; + + mhd_assert (NULL != upgrade_handler); + response = MHD_calloc_ (1, + sizeof (struct MHD_Response)); + if (NULL == response) + return NULL; + if (! MHD_mutex_init_ (&response->mutex)) + { + free (response); + return NULL; + } + response->upgrade_handler = upgrade_handler; + response->upgrade_handler_cls = upgrade_handler_cls; + response->status_code = MHD_HTTP_SWITCHING_PROTOCOLS; + response->total_size = MHD_SIZE_UNKNOWN; + response->reference_count = 1; + if (MHD_NO == + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONNECTION, + "Upgrade")) + { + MHD_destroy_response (response); + return NULL; + } + return response; +} + +/* end of response_for_upgrade.c */ diff --git a/src/lib/response_from_buffer.c b/src/lib/response_from_buffer.c new file mode 100644 index 00000000..be6a1e00 --- /dev/null +++ b/src/lib/response_from_buffer.c @@ -0,0 +1,88 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/response_from_buffer.c + * @brief implementation of MHD_response_from_buffer() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Create a response object. The response object can be extended with + * header information and then be used any number of times. + * + * @param sc status code to use for the response; + * #MHD_HTTP_NO_CONTENT is only valid if @a size is 0; + * @param size size of the data portion of the response + * @param buffer size bytes containing the response's data portion + * @param mode flags for buffer management + * @return NULL on error (i.e. invalid arguments, out of memory) + * @ingroup response + */ +struct MHD_Response * +MHD_response_from_buffer (enum MHD_HTTP_StatusCode sc, + size_t size, + void *buffer, + enum MHD_ResponseMemoryMode mode) +{ + struct MHD_Response *response; + void *tmp; + + mhd_assert ( (NULL != data) || + (0 == size) ); + if (NULL == + (response = MHD_calloc_ (1, + sizeof (struct MHD_Response)))) + return NULL; + response->fd = -1; + if (! MHD_mutex_init_ (&response->mutex)) + { + free (response); + return NULL; + } + if ( (MHD_RESPMEM_MUST_COPY == mode) && + (size > 0) ) + { + if (NULL == (tmp = malloc (size))) + { + MHD_mutex_destroy_chk_ (&response->mutex); + free (response); + return NULL; + } + memcpy (tmp, + data, + size); + data = tmp; + } + if (MHD_RESPMEM_PERSISTENT != mode) + { + response->crfc = &free; + response->crc_cls = data; + } + response->status_code = sc; + response->reference_count = 1; + response->total_size = size; + response->data = data; + response->data_size = size; + return response; +} + +/* end of response_from_buffer.c */ diff --git a/src/lib/response_from_callback.c b/src/lib/response_from_callback.c new file mode 100644 index 00000000..1fd65bf0 --- /dev/null +++ b/src/lib/response_from_callback.c @@ -0,0 +1,80 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/response_from_callback.c + * @brief implementation of MHD_response_from_callback() + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Create a response action. The response object can be extended with + * header information and then be used any number of times. + * + * @param sc status code to return + * @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown + * @param block_size preferred block size for querying crc (advisory only, + * MHD may still call @a crc using smaller chunks); this + * is essentially the buffer size used for IO, clients + * should pick a value that is appropriate for IO and + * memory performance requirements + * @param crc callback to use to obtain response data + * @param crc_cls extra argument to @a crc + * @param crfc callback to call to free @a crc_cls resources + * @return NULL on error (i.e. invalid arguments, out of memory) + * @ingroup response + */ +struct MHD_Response * +MHD_response_from_callback (enum MHD_HTTP_StatusCode sc, + uint64_t size, + size_t block_size, + MHD_ContentReaderCallback crc, + void *crc_cls, + MHD_ContentReaderFreeCallback crfc) +{ + struct MHD_Response *response; + + mhd_assert (NULL != crc); + mhd_assert (0 != block_size); + if (NULL == + (response = MHD_calloc_ (1, + sizeof (struct MHD_Response) + + block_size))) + return NULL; + response->fd = -1; + response->status_code = sc; + response->data = (void *) &response[1]; + response->data_buffer_size = block_size; + if (! MHD_mutex_init_ (&response->mutex)) + { + free (response); + return NULL; + } + response->crc = crc; + response->crfc = crfc; + response->crc_cls = crc_cls; + response->reference_count = 1; + response->total_size = size; + return response; +} + + +/* end of response_from_callback.c */ diff --git a/src/lib/response_from_fd.c b/src/lib/response_from_fd.c new file mode 100644 index 00000000..ea486600 --- /dev/null +++ b/src/lib/response_from_fd.c @@ -0,0 +1,198 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/response_from_fd.c + * @brief implementation of MHD_response_from_fd() + * @author Daniel Pittman + * @author Christian Grothoff + * @author Karlson2k (Evgeny Grin) + */ +#include "internal.h" + + +/** + * Given a file descriptor, read data from the file + * to generate the response. + * + * @param cls pointer to the response + * @param pos offset in the file to access + * @param buf where to write the data + * @param max number of bytes to write at most + * @return number of bytes written + */ +static ssize_t +file_reader (void *cls, + uint64_t pos, + char *buf, + size_t max) +{ + struct MHD_Response *response = cls; +#if !defined(_WIN32) || defined(__CYGWIN__) + ssize_t n; +#else /* _WIN32 && !__CYGWIN__ */ + const HANDLE fh = (HANDLE) _get_osfhandle (response->fd); +#endif /* _WIN32 && !__CYGWIN__ */ + const int64_t offset64 = (int64_t)(pos + response->fd_off); + + if (offset64 < 0) + return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */ + +#if !defined(_WIN32) || defined(__CYGWIN__) + if (max > SSIZE_MAX) + max = SSIZE_MAX; /* Clamp to maximum return value. */ + +#if defined(HAVE_PREAD64) + n = pread64 (response->fd, + buf, + max, + offset64); +#elif defined(HAVE_PREAD) + if ( (sizeof(off_t) < sizeof (uint64_t)) && + (offset64 > (uint64_t)INT32_MAX) ) + return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */ + + n = pread (response->fd, + buf, + max, + (off_t) offset64); +#else /* ! HAVE_PREAD */ +#if defined(HAVE_LSEEK64) + if (lseek64 (response->fd, + offset64, + SEEK_SET) != offset64) + return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */ +#else /* ! HAVE_LSEEK64 */ + if ( (sizeof(off_t) < sizeof (uint64_t)) && + (offset64 > (uint64_t)INT32_MAX) ) + return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */ + + if (lseek (response->fd, + (off_t) offset64, + SEEK_SET) != (off_t) offset64) + return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */ +#endif /* ! HAVE_LSEEK64 */ + n = read (response->fd, + buf, + max); + +#endif /* ! HAVE_PREAD */ + if (0 == n) + return MHD_CONTENT_READER_END_OF_STREAM; + if (n < 0) + return MHD_CONTENT_READER_END_WITH_ERROR; + return n; +#else /* _WIN32 && !__CYGWIN__ */ + if (INVALID_HANDLE_VALUE == fh) + return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */ + else + { + OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */ + ULARGE_INTEGER pos_uli; + DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max; + DWORD resRead; + + pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */ + f_ol.Offset = pos_uli.LowPart; + f_ol.OffsetHigh = pos_uli.HighPart; + if (! ReadFile (fh, + (void*)buf, + toRead, + &resRead, + &f_ol)) + return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */ + if (0 == resRead) + return MHD_CONTENT_READER_END_OF_STREAM; + return (ssize_t) resRead; + } +#endif /* _WIN32 && !__CYGWIN__ */ +} + + +/** + * Destroy file reader context. Closes the file + * descriptor. + * + * @param cls pointer to file descriptor + */ +static void +free_callback (void *cls) +{ + struct MHD_Response *response = cls; + + (void) close (response->fd); + response->fd = -1; +} + + +/** + * Create a response object based on an @a fd from which + * data is read. The response object can be extended with + * header information and then be used any number of times. + * + * @param sc status code to return + * @param fd file descriptor referring to a file on disk with the + * data; will be closed when response is destroyed; + * fd should be in 'blocking' mode + * @param offset offset to start reading from in the file; + * reading file beyond 2 GiB may be not supported by OS or + * MHD build; see ::MHD_FEATURE_LARGE_FILE + * @param size size of the data portion of the response; + * sizes larger than 2 GiB may be not supported by OS or + * MHD build; see ::MHD_FEATURE_LARGE_FILE + * @return NULL on error (i.e. invalid arguments, out of memory) + * @ingroup response + */ +struct MHD_Response * +MHD_response_from_fd (enum MHD_HTTP_StatusCode sc, + int fd, + uint64_t offset, + uint64_t size) +{ + struct MHD_Response *response; + + mhd_assert (-1 != fd); +#if !defined(HAVE___LSEEKI64) && !defined(HAVE_LSEEK64) + if ( (sizeof (uint64_t) > sizeof (off_t)) && + ( (size > (uint64_t)INT32_MAX) || + (offset > (uint64_t)INT32_MAX) || + ((size + offset) >= (uint64_t)INT32_MAX) ) ) + return NULL; +#endif + if ( ((int64_t) size < 0) || + ((int64_t) offset < 0) || + ((int64_t) (size + offset) < 0) ) + return NULL; + + response = MHD_response_from_callback (size, + 4 * 1024, + &file_reader, + NULL, + &free_callback); + if (NULL == response) + return NULL; + response->fd = fd; + response->status_code = sc; + response->fd_off = offset; + response->crc_cls = response; + return response; +} + +/* end of response_from_fd.c */ + diff --git a/src/lib/response_options.c b/src/lib/response_options.c new file mode 100644 index 00000000..406d1d32 --- /dev/null +++ b/src/lib/response_options.c @@ -0,0 +1,61 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/response_option.c + * @brief implementation of response options + * @author Christian Grothoff + */ +#include "internal.h" + + +/** + * Only respond in conservative HTTP 1.0-mode. In + * particular, do not (automatically) sent "Connection" headers and + * always close the connection after generating the response. + * + * @param request the request for which we force HTTP 1.0 to be used + */ +void +MHD_response_option_v10_only (struct MHD_Response *response) +{ + response->v10_only = true; +} + + +/** + * Set a function to be called once MHD is finished with the + * request. + * + * @param response which response to set the callback for + * @param termination_cb function to call + * @param termination_cb_cls closure for @e termination_cb + */ +void +MHD_response_option_termination_callback (struct MHD_Response *response, + MHD_RequestTerminationCallback termination_cb, + void *termination_cb_cls) +{ + /* Q: should we assert termination_cb non-NULL? */ + response->termination_cb = termination_cb; + response->termination_cb_cls = termination_cb_cls; +} + + +/* end of response_option.c */ diff --git a/src/lib/version.c b/src/lib/version.c index 84918fb7..9ef03e53 100644 --- a/src/lib/version.c +++ b/src/lib/version.c @@ -1,3 +1,28 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file lib/version.c + * @brief versioning and optional feature tests + * @author Christian Grothoff + */ +#include "internal.h" /** diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index d677cf62..9de4843d 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c @@ -246,12 +246,13 @@ MHD_get_response_header (struct MHD_Response *response, NULL != pos; pos = pos->next) { - if ( MHD_str_equal_caseless_ (pos->header, key) ) + if (MHD_str_equal_caseless_ (pos->header, key)) return pos->value; } return NULL; } + /** * Check whether response header contains particular token. *