more work on mhd2 api implementation

This commit is contained in:
Christian Grothoff
2018-02-09 05:44:20 +01:00
parent f6e1ee426f
commit e77fce2749
24 changed files with 1854 additions and 53 deletions
+24 -11
View File
@@ -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
+60
View File
@@ -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 */
+130
View File
@@ -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 */
+61
View File
@@ -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 */
+92
View File
@@ -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 */
+132
View File
@@ -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 */
+52
View File
@@ -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 */
+104 -7
View File
@@ -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 */
+45 -10
View File
@@ -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 */
+3 -3
View File
@@ -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;
+25
View File
@@ -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"
+25
View File
@@ -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
+167 -21
View File
@@ -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
+25
View File
@@ -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"
/**
+53
View File
@@ -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 */
+48
View File
@@ -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 */
+264
View File
@@ -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 */
+90
View File
@@ -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 */
+88
View File
@@ -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 */
+80
View File
@@ -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 */
+198
View File
@@ -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 */
+61
View File
@@ -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 */
+25
View File
@@ -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"
/**
+2 -1
View File
@@ -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.
*